diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /web/spiderweb |
Initial commit
Diffstat (limited to 'web/spiderweb')
170 files changed, 54728 insertions, 0 deletions
diff --git a/web/spiderweb/COPYRIGHT b/web/spiderweb/COPYRIGHT new file mode 100644 index 0000000000..193fdea8b4 --- /dev/null +++ b/web/spiderweb/COPYRIGHT @@ -0,0 +1,11 @@ +Spider and Spidery WEB are copyright 1989-1992 by Norman Ramsey, +Odyssey Research Associates (ORA Corp), 301A Dates Drive, Ithaca, New +York 14850. + +You may use and distribute Spider and Spidery WEB for any purpose, for +free. You may modify Spider and Spidery WEB and create derived works, +provided you retain the copyright notice, but the result may not be +called Spider or Spidery WEB without written permission from ORA Corp. +You may not sell Spider or Spidery WEB themselves, but you may do +anything you like with programs created with Spider and Spidery WEB. + diff --git a/web/spiderweb/README b/web/spiderweb/README new file mode 100644 index 0000000000..c615d5adb3 --- /dev/null +++ b/web/spiderweb/README @@ -0,0 +1,102 @@ +This is Spidery WEB, tool for building a WEB system for the language +of your choice. It was probably gotten by anonymous ftp from the +Comprehensive TeX Archive Network, possibly from niord.shsu.edu. My +colleagues and I have used Spider to build WEB systems for Ada, C, +AWK, and other languages. Spidery WEB is no longer supported; the +lessons learned in its implementation and use have been applied to the +design of `noweb', a much simpler literate-programming tool. noweb is +available by anonymous ftp from csservices.princeton.edu:pub/noweb.shar.Z. +ORA Corp makes some effort to keep Spidery WEB working; bug reports, +fixes, and new language descriptions can be sent to spider-bugs@oracorp.com. +The rest of this file contains a brief description of Spidery WEB and +this distribution; more extensive documentation can be found in the +doc subdirectory. + +INTRODUCTION + +Spider reads a description of a programming language, and writes +source code for a Weave and Tangle which support that language. The +language-dependent parts are derived from the description given +Spider, and the language-independent parts are taken from ``master +copies'' of Weave and Tangle. The master copies are derived from +Silvio Levy's CWEB, and the Tangle and Weave that are constructed are +implemented in C. Spider is implemented as an Awk program. + +An exhaustive list of Spidery Web's features would interest only Web +experts, but I do want to mention some features that I hope will +encourage people to use Spidery {\tt WEB}. + + Tangle and Weave can read from multiple files (this feature is + present in Levy's CWEB), and Tangle can write to multiple files. + Included files will be searched for on a path if not found in the + current directory. These features make Spidery WEB more + usable on systems that have make. + + TANGLE can expand macros with multiple parameters. + + TANGLE writes #line directives, so you can debug at the WEB + source level if your compiler respects the C~conventions for #line. + + +Many features of WEB seem to exist only to compensate for deficiencies +in PASCAL, and most of those were dropped in CWEB. I have changed +much of CWEB in order to avoid being bound too much by C conventions. +As a result, there are dozens of minor differences between Spidery WEB +and original WEB. To give just one example, Spidery WEB supports +octal and hexadecimal constants using WEB-style notation, not the C +notation used in CWEB. + +Spider can generate WEB systems for a variety of languages. The +author has written Spider description files for C, AWK, Ada, SSL (a +language that describes attribute grammars to the Cornell Synthesizer +Generator), the Larch Shared Language (a language for describing +equational theories), and Dijkstra's language of guarded commands. +Debugging the grammar that WEAVE uses to prettyprint the language is +the most time-consuming part of creating a WEB system for a new target +language, and Spider makes it trivial to change that grammar. To make +a Spider description file for an Algol-like language that uses infix +expression notation, an experienced systems programmer should be able +to adapt an existing Spider description file very quickly. + +Spider's major limitations are lexical. All Spidery WEBs assume that +spaces and tabs in the input are not significant, except as +separators; this makes it impossible to construct Spidery WEBs for +languages like Fortran and Miranda, where the position of text on a +line is significant. (You would have to modify the ``master copies'' +of Tangle and Weave to change the lexical analyzer.) The lexical +structures of identifiers, string literals, and numeric literals are +fixed. + +Spider's major value is that is makes it possible to create a new WEB +quickly, and to tinker with it easily. My colleagues and I have used +Spidery WEB to write programs in Ada, C, and SSL, and has been pleased +with the result. We have written in WEB an application of 24 thousand +lines, and we are very pleased at how easy it has been to review and +maintain this code. I hope that the availability of Spidery WEB will +encourage other groups to try literate programming, and that they, +too, will be pleased with the results. + + +WHAT YOU GET + +Although Spider is complete and useful, this distribution contains bug +fixes and enhancements that I have not folded into the code. +I have tested this system only under Unix, but other users have +provided Macintosh, MS-DOS, and OS/2 implementations. + +This directory contains: + + bug-reports reports of bugs that may or may not have been fixed + doc manuals and articles about Spider + fixes-to-be-applied bug fixes and enhancements + mac Macintosh binaries + ms-dos MS-DOS binaries + os2 OS/2 source-code changes + patches patches for old versions of Spider (now useless) + src Spider source code & instructions for building Spider + todo a wish list + tools auxiliary tools that might be useful with Spidery WEB + +Send comments or bug reports to spider-bugs@oracorp.com + +Norman Ramsey diff --git a/web/spiderweb/bug-reports b/web/spiderweb/bug-reports new file mode 100644 index 0000000000..2f0537b5a6 --- /dev/null +++ b/web/spiderweb/bug-reports @@ -0,0 +1,1973 @@ +From chase@orc.olivetti.com Thu Apr 6 16:11:45 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA24139; Thu, 6 Apr 89 16:11:43 EDT +Received: from NET.BIO.NET by Princeton.EDU (5.58+++/2.6) + id AA12881; Thu, 6 Apr 89 16:11:18 EDT +Received: from orc.olivetti.com by net.bio.net (5.59/1.15) with UUCP + id AA09769; Thu, 6 Apr 89 13:10:52 PDT +Received: from ozona.orc.olivetti.com by orc.olivetti.com (3.2/SMI-3.2) + id AA14880; Thu, 6 Apr 89 12:31:15 PDT +Received: by ozona.orc.olivetti.com (3.2/SMI-3.2) + id AA06589; Thu, 6 Apr 89 12:40:52 PDT +From: chase@orc.olivetti.com (David Chase) +Message-Id: <8904061940.AA06589@ozona.orc.olivetti.com> +To: nr@Princeton.EDU +Subject: "cputype?" +Reply-To: David Chase <chase@orc.olivetti.com> +Date: Thu, 06 Apr 89 12:40:50 -0700 +Status: RO + +is not a command on my Unix machine (a Sun). + +David + +From chase@orc.olivetti.com Thu Apr 6 16:11:56 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA24169; Thu, 6 Apr 89 16:11:53 EDT +Received: from NET.BIO.NET by Princeton.EDU (5.58+++/2.6) + id AA12880; Thu, 6 Apr 89 16:11:17 EDT +Received: from orc.olivetti.com by net.bio.net (5.59/1.15) with UUCP + id AA09765; Thu, 6 Apr 89 13:10:50 PDT +Received: from ozona.orc.olivetti.com by orc.olivetti.com (3.2/SMI-3.2) + id AA14856; Thu, 6 Apr 89 12:27:42 PDT +Received: by ozona.orc.olivetti.com (3.2/SMI-3.2) + id AA06558; Thu, 6 Apr 89 12:37:19 PDT +From: chase@orc.olivetti.com (David Chase) +Message-Id: <8904061937.AA06558@ozona.orc.olivetti.com> +To: nr@Princeton.EDU +Subject: Spideryweb bug report +Reply-To: David Chase <chase@orc.olivetti.com> +Date: Thu, 06 Apr 89 12:37:15 -0700 +Status: RO + +An installation problem: People who care about Trojan horses +don't put "." at the beginning of their path, so shell scripts +invoked as "make" never get executed. Try "./make" instead. +I realize that "." at front is the Unix default, but it is an +exceptionally stupid one (put a benign Trojan horse named "ls" +in a few world-writeable directories on a time-shared Unix machine, +and see what happens). I don't know why this isn't more widely +worried about. + +David + +From chase@orc.olivetti.com Thu Apr 6 16:12:03 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA24179; Thu, 6 Apr 89 16:12:01 EDT +Received: from NET.BIO.NET by Princeton.EDU (5.58+++/2.6) + id AA12883; Thu, 6 Apr 89 16:11:24 EDT +Received: from orc.olivetti.com by net.bio.net (5.59/1.15) with UUCP + id AA09777; Thu, 6 Apr 89 13:10:58 PDT +Received: from ozona.orc.olivetti.com by orc.olivetti.com (3.2/SMI-3.2) + id AA14962; Thu, 6 Apr 89 12:44:22 PDT +Received: by ozona.orc.olivetti.com (3.2/SMI-3.2) + id AA06693; Thu, 6 Apr 89 12:53:57 PDT +From: chase@orc.olivetti.com (David Chase) +Message-Id: <8904061953.AA06693@ozona.orc.olivetti.com> +To: nr@Princeton.EDU +Subject: That cute trick with '#' in variable definitions +Reply-To: David Chase <chase@orc.olivetti.com> +Date: Thu, 06 Apr 89 12:53:54 -0700 +Status: RO + +was unknown to me. I broke things badly "cleaning up" the +definition of the three directories. I think you ought +to either change the formatting, or mention that there is +a reason for the '#' immediately following the definitions +(it's not like I'm a novice at this, either) + +David + +From chase@orc.olivetti.com Thu Apr 6 16:12:13 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA24188; Thu, 6 Apr 89 16:12:10 EDT +Received: from NET.BIO.NET by Princeton.EDU (5.58+++/2.6) + id AA12886; Thu, 6 Apr 89 16:11:27 EDT +Received: from orc.olivetti.com by net.bio.net (5.59/1.15) with UUCP + id AA09786; Thu, 6 Apr 89 13:11:04 PDT +Received: from ozona.orc.olivetti.com by orc.olivetti.com (3.2/SMI-3.2) + id AA15001; Thu, 6 Apr 89 13:02:35 PDT +Received: by ozona.orc.olivetti.com (3.2/SMI-3.2) + id AA06741; Thu, 6 Apr 89 13:12:11 PDT +From: chase@orc.olivetti.com (David Chase) +Message-Id: <8904062012.AA06741@ozona.orc.olivetti.com> +To: nr@Princeton.EDU +Subject: So far, so good +Reply-To: David Chase <chase@orc.olivetti.com> +Date: Thu, 06 Apr 89 13:12:08 -0700 +Status: RO + +It made it past "make boot", and I'm fixing to look at +the documentation. My intention is to see if this can +easily be made to generate Modula-3 -- if so, (I think) +I can use it to generate test input for the Modula-3 +compiler. Of course, any such test input is unlikely to +be incredibly sophisticated, since it will be machine- +generated, but it's better than none at all. + +David + +From nr Thu Apr 6 20:12:03 1989 +Received: by notecnirp.Princeton.EDU (5.51/1.81) + id AA05087; Thu, 6 Apr 89 20:11:36 EDT +Date: Thu, 6 Apr 89 20:11:36 EDT +From: nr (Norman Ramsey) +Message-Id: <8904070011.AA05087@notecnirp.Princeton.EDU> +To: chase@orc.olivetti.com +Subject: Re: "cputype?" +Cc: nr +Status: RO + +> Subject: "cputype?" +> is not a command on my Unix machine (a Sun). +> +> David + +I have added instructions to README and to WebMakefile that deal with +cputype. As far as I know, it is a local idiosyncracy, and my +documentation predates it. Thank you for calling it to my attention. + +It looks like you've already figured it out, but a shell script +containing the line `echo sun3' will do fine if it is somewhere on +your search path. + +> An installation problem: People who care about Trojan horses +> don't put "." at the beginning of their path, so shell scripts +> invoked as "make" never get executed. Try "./make" instead. + +I don't see a clean way to fix this. Are any files affected besides +WEBROOT/Makefile? The problem is that some of the calls to $(MAKE) +are calls to shell scripts in subdirectories, while others are calls +to /bin/make in the current directory. What have you done to improve +things? + +> I realize that "." at front is the Unix default, but it is an +> exceptionally stupid one (put a benign Trojan horse named "ls" +> in a few world-writeable directories on a time-shared Unix machine, +> and see what happens). I don't know why this isn't more widely +> worried about. + +I think this isn't worried about because most people assume the world +is benign until they are bitten once or twice. Some of my colleagues +swear by never putting . on their path at all. Me, I haven't been +bitten yet. +> Subject: That cute trick with '#' in variable definitions +> was unknown to me. I broke things badly "cleaning up" the +> definition of the three directories. I think you ought +> to either change the formatting, or mention that there is +> a reason for the '#' immediately following the definitions +> (it's not like I'm a novice at this, either) + +I put a comment in. When I first prepared this for distribution, I +broke things badly by commenting those (previously uncommented) macro +definitions. + +> It made it past "make boot", and I'm fixing to look at +> the documentation. My intention is to see if this can +> easily be made to generate Modula-3 -- if so, (I think) +> I can use it to generate test input for the Modula-3 +> compiler. Of course, any such test input is unlikely to +> be incredibly sophisticated, since it will be machine- +> generated, but it's better than none at all. + +Generating Modula-3 from a Modula-3 literate program should be no +trouble at all. One the other hand, if you want to translate +something else into Modula-3, you are probably better off using +WEB-to-C as a basis. Let me know how it goes; I would love to have a +Modula-3 spider file to add to the distribution. + +Norman + + +From Chris.Paris@vega.fac.cs.cmu.edu Mon Jan 23 20:52:57 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.68) + id AA03118; Mon, 23 Jan 89 20:52:56 EST +Received: from VEGA.FAC.CS.CMU.EDU by Princeton.EDU (5.58+++/1.98) + id AA27627; Mon, 23 Jan 89 20:52:44 EST +Message-Id: <8901240152.AA27627@Princeton.EDU> +Received: from VEGA.FAC.CS.CMU.EDU by VEGA.FAC.CS.CMU.EDU; 23 Jan 89 20:51:40 EST +To: nr@Princeton.EDU +Reply-To: cap@cs.cmu.edu (Chris Paris) +Subject: webkernel +Date: Mon, 23 Jan 89 20:51:36 EST +From: Chris.Paris@VEGA.FAC.CS.CMU.EDU +Status: RO + +I would be more than happy to help beta test Spider. I think it is a +wonderful idea that seems very well implimented. I installed the +webkernel you sent me (thanks), and it fixed most problems I was +having. However, when ceeweave->TeX comes across something like, + + @u + #include <stdio.h> + #include <fcntl.h> + #include "myinclude.h" + + main() + +things happen that I wouldn't expect. First, the filenames in angle +brackets get set in italics without the brackets. I wouldn't expect +this because it looks like c.spider has code to recognize and put in +brackets. "myinclude.h" is set in \tt with the quotes, which is what +I would expect. + +Second, if the first line of code is a preprocessor directive, it is +indented, so that it lines up with main(). Subsequent directives are +against the left margin. + +I don't want to call these bugs since I don't know if what I'm seeing +is what you intended or not. I am testing this on a Sun 3/60 running +Mach (4.3 BSD superset), using TeX 2.9 (generated by web2c). I can +also test on Vaxen and IBM RT's, but have not done so yet. I'm +willing to help out with this any way I can as long as I don't get too +sidetracked from my regular work. Thanks for your help. + +/cap + +From nr Tue Jan 24 12:41:32 1989 +Received: by notecnirp.Princeton.EDU (5.51/1.68) + id AA24196; Tue, 24 Jan 89 12:41:30 EST +Date: Tue, 24 Jan 89 12:41:30 EST +From: nr (Norman Ramsey) +Message-Id: <8901241741.AA24196@notecnirp.Princeton.EDU> +To: cap.cs.cmu.edu +Subject: Bugs +Cc: nr +Status: RO + +> I would be more than happy to help beta test Spider. I think it is a +> wonderful idea that seems very well implimented. + +I'm glad you think so. I myself have some dissatisfactions with the +implementation, especially with the webkernel macros. I hope to have +time to work them out this summer. + +> I installed the +> webkernel you sent me (thanks), and it fixed most problems I was +> having. However, when ceeweave->TeX comes across something like, +> +> @u +> #include <stdio.h> +> #include <fcntl.h> +> #include "myinclude.h" +> +> main() +> +> things happen that I wouldn't expect. First, the filenames in angle +> brackets get set in italics without the brackets. I wouldn't expect +> this because it looks like c.spider has code to recognize and put in +> brackets. "myinclude.h" is set in \tt with the quotes, which is what +> I would expect. + +You found a bug in c.spider, which I have fixed. Generally, the way +to detect such a bug is to put an @2 in a very small test program, and +then look at the resulting diagnostic output. The numbers are numbers +of productions (from productions.list). Anyway I changed the +following production so that it wouldn't swallow the angle brackets:: + + preproc !(less|lesssimp|backslash|newline) --> preproc + + +> Second, if the first line of code is a preprocessor directive, it is +> indented, so that it lines up with main(). Subsequent directives are +> against the left margin. + +A bug in Knuth's unfathomable macros. I have hacked webkernel and +just hope I haven't broken anything else. + +> I don't want to call these bugs since I don't know if what I'm seeing +> is what you intended or not. + +Not. I think my only nonstandard prettyprinting is of (old-style) +parameter declarations. + +> I am testing this on a Sun 3/60 running +> Mach (4.3 BSD superset), using TeX 2.9 (generated by web2c). I can +> also test on Vaxen and IBM RT's, but have not done so yet. + +You will have trouble using the makefiles on other machines---I +unknowingly used some features specific to Sun make (the @#$(&% man +page didn't say `warning, not portable'), so things like `make boot' +and `make distribution' may not work right. But `make weave' and +`make tangle' work fine on a VAX running BSD4.3. + +> I'm +> willing to help out with this any way I can as long as I don't get too +> sidetracked from my regular work. Thanks for your help. + +I'm looking for a guinea pig to try to write a Spider file for ANSI C. +Be aware that C is by far the most complicated language to prettyprint +(of the ones in the distribution). + +Norman + +From crm@summanulla.mc.duke.edu Fri Apr 7 21:29:18 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA14862; Fri, 7 Apr 89 21:29:16 EDT +Received: from duke.cs.duke.edu by Princeton.EDU (5.58+++/2.6) + id AA02957; Fri, 7 Apr 89 21:29:01 EDT +Received: from summanulla.mc.duke.edu by duke.cs.duke.edu (5.59/DUKE/08-19-88) + id AA01720; Fri, 7 Apr 89 21:31:47 EDT +Received: by summanulla.mc.duke.edu (3.2/DUKE/3-1-88) + id AA08029; Fri, 7 Apr 89 18:22:28 EDT +Date: Fri, 7 Apr 89 18:22:28 EDT +From: Charles R. Martin <crm@summanulla.mc.duke.edu> +Message-Id: <8904072222.AA08029@summanulla.mc.duke.edu> +To: nr@Princeton.EDU +Cc: crm@summanulla.mc.duke.edu +Subject: Spiders, eeek! +Status: RO + +I got Spider over the wires a little while ago; I'm quite excited about +it, but I've had a little bit of trouble with the installation: + +(1) I set up a cputype to echo sun3; when I do this, it creates a +subdirectory sun3 of master, and attempts to compile from there. +unfortunately, the objects aren't there, and so the compilation fails. + +(2) compiling the Dijkstra version given a C compile error, with +duplicate labels in a case statement. + +Sorry that I haven't gotten all the details of this, but its Friday +afternoon. + +The compilation record of the dijkstra version is appended below for +your convenience, if that's the word. + +echo "date" `date` | cat - d.spider | awk -f /usr/nbsr/crm/Spider/master/spider.awk +Warning: numeric constants and strings are identified in this WEAVE. +Warning: TeX strings have the same category as numeric constants in this WEAVE. +You used 3 translation keywords. +You defined 18 reserved words of 12 ilks. +You used 15 different categories in 14 productions. +The biggest production had 3 scraps on its left-hand side. +cat /usr/nbsr/crm/Spider/master/transcheck.list trans_keys.unsorted | awk -f /usr/nbsr/crm/Spider/master/transcheck.awk +awk -f /usr/nbsr/crm/Spider/master/cycle.awk < cycle.test +There can't possibly be a cycle in the graph +sort *.unsorted | awk -f /usr/nbsr/crm/Spider/master/nodups.awk +mv *web.tex /usr/nbsr/crm/lib/tex +/bin/rm -f tangle.web +ln /usr/nbsr/crm/Spider/master/tangle.web tangle.web +ceetangle -I/usr/nbsr/crm/Spider/master tangle +This is C TANGLE (generated at 6:13 PM on April 7, 1989) +*1*14*21*25*34*62*64*84*92*107*131*141 +Writing the output files: (tangle.c).....500.....1000.....1500 +Done. +(No errors were found.) +cc -DDEBUG -g -DSTAT -c tangle.c +"tangle.web", line 838: duplicate case in switch, 10 +*** Error code 1 + +Stop. +*** Error code 1 + +From nr Sun Apr 9 22:24:29 1989 +Received: by notecnirp.Princeton.EDU (5.51/1.81) + id AA04177; Sun, 9 Apr 89 22:24:06 EDT +Date: Sun, 9 Apr 89 22:24:06 EDT +From: nr (Norman Ramsey) +Message-Id: <8904100224.AA04177@notecnirp.Princeton.EDU> +To: crm@summanulla.mc.duke.edu +Subject: Re: Spiders, eeek! +Cc: nr +Status: RO + + From crm@summanulla.mc.duke.edu Sat Apr 8 20:31:56 1989 + Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA10629; Sat, 8 Apr 89 20:31:53 EDT + Received: from duke.cs.duke.edu by Princeton.EDU (5.58+++/2.6) + id AA28812; Sat, 8 Apr 89 20:31:39 EDT + Received: from summanulla.mc.duke.edu by duke.cs.duke.edu (5.59/DUKE/08-19-88) + id AA17447; Sat, 8 Apr 89 20:34:46 EDT + Received: by summanulla.mc.duke.edu (3.2/DUKE/3-1-88) + id AA09036; Sat, 8 Apr 89 20:31:21 EDT + Date: Sat, 8 Apr 89 20:31:21 EDT + From: Charles R. Martin <crm@summanulla.mc.duke.edu> + Message-Id: <8904090031.AA09036@summanulla.mc.duke.edu> + To: nr@Princeton.EDU + In-Reply-To: <8904081713.AA03350@notecnirp.Princeton.EDU> "nr@Princeton.EDU" + Subject: Spiders, eeek! + + Got the patches, thanks. They appear to be compiling fine, although + I've uncovered another minor bug in the makefile: when you make clean, + it mashes c/tangle.c and awk/tangle.c, which are needed for compilation. + + I'll look into the dijkstra thing first of next week. + + Thanks again! + +That is a Feature. If you've lost them you should be able to get them back +using `make source'. (Once you've done a `make boot', of course.) + +Norman + +PS Dijkstra compiles for me now. + +From crm@harahan.mc.duke.edu Mon Apr 10 10:19:15 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA15358; Mon, 10 Apr 89 10:19:13 EDT +Received: from duke.cs.duke.edu by Princeton.EDU (5.58+++/2.6) + id AA10282; Mon, 10 Apr 89 10:18:38 EDT +Received: from nbsrws9.mc.duke.edu by duke.cs.duke.edu (5.59/DUKE/08-19-88) + id AA24403; Mon, 10 Apr 89 10:21:33 EDT +Received: by harahan.mc.duke.edu (3.2/DUKE/3-1-88) + id AA02511; Mon, 10 Apr 89 10:18:08 EDT +Date: Mon, 10 Apr 89 10:18:08 EDT +From: Charles R. Martin <crm@harahan.mc.duke.edu> +Message-Id: <8904101418.AA02511@harahan.mc.duke.edu> +To: nr@Princeton.EDU +In-Reply-To: <8904100224.AA04177@notecnirp.Princeton.EDU> "nr@Princeton.EDU" +Subject: Spiders, eeek! +Status: RO + + Date: Sun, 9 Apr 89 22:24:06 EDT + From: nr@Princeton.EDU (Norman Ramsey) + + From crm@summanulla.mc.duke.edu Sat Apr 8 20:31:56 1989 + Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA10629; Sat, 8 Apr 89 20:31:53 EDT + Received: from duke.cs.duke.edu by Princeton.EDU (5.58+++/2.6) + id AA28812; Sat, 8 Apr 89 20:31:39 EDT + Received: from summanulla.mc.duke.edu by duke.cs.duke.edu (5.59/DUKE/08-19-88) + id AA17447; Sat, 8 Apr 89 20:34:46 EDT + Received: by summanulla.mc.duke.edu (3.2/DUKE/3-1-88) + id AA09036; Sat, 8 Apr 89 20:31:21 EDT + Date: Sat, 8 Apr 89 20:31:21 EDT + From: Charles R. Martin <crm@summanulla.mc.duke.edu> + Message-Id: <8904090031.AA09036@summanulla.mc.duke.edu> + To: nr@Princeton.EDU + In-Reply-To: <8904081713.AA03350@notecnirp.Princeton.EDU> "nr@Princeton.EDU" + Subject: Spiders, eeek! + + Got the patches, thanks. They appear to be compiling fine, although + I've uncovered another minor bug in the makefile: when you make clean, + it mashes c/tangle.c and awk/tangle.c, which are needed for compilation. + + I'll look into the dijkstra thing first of next week. + + Thanks again! + + That is a Feature. If you've lost them you should be able to get them back + using `make source'. (Once you've done a `make boot', of course.) + +Uh, I think one of us doesn't understand. I do make clean then make +boot, and get an error. I have to recover c/tangle.c and awk/tangle.c +from the tar file to get it to work. + +Oh, wait -- I see. Now that I've got ceetangle, I can make source and +get tangle.c. Okay, in that case, how about having a make veryclean +that really cleans up everything, and have make clean make a +re-'make-boot'-able state? It is, however, a style question rather +than a function question at that point. + + Norman + + PS Dijkstra compiles for me now. + +Thanks, me too. I haven't had a chance to look at the results, but it +does compile. (If I could only preview dvi files through my PC at home +as I do through my 3/60 at work....) + +Thanks again, + +Charlie Martin (...!mcnc!duke!crm, crm@summanulla.mc.duke.edu) +NBSR/Box 3709/Duke University Medical Center/Durham, NC 27710 + +From chase@orc.olivetti.com Mon Apr 10 12:31:21 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA21577; Mon, 10 Apr 89 12:31:20 EDT +Received: from NET.BIO.NET by Princeton.EDU (5.58+++/2.6) + id AA14387; Mon, 10 Apr 89 12:31:02 EDT +Received: from orc.olivetti.com by net.bio.net (5.61/1.15) with UUCP + id AA28032; Mon, 10 Apr 89 09:30:25 -0700 +Received: from ozona.orc.olivetti.com by orc.olivetti.com (3.2/SMI-3.2) + id AA02330; Mon, 10 Apr 89 09:19:46 PDT +Received: by ozona.orc.olivetti.com (3.2/SMI-3.2) + id AA02170; Mon, 10 Apr 89 09:29:22 PDT +From: chase@orc.olivetti.com (David Chase) +Message-Id: <8904101629.AA02170@ozona.orc.olivetti.com> +To: nr@Princeton.EDU (Norman Ramsey) +Reply-To: David Chase <chase@orc.olivetti.com> +Subject: Re: "cputype?" +In-Reply-To: Your message of Thu, 06 Apr 89 20:11:36 -0400. + <8904070011.AA05087@notecnirp.Princeton.EDU> +Date: Mon, 10 Apr 89 09:29:18 -0700 +Status: RO + + +>> invoked as "make" never get executed. Try "./make" instead. + +>I don't see a clean way to fix this. Are any files affected besides +WEBROOT/Makefile? The problem is that some of the calls to $(MAKE) +are calls to shell scripts in subdirectories, while others are calls +to /bin/make in the current directory. What have you done to improve +things? + +It seemed to compile after I changed Makefile in the top-level +directory to say "./make", but I just now tried a "make -n clean" +and found a few missing things. I'd suggest that in the case where +you want "make" to mean "/bin/make" that you just drop in a shell +script along the lines of + + /bin/make $* + +There's a fair chance that I'll be able to translate Pascal into +Modula-3 with a little assistance. Another worthy project would +be to get a dialect of Pascal output more acceptable to the +brain-dead Pascal compilers used on Olivetti machines. + +David + +From simpson%trwarcadia.UUCP@oberon.usc.edu Mon Apr 10 14:16:57 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA07529; Mon, 10 Apr 89 14:16:53 EDT +Received: from OBERON.USC.EDU by Princeton.EDU (5.58+++/2.6) + id AA17855; Mon, 10 Apr 89 14:16:35 EDT +Received: by oberon.usc.edu (5.59/5.5) id AA01417; + Mon, 10 Apr 89 11:15:42 PST +Received: from localhost by trwarcadia.uucp (3.2/SMI-3.2) + id AA22106; Mon, 10 Apr 89 10:55:03 PDT +Message-Id: <8904101755.AA22106@trwarcadia.uucp> +To: nr@Princeton.EDU +Subject: Figure 2 of "Building a Language-Independent WEB" +Date: Mon, 10 Apr 89 10:55:00 -0700 +From: Scott Simpson <simpson%trwarcadia.UUCP@oberon.usc.edu> +Status: RO + +I believe the line coming into xtangle.c from the right should be labeled +CTANGLE, not CWEAVE. + Scott Simpson, TRW + +From nr Tue Apr 11 14:13:27 1989 +Received: by notecnirp.Princeton.EDU (5.51/1.81) + id AA11976; Tue, 11 Apr 89 14:12:49 EDT +Date: Tue, 11 Apr 89 14:12:49 EDT +From: nr (Norman Ramsey) +Message-Id: <8904111812.AA11976@notecnirp.Princeton.EDU> +To: mackay@june.cs.washington.edu +Subject: Re: spiderweb copyright (last time??) +Cc: nr +Status: RO + +> One last clarification. The question is bound to come up, especially +> from the Japanese, who are very sensitive about this. +> +> 1. Is it within your intentions in copyrighting this that a firm +> might develop proprietary software which in no way incorporates +> any part of spiderweb, but simply uses spiderweb as a development +> tool for internal documentation. +> +> 2. What about the proprietary publication of documented source +> which was produced with one of the language versions of spiderweb? +> (Again with the understanding that no part of spiderweb is included +> in that documentation.) + +I personally would be happy with either of these uses of spiderweb, +but the decision is not entirely up to me. Spiderweb was developed +partly with government contract money, and is agreed to be released +``for research purposes only'' (whatever that means). I will have to +look into this and get back to you. + +> ------------------------------------------------------------------------- +> Now for some first impressions. +> +> You have already supplied the explanation of how to get around `cputype` +> in the new version (which I picked up yesterday). + +Yes, this was a late-breaking compromise to deal with the heterogenous +processor environment here at Princeton. I hate it, but it seems to +get the job done. +> +> In WebMakefile, the target boot: does not move the *.o files +> to the appropriate directory, they remain in the master directory. + +Someone else found that too. I have patched the Makefile and added +some comments. I will send you patches. In the process, I broke the +Makefile to remove some of the sources. I think I have fixed that +now, but for about a day a bad version was on princeton.edu +> +> The weave output from ceetangle comes out perfectly, but the +> weave output from weave runs into problems when it includes grammar.web +> +> @ Here is where we define |highestposoverall| and where we +> check the productions. +> @d highestposoverall = 6 +> @<Test for all of the productions@>= +> if ((1) && +> (pp+1)->cat==SP_ignore_scrap) { +> /* 1: {\tt ? ignore_scrap --> #1} */ +> +> This goes fine until it hits the comment line +> +> /* 1: {\tt ? ignore_scrap --> #1} */ +> but then TeX is bothered by the _ and the #. +> +> What is needed is some sort of \ttverbatim after the {, and possibly an +> \endttverbatim before the } (I seem to remember that it can be +> difficult to get \ttverbatim to turn itself off when it drops to +> a lower level out of {} braces, but perhaps, since you are only +> dealing with one-line comments and there are no embedded newlines +> to be formatted, the difficulty can be got around.) + +Actually a \ttverbatim kind of solution won't work, because +\ttverbatim needs to be able to change the catcodes, and they can't be +changed at that late date because the whole affair is an argument to +another macro, and the characeters have already been gobbled up (or +whatever the appropriate parts of TeX's anatomy that sets catcodes). +I have changed spider.web so the offending characters are escaped with +backslashes: {\tt ? ignore\_scrap --> \#1} and so on. + +> The tangle for C seems to run with very satisfactory speed. + +We have Don Knuth to thank for this. The lexer sees the code just +once, and then converts everything to either eight or sixteen bit +tokens. Output is very fast. + +I would like to speed up WEAVE some day, by making it run from a table +(decision tree). Doing that and abandoning the internal conversion to +ASCII would probably gain a factor of three. + +> Query? How does the Make variable $(SPIDER) with the equivalent +> any.spider get changed into the appropriate *.spider. It works, but +> I can't figure out how it works. Does "any" have some esoteric meaning +> to make? + +This was a horrendous hack to be able to make many different WEBs +while keeping only one Makefile around. The three magic names +$(THETANGLE), $(THEWEAVE), and $(SPIDER) are all expected to be set on +the command line. (Perhaps I shouldn't set them at all inside +WebMakefile.) Look at ./c/make and you'll see how it works. + + +I am sending you a list of bugs so far and patches for them, under +separate cover, via tarmail. + +Norman + +From intvax!drstrip@unmvax.cs.unm.edu Tue Apr 11 12:02:41 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA02118; Tue, 11 Apr 89 12:02:39 EDT +Received: from unmvax.cs.unm.edu by Princeton.EDU (5.58+++/2.6) + id AA21790; Tue, 11 Apr 89 12:02:30 EDT +Received: from intvax.UUCP by unmvax.cs.unm.edu (5.61/3.1) with UUCP + id <AA17499@unmvax.cs.unm.edu>; Tue, 11 Apr 89 08:57:53 -0700 +From: intvax!drstrip@unmvax.cs.unm.edu +Received: by intvax.LOCAL on Tue, 11 Apr 89 09:58:18 mdt +Date: Tue, 11 Apr 89 09:58:18 mdt +Message-Id: <8904111558.AA10373@intvax.LOCAL> +To: unmvax!nr@Princeton.EDU +Subject: spider +Status: RO + +I was finally able to ftp the spider files. It was just a slow connection +that was fooling me. The webkernal file appears to have an extra carriage +return right after the "?" in the comment before you define a verbatim macro. +Also, in spiderwebman (I like that, also the ref. to Stan Lee), there is an +endnewstuff missing after the section on macros. (A lot is commented out in +the section, although not the endnewstuff, which just seems to be missing.) +Thanks for the contriution. I'll let you know if I apply it. +Strip + +From ramsdell@linus.MITRE.ORG Mon Jun 5 15:02:30 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA01963; Mon, 5 Jun 89 15:02:27 EDT +Received: from MBUNIX.MITRE.ORG by Princeton.EDU (5.58+++/2.17) + id AA28417; Mon, 5 Jun 89 15:01:58 EDT +Posted-From: The MITRE Corp., Bedford, MA +X-Alternate-Route: user%node@mbunix.mitre.org +Return-Path: <ramsdell@linus.MITRE.ORG> +Received: from huxley.mitre.org by linus.MITRE.ORG (5.59/RCF-3S) + id AA20583; Mon, 5 Jun 89 14:59:51 EDT +Posted-Date: Mon, 5 Jun 89 15:00:16 EDT +Received: by huxley.mitre.org (4.0/RCF-4C) + id AA11117; Mon, 5 Jun 89 15:00:16 EDT +Date: Mon, 5 Jun 89 15:00:16 EDT +From: ramsdell@linus.MITRE.ORG +Message-Id: <8906051900.AA11117@huxley.mitre.org> +To: nr@Princeton.EDU +Subject: Spidery Scheme +Reply-To: ramsdell@MDF.mitre.org +Status: RO + +I was playing with the idea of generating WEB for Scheme. There are +many problem, especially the fact that Scheme users like a pretty +printed format that seems not generatable by WEB's algorithm. While I +was playing, I found two bugs. + +(1) In WebMakefile: the make command makes common.o and pathopen.o +even if they exist. + +huxley% make +cc -DDEBUG -g -DSTAT -c /usr/src/local/tex/mitre/Spiderweb/master/common.c +mv common.o /usr/src/local/tex/mitre/Spiderweb/master/`arch` +cc -DDEBUG -g -DSTAT -c /usr/src/local/tex/mitre/Spiderweb/master/pathopen.c +mv pathopen.o /usr/src/local/tex/mitre/Spiderweb/master/`arch` +echo "date" `date` | cat - scheme.spider | awk -f /usr/src/local/tex/mitre/Spiderweb/master/spider.awk +Warning: numeric constants and strings are identified in this WEAVE. +awk: tokentest is not an array + record number 30 +*** Error code 2 +make: Fatal error: Command failed for target `grammar.web' + +(2) Spider.awk fails as input to GNU's version of make: + +huxley% echo "date" `date` | cat - scheme.spider | gawk -f /usr/src/local/tex/mitre/Spiderweb/master/spider.awk +gawk: syntax error near line 1221: +temp=sprintf"strncmp("%s",loc-1,%d)==0=0",$2,length($2) + + + ^ parse error + +The problem is gawk's sprintf expects a parenthesized argument list. +Using gawk is prefered because the error messages are better an Sun +awk does not always run spider.awk correctly. The input file + +scheme.spider: +------------- +## A very broken attempt at scheme. + +language Scheme extension scm + +module definition exp use exp +# use as stmt is unavoidable since tangle introduces line breaks + +comment begin <";"> end newline + +line begin <";"-space-"line"> end <""> + +default translation <*> mathness no + +# identifiers are wrong -- no hope here. +token identifier category exp mathness yes +token number category exp mathness yes +token newline category newline translation <> mathness no +token pseudo_semi category semi mathness maybe translation <"\\relax"> + +semi <force> --> exp + +token ( category open +token ) category close +#token . category binop translation <".\\,"-opt-3> + +open exp --> call +call exp --> call +call close --> exp + +#newline --> ignore_scrap + +? ignore_scrap --> #1 + +------------------- + +gives this output: (all is okay using gawk) + +huxley% echo "date" `date` | cat - scheme.spider | awk -f /usr/src/local/tex/mitre/Spiderweb/master/spider.awk +Warning: numeric constants and strings are identified in this WEAVE. +awk: tokentest is not an array + record number 27 + +--------------------- + +Thank you for making your software available. I like Levy's CWEB and +am looking forward to using your version of CWEB. +John + + + +From kademan@stat.wisc.edu Thu Jun 8 15:30:58 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA12073; Thu, 8 Jun 89 15:30:56 EDT +Received: from bayes.stat.wisc.edu by Princeton.EDU (5.58+++/2.17) + id AA00826; Thu, 8 Jun 89 15:30:47 EDT +Date: Thu, 8 Jun 89 14:28:47 CDT +From: kademan@stat.wisc.edu (Ed Kademan) +Message-Id: <8906081928.AA16941@bayes.stat.wisc.edu> +Received: by bayes.stat.wisc.edu; Thu, 8 Jun 89 14:28:47 CDT +To: nr@Princeton.EDU +Subject: spiderweb bug report +Status: RO + +In case you haven't heard of this one yet, two of the line directives in +the file WEBROOT/master/common.c did not have any space between the number +and the file name string. GNU C would not compile it as a result. The +lines were numbers 168 and 170 I believe: +---------------------------------------------------------------------- +#line 187"/u/nr/src/web/master/pathopen.web" + +#line 188"/u/nr/src/web/master/pathopen.web" +---------------------------------------------------------------------- +===> Bundled 11 Apr 89; all bugs into patches/003 + +From nr Sat Jun 17 11:02:26 1989 +Received: by notecnirp.Princeton.EDU (5.51/1.81) + id AA00234; Sat, 17 Jun 89 11:02:25 EDT +Date: Sat, 17 Jun 89 11:02:25 EDT +From: nr (Norman Ramsey) +Message-Id: <8906171502.AA00234@notecnirp.Princeton.EDU> +To: ramsdell@linus.MITRE.ORG +Subject: Re: Spidery Scheme +Cc: nr +Status: RO + +> From ramsdell@linus.MITRE.ORG Mon Jun 5 15:02:30 1989 +> I was playing with the idea of generating WEB for Scheme. There are +> many problem, especially the fact that Scheme users like a pretty +> printed format that seems not generatable by WEB's algorithm. + +What is the difficulty? Are there some lexical elements that WEB +can't recognize, or does one need semantic information to prettyprint +Scheme? I have only a nodding acquaintance with Lisp and know even +less about Scheme, but I shouldn't have expected too much difficulty. + +> While I +> was playing, I found two bugs. +> +> (1) In WebMakefile: the make command makes common.o and pathopen.o +> even if they exist. +> +> huxley% make +> cc -DDEBUG -g -DSTAT -c /usr/src/local/tex/mitre/Spiderweb/master/common.c +> mv common.o /usr/src/local/tex/mitre/Spiderweb/master/`arch` +> cc -DDEBUG -g -DSTAT -c /usr/src/local/tex/mitre/Spiderweb/master/pathopen.c +> mv pathopen.o /usr/src/local/tex/mitre/Spiderweb/master/`arch` +> echo "date" `date` | cat - scheme.spider | awk -f /usr/src/local/tex/mitre/Spiderweb/master/spider.awk +> Warning: numeric constants and strings are identified in this WEAVE. +> awk: tokentest is not an array +> record number 30 +> *** Error code 2 +> make: Fatal error: Command failed for target `grammar.web' + + +The problem is in your use of `arch` and exposes a flaw in make. Make +is looking for a file common.o in a directory `arch` and not finding +it, so it makes the target. You can cure the problem by replacing +`arch` with $(ARCH) in the Makefile and using ARCH=`arch` in the make +script that calls /bin/make. I don't know of anything better. + + +> (2) Spider.awk fails as input to GNU's version of make: +> +> huxley% echo "date" `date` | cat - scheme.spider | gawk -f /usr/src/local/tex/mitre/Spiderweb/master/spider.awk +> gawk: syntax error near line 1221: +> temp=sprintf"strncmp("%s",loc-1,%d)==0=0",$2,length($2) +> +> +> ^ parse error +> +> The problem is gawk's sprintf expects a parenthesized argument list. +> Using gawk is prefered because the error messages are better an Sun +> awk does not always run spider.awk correctly. + +I am reluctant to move to gawk because in the past I have found it +buggy and unstable. BSD awk is buggy but at least is stable. +Spider.awk contains a number of workarounds. I will look into the +tokentest problem. + +> Thank you for making your software available. I like Levy's CWEB and +> am looking forward to using your version of CWEB. +> John + +I'm glad to hear it. Sorry I took so long getting back to you; I've +been out of town and things piled up while I was away. + +Norman + +From nr Sat Jun 17 11:08:01 1989 +Received: by notecnirp.Princeton.EDU (5.51/1.81) + id AA00397; Sat, 17 Jun 89 11:07:51 EDT +Date: Sat, 17 Jun 89 11:07:51 EDT +From: nr (Norman Ramsey) +Message-Id: <8906171507.AA00397@notecnirp.Princeton.EDU> +To: kademan@stat.wisc.edu +Subject: Re: spiderweb bug report +Cc: nr +Status: RO + +I haven't heard of this one yet; thanks for the report. The problem is that +TANGLE tries to be clever about removing ``unnecessary'' spaces from its input. +The lines you found were from a .h file that was @included. Since I'm spending +my time writing new literate programming tools, I'm not going to attempt to fix +it. You can work around it by running the code through a sed script: + /^#line/s/"/ "/ + +Good luck. + +Norman + From kademan@stat.wisc.edu Thu Jun 8 15:30:58 1989 + Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA12073; Thu, 8 Jun 89 15:30:56 EDT + Received: from bayes.stat.wisc.edu by Princeton.EDU (5.58+++/2.17) + id AA00826; Thu, 8 Jun 89 15:30:47 EDT + Date: Thu, 8 Jun 89 14:28:47 CDT + From: kademan@stat.wisc.edu (Ed Kademan) + Message-Id: <8906081928.AA16941@bayes.stat.wisc.edu> + Received: by bayes.stat.wisc.edu; Thu, 8 Jun 89 14:28:47 CDT + To: nr@Princeton.EDU + Subject: spiderweb bug report + Status: RO + + In case you haven't heard of this one yet, two of the line directives in + the file WEBROOT/master/common.c did not have any space between the number + and the file name string. GNU C would not compile it as a result. The + lines were numbers 168 and 170 I believe: + ---------------------------------------------------------------------- + #line 187"/u/nr/src/web/master/pathopen.web" + + #line 188"/u/nr/src/web/master/pathopen.web" + ---------------------------------------------------------------------- + ===> Bundled 11 Apr 89; all bugs into patches/003 + + +From kademan@stat.wisc.edu Mon Jun 26 07:17:06 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA14563; Mon, 26 Jun 89 07:17:05 EDT +Received: from bayes.stat.wisc.edu by Princeton.EDU (5.58+++/2.17) + id AA27774; Mon, 26 Jun 89 07:16:24 EDT +Date: Mon, 26 Jun 89 06:14:15 CDT +From: kademan@stat.wisc.edu (Ed Kademan) +Message-Id: <8906261114.AA02589@bayes.stat.wisc.edu> +Received: by bayes.stat.wisc.edu; Mon, 26 Jun 89 06:14:15 CDT +To: nr@Princeton.EDU +Subject: spider bug report +Status: RO + +===> Bundled 11 Apr 89; all bugs into patches/003 + +The webkernel.tex file has an \eject command on line 221 right after the +code that sets up an empty page for the first use of the output routine. +As a result the first "page" gets output before the regular macros get a +chance to set mark, and the section number in the first header is null. +Simply deleting that \eject command fixes the problem (and doesn't +introduce any new ones as far as I can tell.) + +I've been having a good time playing with this spider system, and have +created a web for C++ by tweaking your c.spider file. + +From matsl@inmic.se Tue May 23 11:11:17 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.81) + id AA14352; Tue, 23 May 89 11:11:15 EDT +Received: from [192.36.125.2] by Princeton.EDU (5.58+++/2.13) + id AA28056; Tue, 23 May 89 11:11:01 EDT +Received: from inmic.se by sunic.sunet.se (5.61+IDA/KTH/LTH/1.53) + id AAsunic04212; Tue, 23 May 89 17:11:18 +0200 +Received: from haf2.inmic.se (ha2) by nmpcad.inmic.se (dec-1.2/3.0) + id AA14700; Tue, 23 May 89 17:08:19 -0200 +Received: by haf2.inmic.se (hp-13.1/3.0) + id AA16364; Tue, 23 May 89 17:10:39 met +Date: Tue, 23 May 89 17:10:39 met +From: Mats Lidell <matsl@inmic.se> +Message-Id: <8905231510.AA16364@haf2.inmic.se> +To: nr@Princeton.EDU +In-Reply-To: Norman Ramsey's message of Mon, 22 May 89 11:18:05 EDT <8905221518.AA03626@notecnirp.Princeton.EDU> +Subject: Spiderweb +Status: RO + +Dear Norman, + +Thanks for your quick and helpful answer. It made me try it once again. + +> I have only two guesses: +> -- you are somehow combining Spider with Silvio Levy's CWEB in a way +> that doesn't work +> -- you've got a buggy C compiler + +Quite right. I was combining Spider with Silvio Levy's CWEB. See note +below. + +> Please let me know more if you can, or at least tell me how big your +> tangle.c is, so I can tell if it makes sense. + +This time I tried to follow the instructions real hard and it worked! +But I had some small problems. + +When doing 'make boot' the link of ceetangle and ceeweave tries to get +the common object files from the cputype directory but they are not +there. They are compiled in the master directory! I just removed the +use of the cputype-directory and then it worked! + +I also managed to destroy the tangle.c file in the master directory +when I typed 'make -p'. Well I shouldn't have done it but away it +went. Then I realised that this was what happened the last time I +tried to make spiderweb and that time I copied ctangle.c from CWEB +just to try it. Stupid me! This time I went back to my copy of the +distribution and got the real ctangle.c! The previous time I didn't +realised that it ever was in the master directory. I though it simply +was missing. + +The programs are using the 'index' function that's not available on +SYSV. (I'm running HP-UX.) This should be substituted with 'strchr' +since I think that this is now normally available on both SYSV and BSD +systems. (I haven't checked that though! Maybe a macro is safer.) I +found no other system problem. + +A small error when trying to print out the weave. I haven't tried to +find out why it fails. See output below. + + ceeweave -I../master weave.web + This is C WEAVE (generated at 11:03 AM on May 23, 1989) + *1*14*28 + ! Illegal use of @ in comment. (l. 363) + /* identifier =200 or octal @' + 310 */ *35*52*65*75*81*84*114*138*150*151*168*188*211*235 + Writing the output file...*1*14*28 + ! Illegal use of @ in comment. (l. 363) + /* identifier =200 or octal @' + 310 */ *35*52*65*75*81*84*114*138*150*151*168*188*211*235 + Writing the index...Done. + Memory usage statistics: 722 of 3999 names, 2988 of 19999 cross-references, + 9695 of 89999 bytes; + Parsing required 822 of 1000(950) scraps, 1736 of 2000(1950) texts, + 3749 of 20000(19950) tokens, 258 of 399 levels; + + Sorting required 47 levels + + (Pardon me, but I think I spotted something wrong.) + + +I can't find any collection of the improvements and/or differences you +have added to your weave and tangle nor can I find any users manual in +the same way as for CWEB. Well I will start looking through the +program documentation but if you have anything better I would +appreciate that. + +Many thanks. + +Yours matsl +--- +Mats Lidell + Swedish Institute of Microelectronics, VHDL CAD Tools, + PO Box 1084, S-164 21 KISTA, SWEDEN + Tel: +46 8 752 11 42 Ttx: 128 75 INMIC S Fax: +46 8 750 80 56 +Internet: matsl@inmic.se or {uunet,unido,mcvax,ukc,munnari}sunic!inmic.se!matsl + +From campbell@vx2.GBA.NYU.EDU Sat Jul 1 18:34:13 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.82) + id AA13480; Sat, 1 Jul 89 18:34:12 EDT +Received: from VX2.GBA.NYU.EDU by Princeton.EDU (5.58+++/2.19) + id AA22478; Sat, 1 Jul 89 18:34:04 EDT +Received: by vx2.GBA.NYU.EDU (5.61/1.34) + id AA25315; Sat, 1 Jul 89 17:35:25 -0500 +Date: Sat, 1 Jul 89 17:35:25 -0500 +From: campbell@vx2.GBA.NYU.EDU (bruce dietrich-campbell) +Message-Id: <8907012235.AA25315@vx2.GBA.NYU.EDU> +To: nr@Princeton.EDU +Subject: spider installation on 3b1 +Status: RO + +Hi, + +I've just installed spider on my ATT 3b1 (aka UnixPC). Thought you +might be interested in a few minor changes I had to make. + + 1. In common.c I added the definition + + #define index strchr + + since the routine is named differently on SysV machines. + I probably should have added a -DUSG compilation flag, but + since this was the only dependency ... + + 2. In spider.awk, three sprintf lines were missing the + surrounding parentheses: + +1221c1221 +< temp=sprintf"strncmp(\"%s\",loc-1,%d)==0",$2,length($2) +--- +> temp=sprintf("strncmp(\"%s\",loc-1,%d)==0",$2,length($2)) +1231c1231 +< temp=sprintf"'%s'",$2 +--- +> temp=sprintf("'%s'",$2) +3040c3040 +< temp=sprintf"(pp+%d)->cat",$i-1 +--- +> temp=sprintf("(pp+%d)->cat",$i-1) + + This was confusing, since BSD4.3 awk doesn't mind. + + 3. My awk then wouldn't digest c.spider or awk.spider, + complaining of an + + awk : unexpected break, continue or next at record ### + + where ### was one more than the number of lines in c.spider + or awk.spider. Rather than fight it, I installed gawk2.10 + and everything went fine. (Note that gawk also burps on + the missing parentheses mentioned in 2 above.) + + +The last line of BUGS is: + +===> Bundled 11 Apr 89; all bugs into patches/003 + +Cheers! + +............................................................................. +Bruce Dietrich-Campbell ARPA: campbell@vx2.gba.nyu.edu + USENET: ...!{uunet,rocky,harvard}!cmcl2!vx2!campbell + +From purtill@math.mit.edu Thu Jul 20 18:19:07 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.83) + id AA19356; Thu, 20 Jul 89 18:19:05 EDT +Received: from BOURBAKI.MIT.EDU by Princeton.EDU (5.58+++/2.20) + id AA27225; Thu, 20 Jul 89 18:18:47 EDT +Received: from jacobi.mit.edu by math.mit.edu; Thu, 20 Jul 89 18:18:32 EDT +Received: by jacobi.mit.edu; Thu, 20 Jul 89 18:18:23 EDT +Date: Thu, 20 Jul 89 18:18:23 EDT +From: purtill@math.mit.edu +Message-Id: <8907202218.AA05761@jacobi.mit.edu> +To: nr@Princeton.EDU (Norman Ramsey) +Subject: spider bug(?) +Status: R + + +If foo.web is: +---------- +@* Oink. + +@<Oink |#include|s@>= +#include <oink.h> +---------- + +Then foo.tex (produced by ceeweave) is: +---------- +\input cweb.tex + +\N1. Oink. + +\Y\P\4\X1:Oink s\X${}\S{}$\par +\fi + + +\inx +\:\\{include}, 1. +\:\\{oink}, 1. +\fin +\:\X1:Oink s\X +\con +---------- + +Notice that the module name which should be "<Oink #includes>" +cleverly formated ends up being just "<Oink s>". (Also, I'm no longer +using gawk!) + +^.-.^ Mark Purtill purtill@math.mit.edu (617)623-6238 - H +((")) Dept. of Math, MIT 2-229, Cambridge, MA 02139 (617)253-1589 - O + + + + +From nr Thu Jul 20 18:43:45 1989 +Received: by notecnirp.Princeton.EDU (5.51/1.83) + id AA19658; Thu, 20 Jul 89 18:43:44 EDT +Date: Thu, 20 Jul 89 18:43:44 EDT +From: nr (Norman Ramsey) +Message-Id: <8907202243.AA19658@notecnirp.Princeton.EDU> +To: purtill@math.mit.edu +Subject: Re: spider bug(?) +Cc: nr +Status: R + +This is a bug. A production is matching a token that isn't +there, and for some reason this is making WEAVE drop all its +text. I haven't found a quick workaround; you'll have to put +something else in that title (it needs a newline to terminate +the #include, and it can never get one within @<...@>). + +I'll let you know when I get the bug fixed. + +Norman + +From alexande@cs.unc.edu Fri Jan 19 17:52:39 1990 +Received: by cs.Princeton.EDU (5.57/1.98) + id AA05330; Fri, 19 Jan 90 17:52:38 EST +Received: from Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.98) + id AA08642; Fri, 19 Jan 90 17:52:10 EST +Received: from mcnc.mcnc.org by Princeton.EDU (5.58+++/2.29/mailrelay) + id AA17810; Fri, 19 Jan 90 17:45:02 EST +Received: from mercury.cs.unc.edu by mcnc.mcnc.org (5.59/MCNC/5-16-88) + id AA21523; Fri, 19 Jan 90 17:43:28 EST +Received: from dopey.cs.unc.edu by mercury.cs.unc.edu (5.59/UNC/6-17-88) + id AA11354; Fri, 19 Jan 90 17:42:24 EST +Received: by dopey.cs.unc.edu (5.59/UNC/06-13-88) + id AA00405; Fri, 19 Jan 90 17:41:01 EST +Date: Fri, 19 Jan 90 17:41:01 EST +From: Geoffrey D. Alexander <alexande@cs.unc.edu> +Message-Id: <9001192241.AA00405@dopey.cs.unc.edu> +To: nr@Princeton.EDU +Subject: Problem installing spidery WEB +Cc: alexande@cs.unc.edu +Status: RO + +Norman, + +I have run into a problem installing Spidery WEB. The problem occur when I +try to run make boot from WEBROOT. Here is the output produced: + +=============================================================================== +cd c; make boot; cd .. +cd ../master; rm -f *.o; for i in /unc/alexande/spiderweb/master/common.c /unc/alexande/spiderweb/master/pathopen.c; do \ + cc -DDEBUG -g -DSTAT -c $i; \ + mv *.o /unc/alexande/spiderweb/master/sparc_sunos ; \ +done; cd ../c +cc -DDEBUG -g -DSTAT -c tangle.c; \ +cc -DDEBUG -g -DSTAT -o /unc/alexande/bin/sparc_sunos/ceetangle /unc/alexande/spiderweb/master/sparc_sunos/common.o /unc/alexande/spiderweb/master/sparc_sunos/pathopen.o tangle.o +ld: /unc/alexande/spiderweb/master/sparc_sunos/common.o: Not a directory +*** Error code 4 +make: Fatal error: Command failed for target `boot' +Current working directory /tmp_mnt/auto/phi/phi2/unc/alexande/spiderweb/c +*** Error code 1 +make: Fatal error: Command failed for target `boot' +=============================================================================== + +The problem is that there is no directory WEBROOT/master/sparc_sunos where +sparc_sunos is the value returned by cputype. I see that Spidery WEB is +distributed with null directories WEBROOT/master/sun3 and WEBROOT/master/vax. +Instead of "precreating" these null directories, why not dynamically create +them? Note that there wasn't anything in WEBROOT/README or +EBROOT/master/WebMake which indicated that cputype has to return either sun3 +or vax (or that a null directory has to be created). + +The last line of WEBROOT/BUGS is + +=============================================================================== +===> Bundled 29 Nov 89; all bugs into patches/008 +=============================================================================== + +If you have any questions, please let me know. + +Thanks, +Geoff + +From nr Mon Apr 16 10:57:52 1990 +Received: by cs.Princeton.EDU (5.57/1.100) + id AA08937; Mon, 16 Apr 90 10:57:34 EDT +Date: Mon, 16 Apr 90 10:57:34 EDT +From: Norman Ramsey <nr> +Message-Id: <9004161457.AA08937@cs.Princeton.EDU> +To: alexande@cs.unc.edu +Subject: Re: Problem installing spidery WEB +Cc: nr +Status: R + +> +> Norman, +> +> I havd the following problems installing Spidery WEB: +> +> * I was unable to make web in the larch subdirectory. +> Error: "comment begin" must have a restricted translation +> Error: "line begin" must have a restricted translation + +Fixed. You need <"%"> not % and <"%line"> not %line + +> * I had two problems making web in the penelope subdirectory although I did +> get a tangle and weave wiich run. Why did I get a Fatal error from make +> (I believe it comes from /bin/make -f SpiderMakefile $*)? + +Beats me. + + +> Why is there +> potential cycle error? + +Cleverness about newlines in annotations. Context eliminates the +possibility of a cycle---check the productions.list file if you're not +clear about that. + +> I recently started using Spidery WEB. I have encountered a few minor problems. +> The first problem is that I would like to use C code in a module name. This +> is illustrated by the following short example. +> +> =============================================================================== +> @*= Starred module with |C_code|. + +This is broken just like anything else that changes catcodes in +arguments. It's a TeX problem that nobody knows how to fix. + +> As a temporary soultion for using C code in module names, I tried using \it. +> This illustrated by +> +> =============================================================================== +> @*= Starred module with {\it C\_code}. +> +> @*= Index. +> =============================================================================== +> +> This didn't work. When I ran TeX, I got +> ...... +> A solution which worked for me was to move \write\cont{\string... after +> \openout\cont=\contentsfile. This is similar to the code in CWEB's +> cwebmac.tex. Is this a good fix? + +Looks good to me. + +> This problem has to do with C preprocessor commands and the index. Consider +> the following short example. +> +> Ceeweave and TeX both run fine. However, the index contains entries for ifdef, +> include, and endif (in italics and without the #). I don't think preprocessor +> commands should be in the index (in any form). What do you think? How do I +> fix this? +> +> This problem invloves #include and the index. Consider the following short +> example. +> +> Both ceeweave and TeX run fine. However the index contains entries for test +> and it. It should contain instead an entry for test.it (or no entry). What +> do you think? How do I fix this? + +You're not going to be able to do anything about this without +fundamentally changing Weave's idea of what an identifier is. +If you want you could make the preprocessor directives reserved words, +suppressing their appearance in the index, but that will have +unpleasant repercussions, I'm sure. If you really want to fix this +you'll have to do some hacking. + +> This problem has to do with spacing in ANSI C function parameter +> specifications. Consider the following short example. + +Nobody has written a Spider description for ANSI C that I am aware of. +If you care to write one I'll be happy to put it in the distribution. + +> This problem has to do with the running head. Consider the following short +> example. +> +> =============================================================================== +> @*= Test of starred modules -- chapter. +> +> @*2 Test of starred modules -- subsection. +> +> @*4 Test of starred modules -- subsubsection. +> +> @*=Index. +> =============================================================================== +> +> Both ceeweave and TeX run fine. However, the running head on page 1 has module +> number 1 and the title for module 3. I believe that they should be consistent. + +Fidget with \firstmark, \topmark, and all of their friends in +webkernel.tex. Let me know when you have something you're happy with. + +> Actually, I would like to have only starred modules which cause page ejects be +> reflected in the running head. What do you think? How do I fix this? + +Not a bad idea. Get hacking. + +> This is not really a problem as much as a design question. I feel that @f +> should not result in any text in the TeX output (either in the module in +> which it occurs or in the index). @f is a directive to ceeweave; it does not +> contribute to understanding the C program. For example, if I use Xlib, I need +> to @f a number (20+) of indetifiers which are "typed" in the Xlib header files. +> I feel that having the @f's appear in a module (and in the index) simply +> detracts from the program. What do you think? How might I "fix" @f? + +I think that if you're going to lie to your reader by using @f, your +reader should at least have a chance to catch you in the act. From +this you may infer that I never use @f. + + +Norman + +From ndn@seg.npl.co.uk Thu Mar 29 04:58:29 1990 +Received: by cs.Princeton.EDU (5.57/1.98) + id AA02242; Thu, 29 Mar 90 04:58:28 EST +Received: from mcsun.eu.net by Princeton.EDU (5.58+++/2.32/mailrelay) + id AA14282; Thu, 29 Mar 90 04:56:23 EST +Received: by mcsun.EU.net via EUnet; Thu, 29 Mar 90 11:57:25 +0200 (MET) +Received: from psg.npl.co.uk by kestrel.Ukc.AC.UK with UUCP id aa29895; + 29 Mar 90 10:32 BST +Received: from guava.seg.npl.co.uk by snow.psg.npl.co.uk; Thu, 29 Mar 90 09:29:47 BST +From: Nick North <ndn@seg.npl.co.uk> +Date: Thu, 29 Mar 90 09:32:36 BST +Message-Id: <10449.9003290832@guava.seg.npl.co.uk> +To: nr@Princeton.EDU +Subject: Spiderweb bug +Status: RO + +We are using the adaweave generated by Spiderweb and have run into +problems with the ** operator: the ada.spider supplied generates a +weave which turns + i := 3 ** Integer(p); +into + $\|i\mathbin{:=}\O{3}C\\{Integer}\ (\|p); \32$ +So the ** has disappeared. +The following patch solves the problem (I don't know if it is the best +solution though): + +*** ada.spider.old Wed Mar 28 11:46:50 1990 +--- ada.spider Wed Mar 28 10:04:03 1990 +*************** +*** 46,52 **** + + token => category arrow translation <"\\AR"> + token .. category binop translation <"\\.{..}"> +! token ** category binop + token := category binop translation <"\\mathbin{:=}"> + token /= translation <"\\I"> category binop + token >= translation <"\\G"> category binop +--- 46,52 ---- + + token => category arrow translation <"\\AR"> + token .. category binop translation <"\\.{..}"> +! token ** category binop translation <"\\mathbin{**}"> + token := category binop translation <"\\mathbin{:=}"> + token /= translation <"\\I"> category binop + token >= translation <"\\G"> category binop + +We are running the version of Spiderweb whose BUGS file ends with: +===> Bundled 11 Apr 89; all bugs into patches/003 + +Nick North +National Physical Laboratory, UK + +From alexande@cs.unc.edu Tue Apr 24 11:26:22 1990 +Received: by cs.Princeton.EDU (5.57/1.101) + id AA29083; Tue, 24 Apr 90 11:26:18 EDT +Received: from bashful.cs.unc.edu by mcnc.mcnc.org (5.59/MCNC/5-16-88) + id AA18202; Tue, 24 Apr 90 11:25:14 EDT +Received: from fillmore.cs.unc.edu by bashful.cs.unc.edu (5.61/UNC_02-28-90) + id AA21656; Tue, 24 Apr 90 11:24:49 -0400 +Received: by fillmore.cs.unc.edu (5.61/UNC_02-28-90) + id AA10498; Tue, 24 Apr 90 11:24:40 -0400 +Date: Tue, 24 Apr 90 11:24:40 -0400 +From: Geoffrey D. Alexander <alexande@cs.unc.edu> +Message-Id: <9004241524.AA10498@fillmore.cs.unc.edu> +To: nr@cs +Subject: 3 more SpiderWEB problems +Cc: alexande@cs.unc.edu +Status: RO + +I have run into three more Spidery WEB problems: + +8. Page number may be off by one in table of contents. Illustrated by the + following example. Not that module 2 starts on page 2 -- table of contents + entry for module 2 gives page 1. + +=============================================================================== +@*= A Page Number Test. + +Include a large amount of vertical space. +\vskip 6in + +@*2 A level 2 module. + +Include a large amount of vertical space. +\vskip 6in + +@*= Index. +=============================================================================== + +9. Enums not formatted correctly by ceeweave. Illustrated by the following + example. I think enums should be formatted similar to structures. Also, + left arrows are not appropriate; I think a colon might be better. Finally, + enumerated values (false and true) should be underscored in index. + +=============================================================================== +@*= Test of enum. + +@c +enum { + false=0, + true=1 +} boolean; + +@*= Index. +=============================================================================== + +10. Typedefs not formated correctly by ceeweave. Illustrated by the following + example. The new types (boolean, lstring_head, lstring, and string) should + be formatted as types (ie. in bold). I tried using @f to redefine them. + See second example. This caused there to be no line break between typedefs + and a small white space between the new type and ;. + +=============================================================================== +@*= Test of typedef. + +@c +typedef enum { + @!false=0, + @!true=1 +} boolean; +typedef struct { + int buf_len; + int cur_len; +} lstring_head; +typedef lstring_head *lstring; +typedef char *string; + +@*= Index. +=============================================================================== + +=============================================================================== +@*= Test of typedef. + +@f boolean char +@f lstring_head char +@f lstring char +@f string char + +@c +typedef enum { + @!false=0, + @!true=1 +} boolean; +typedef struct { + int buf_len; + int cur_len; +} lstring_head; +typedef lstring_head *lstring; +typedef char *string; + +@*= Index. +=============================================================================== + +The last line of the BUGS file is + + ==> Bundled 29 Nov 89; all bugs into patches/008 + +I think that problem 8 requires a change to webkernel.tex and that problems 9 +and 10 reguire changes to the C definition source. I plan to look at problem +8 later this week. I'll take a look at problems 9 and 10 when I get around to +creating a Spidery WEB for ANSI C. + +If you have any suggestions or fixes, please let me know. + +Thanks, +Geoff Alexander + +From nr Tue Apr 24 17:05:07 1990 +Received: by cs.Princeton.EDU (5.57/1.101) + id AA08862; Tue, 24 Apr 90 17:04:56 EDT +Date: Tue, 24 Apr 90 17:04:56 EDT +From: Norman Ramsey <nr> +Message-Id: <9004242104.AA08862@cs.Princeton.EDU> +To: alexande@cs.unc.edu +Subject: Re: 3 more SpiderWEB problems +Cc: nr +Status: R + +> +> I have run into three more Spidery WEB problems: +> +> 8. Page number may be off by one in table of contents. + +This is a problem with the underlying TeX macros (marks, and so on). +I'll be delighted if you can find a fix. + +> 9. Enums not formatted correctly by ceeweave. + +enums are not K&R (old-style C). An ANSI C spider definition is badly +needed, but I don't have funding to produce one. + +> 10. Typedefs not formated correctly by ceeweave. + +Only if you believe ``correctly'' == ``what Silvio does.'' +The problem is that the logical structure of typedefs follows the +structure of the C program, whereas the formatting is done on the +structure of the WEB source. There are nasty problems of scoping, and +even doing a botched job requires a two-pass algorithm. + +> I tried using @f to redefine them. +> See second example. This caused there to be no line break between typedefs +> and a small white space between the new type and ;. +> +> =============================================================================== +> @*= Test of typedef. +> +> @f boolean char +> @f lstring_head char +> @f lstring char +> @f string char + +This should be fixable by fiddling the c.spider definition; let me +know how you make out. + +> I'll take a look at problems 9 and 10 when I get around to +> creating a Spidery WEB for ANSI C. + +Sorry to be so unhelpful, but I have been putting my time into new, +better-designed tools, instead of continually patching web. + +Norman + +From alexande@cs.unc.edu Tue Apr 24 21:51:59 1990 +Received: by cs.Princeton.EDU (5.57/1.101) + id AA11728; Tue, 24 Apr 90 21:51:55 EDT +Received: from bashful.cs.unc.edu by mcnc.mcnc.org (5.59/MCNC/5-16-88) + id AA00785; Tue, 24 Apr 90 21:50:54 EDT +Received: from fillmore.cs.unc.edu by bashful.cs.unc.edu (5.61/UNC_02-28-90) + id AA23752; Tue, 24 Apr 90 21:50:29 -0400 +Received: by fillmore.cs.unc.edu (5.61/UNC_02-28-90) + id AA01306; Tue, 24 Apr 90 21:50:20 -0400 +Date: Tue, 24 Apr 90 21:50:20 -0400 +From: Geoffrey D. Alexander <alexande@cs.unc.edu> +Message-Id: <9004250150.AA01306@fillmore.cs.unc.edu> +To: nr@cs +Subject: Some Spidery WEB fixes +Cc: alexande@cs.unc.edu +Status: R + +Norman, + +I have fixed some of the Spidery WEB problem is snet you. First, a fix for the +"code in a module name" problem (this also allows italic text in a module +name). This fix involves two changes to webkernel.tex: + +Initialize \DC: +===== old ===================================================================== +\def\CD{\relax\ifmmode\let\DC\egroup\hbox\bgroup\else\let\DC\relax\fi} +===== new ===================================================================== +\def\CD{\relax\ifmmode\let\DC\egroup\hbox\bgroup\else\let\DC\relax\fi} +\let\DC\relax +=============================================================================== + +Move the he code that writes "\catcode`@=11" to the toc file: +===== old ===================================================================== +\newwrite\cont +\output{\setbox0=\page % the first page is garbage + \openout\cont=\contentsfile + \global\output{\normaloutput\page\lheader\rheader\lfooter\rfooter}} +\setpage +\vbox to \vsize{} % the first \topmark won't be null +% Delete as per bug report from kademan@stat.wisc.edu +% Causes headings on first page to be missing +% \eject +\write\cont{\string\catcode`\string\@=11}% a hack to make contents + % take stuff in \.{---} +===== new ===================================================================== +\newwrite\cont +\output{\setbox0=\page % the first page is garbage + \openout\cont=\contentsfile + \write\cont{\string\catcode`\string\@=11} % a hack to make contents + % take stuff in \.{---} + \global\output{\normaloutput\page\lheader\rheader\lfooter\rfooter}} +\setpage +\vbox to \vsize{} % the first \topmark won't be null +% Delete as per bug report from kademan@stat.wisc.edu +% Causes headings on first page to be missing +% \eject +=============================================================================== + +Next, a fix for the "module name in running head" problem. This fix makes the +module name in the running head change only a "page eject" module is +encountered. This fix involves a a single change. + +Move the code that sets \rhead from \N to the \headcheck. +=== old \N ==================================================================== +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \edef\rhead{\uppercase{\ignorespaces\themodtitle}} % define running headline + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip + \Z{\theopen\relax + \themodtitle}{\modno}{\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +=== new \N (includes third fix) =============================================== +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip\Z{\theopen\relax + \themodtitle}{\modno}{\noexpand\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +=============================================================================== + +=== old \headcheck ============================================================ +\def\headcheck#1#2\headcheck{% + \makethechar{#1}% + \def\theskipper{\vfil\penalty-100\vfilneg\vskip12ptminus3pt}% + % skip before new module + \def\theopen{}% opening skip in toc entry + \def\thetocskip{}% vertical skip before toc entry + \def\themodtitle{{#2}} + \ifnextchar={% + \def\theskipper{\vfil\eject}% + \canceltrue + \def\theopen{\bf}% + \def\thetocskip{\vskip3ptplus1in\penalty-100 + \vskip0ptplus-1in}% + }{\ifnextchar1{% + \cancelfalse + \def\theskipper{\vfil\eject}% + \def\theopen{\hskip2em}% + }{\ifnextchar2{% + \cancelfalse + \def\theopen{\hskip2em}% + }{\ifnextchar3{% + \cancelfalse + \def\theskipper{\vfil\eject}% + \def\theopen{\hskip4em}% + }{\ifnextchar4{% + \cancelfalse + \def\theopen{\hskip4em}% + }{% else + \ifcancel\else + \def\theskipper{\vfil\eject}% + \fi + \cancelfalse + \def\themodtitle{#1{#2}}% + }}}}}% + \theskipper +} +=== new \headcheck ============================================================ +\def\headcheck#1#2\headcheck{% + \makethechar{#1}% + \def\theskipper{\vfil\penalty-100\vfilneg\vskip12ptminus3pt}% + % skip before new module + \def\theopen{}% opening skip in toc entry + \def\thetocskip{}% vertical skip before toc entry + \def\themodtitle{{#2}} + \ifnextchar={% + \def\theskipper{\vfil\eject% + \edef\rhead{\uppercase{\ignorespaces% + \themodtitle}}}% + \canceltrue + \def\theopen{\bf}% + \def\thetocskip{\vskip3ptplus1in\penalty-100 + \vskip0ptplus-1in}% + }{\ifnextchar1{% + \cancelfalse + \def\theskipper{\vfil\eject% + \edef\rhead{\uppercase{\ignorespaces% + \themodtitle}}}% + \def\theopen{\hskip2em}% + }{\ifnextchar2{% + \cancelfalse + \def\theopen{\hskip2em}% + }{\ifnextchar3{% + \cancelfalse + \def\theskipper{\vfil\eject% + \edef\rhead{\uppercase{\ignorespaces% + \themodtitle}}}% + \def\theopen{\hskip4em}% + }{\ifnextchar4{% + \cancelfalse + \def\theopen{\hskip4em}% + }{% else + \ifcancel\else + \def\theskipper{\vfil\eject% + \edef\rhead{\uppercase{\ignorespaces% + \themodtitle}}}% + \fi + \cancelfalse + \def\themodtitle{#1{#2}}% + }}}}}% + \theskipper +} +=============================================================================== + +Last, a fix for the "table of contents page number off by one" problem. This +invloves a single change to webkernel.tex: + +Add \noexpand before \the\pageno in \N. +=== old \N ==================================================================== +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \edef\rhead{\uppercase{\ignorespaces\themodtitle}} % define running headline + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip + \Z{\theopen\relax + \themodtitle}{\modno}{\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +=== new \N (includes second fix) ============================================== +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip\Z{\theopen\relax + \themodtitle}{\modno}{\noexpand\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +=============================================================================== + +Note that there are two distinct changes to \N (one for the second fix and one +for the third fix). Feel free to make the changes to the distributed +webkernel.tex. If you have any questions or you have problems with any of the +fixes, please let me know. + +Geoff Alexander + +From alexande@cs.unc.edu Tue Apr 24 21:51:59 1990 +Received: by cs.Princeton.EDU (5.57/1.101) + id AA11728; Tue, 24 Apr 90 21:51:55 EDT +Received: from bashful.cs.unc.edu by mcnc.mcnc.org (5.59/MCNC/5-16-88) + id AA00785; Tue, 24 Apr 90 21:50:54 EDT +Received: from fillmore.cs.unc.edu by bashful.cs.unc.edu (5.61/UNC_02-28-90) + id AA23752; Tue, 24 Apr 90 21:50:29 -0400 +Received: by fillmore.cs.unc.edu (5.61/UNC_02-28-90) + id AA01306; Tue, 24 Apr 90 21:50:20 -0400 +Date: Tue, 24 Apr 90 21:50:20 -0400 +From: Geoffrey D. Alexander <alexande@cs.unc.edu> +Message-Id: <9004250150.AA01306@fillmore.cs.unc.edu> +To: nr@cs +Subject: Some Spidery WEB fixes +Cc: alexande@cs.unc.edu +Status: RO + +Norman, + +I have fixed some of the Spidery WEB problem is snet you. First, a fix for the +"code in a module name" problem (this also allows italic text in a module +name). This fix involves two changes to webkernel.tex: + +Initialize \DC: +===== old ===================================================================== +\def\CD{\relax\ifmmode\let\DC\egroup\hbox\bgroup\else\let\DC\relax\fi} +===== new ===================================================================== +\def\CD{\relax\ifmmode\let\DC\egroup\hbox\bgroup\else\let\DC\relax\fi} +\let\DC\relax +=============================================================================== + +Move the he code that writes "\catcode`@=11" to the toc file: +===== old ===================================================================== +\newwrite\cont +\output{\setbox0=\page % the first page is garbage + \openout\cont=\contentsfile + \global\output{\normaloutput\page\lheader\rheader\lfooter\rfooter}} +\setpage +\vbox to \vsize{} % the first \topmark won't be null +% Delete as per bug report from kademan@stat.wisc.edu +% Causes headings on first page to be missing +% \eject +\write\cont{\string\catcode`\string\@=11}% a hack to make contents + % take stuff in \.{---} +===== new ===================================================================== +\newwrite\cont +\output{\setbox0=\page % the first page is garbage + \openout\cont=\contentsfile + \write\cont{\string\catcode`\string\@=11} % a hack to make contents + % take stuff in \.{---} + \global\output{\normaloutput\page\lheader\rheader\lfooter\rfooter}} +\setpage +\vbox to \vsize{} % the first \topmark won't be null +% Delete as per bug report from kademan@stat.wisc.edu +% Causes headings on first page to be missing +% \eject +=============================================================================== + +Next, a fix for the "module name in running head" problem. This fix makes the +module name in the running head change only a "page eject" module is +encountered. This fix involves a a single change. + +Move the code that sets \rhead from \N to the \headcheck. +=== old \N ==================================================================== +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \edef\rhead{\uppercase{\ignorespaces\themodtitle}} % define running headline + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip + \Z{\theopen\relax + \themodtitle}{\modno}{\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +=== new \N (includes third fix) =============================================== +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip\Z{\theopen\relax + \themodtitle}{\modno}{\noexpand\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +=============================================================================== + +=== old \headcheck ============================================================ +\def\headcheck#1#2\headcheck{% + \makethechar{#1}% + \def\theskipper{\vfil\penalty-100\vfilneg\vskip12ptminus3pt}% + % skip before new module + \def\theopen{}% opening skip in toc entry + \def\thetocskip{}% vertical skip before toc entry + \def\themodtitle{{#2}} + \ifnextchar={% + \def\theskipper{\vfil\eject}% + \canceltrue + \def\theopen{\bf}% + \def\thetocskip{\vskip3ptplus1in\penalty-100 + \vskip0ptplus-1in}% + }{\ifnextchar1{% + \cancelfalse + \def\theskipper{\vfil\eject}% + \def\theopen{\hskip2em}% + }{\ifnextchar2{% + \cancelfalse + \def\theopen{\hskip2em}% + }{\ifnextchar3{% + \cancelfalse + \def\theskipper{\vfil\eject}% + \def\theopen{\hskip4em}% + }{\ifnextchar4{% + \cancelfalse + \def\theopen{\hskip4em}% + }{% else + \ifcancel\else + \def\theskipper{\vfil\eject}% + \fi + \cancelfalse + \def\themodtitle{#1{#2}}% + }}}}}% + \theskipper +} +=== new \headcheck ============================================================ +\def\headcheck#1#2\headcheck{% + \makethechar{#1}% + \def\theskipper{\vfil\penalty-100\vfilneg\vskip12ptminus3pt}% + % skip before new module + \def\theopen{}% opening skip in toc entry + \def\thetocskip{}% vertical skip before toc entry + \def\themodtitle{{#2}} + \ifnextchar={% + \def\theskipper{\vfil\eject% + \edef\rhead{\uppercase{\ignorespaces% + \themodtitle}}}% + \canceltrue + \def\theopen{\bf}% + \def\thetocskip{\vskip3ptplus1in\penalty-100 + \vskip0ptplus-1in}% + }{\ifnextchar1{% + \cancelfalse + \def\theskipper{\vfil\eject% + \edef\rhead{\uppercase{\ignorespaces% + \themodtitle}}}% + \def\theopen{\hskip2em}% + }{\ifnextchar2{% + \cancelfalse + \def\theopen{\hskip2em}% + }{\ifnextchar3{% + \cancelfalse + \def\theskipper{\vfil\eject% + \edef\rhead{\uppercase{\ignorespaces% + \themodtitle}}}% + \def\theopen{\hskip4em}% + }{\ifnextchar4{% + \cancelfalse + \def\theopen{\hskip4em}% + }{% else + \ifcancel\else + \def\theskipper{\vfil\eject% + \edef\rhead{\uppercase{\ignorespaces% + \themodtitle}}}% + \fi + \cancelfalse + \def\themodtitle{#1{#2}}% + }}}}}% + \theskipper +} +=============================================================================== + +Last, a fix for the "table of contents page number off by one" problem. This +invloves a single change to webkernel.tex: + +Add \noexpand before \the\pageno in \N. +=== old \N ==================================================================== +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \edef\rhead{\uppercase{\ignorespaces\themodtitle}} % define running headline + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip + \Z{\theopen\relax + \themodtitle}{\modno}{\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +=== new \N (includes second fix) ============================================== +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip\Z{\theopen\relax + \themodtitle}{\modno}{\noexpand\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +=============================================================================== + +Note that there are two distinct changes to \N (one for the second fix and one +for the third fix). Feel free to make the changes to the distributed +webkernel.tex. If you have any questions or you have problems with any of the +fixes, please let me know. + +Geoff Alexander + diff --git a/web/spiderweb/doc/Makefile b/web/spiderweb/doc/Makefile new file mode 100644 index 0000000000..6f24dc9dbd --- /dev/null +++ b/web/spiderweb/doc/Makefile @@ -0,0 +1,3 @@ +clean: + -rm -f *.dvi *.log *~ + diff --git a/web/spiderweb/doc/abstracts.tex b/web/spiderweb/doc/abstracts.tex new file mode 100644 index 0000000000..bb4f38208e --- /dev/null +++ b/web/spiderweb/doc/abstracts.tex @@ -0,0 +1,23 @@ +\centerline{Spider User's Guide} + +This manual explains how to use the {Spider} program to generate a +{\tt WEB} system for any programming language. +It describes the syntax of the {Spider} description file used to +describe a programming language, giving several examples. +It does not say how to use the generated {\tt WEB} system; for that +see ``The Spidery {\tt WEB} System of Structured Documentation.'' + +\bigskip + +\centerline{The Spidery {\tt WEB} System of Structured Documentation} + + +This manual describes how to write programs in the {\tt WEB} language, +using {\tt WEB} systems generated by {Spider}. +Most of the material is taken verbatim from Donald Knuth's original +memo introducing {\tt WEB}. +It contains a brief introduction to the idea of literate programming, +a short explanation of how to run {\tt WEAVE} and {\tt TANGLE}, and a +list of all of the control sequences that can be used in {\tt WEB} +programs and their effects. + diff --git a/web/spiderweb/doc/cacm.aux b/web/spiderweb/doc/cacm.aux new file mode 100644 index 0000000000..7a91431f55 --- /dev/null +++ b/web/spiderweb/doc/cacm.aux @@ -0,0 +1,16 @@ +\relax +\citation{ramsey:developing} +\citation{levy:cweb} +\@writefile{lof}{\string\contentsline\space {figure}{\string\numberline\space {1}{\ignorespaces Processing a C\penalty \@M \ {\string\ptt\space web} file}}{2}} +\newlabel{instance}{{1}{2}} +\@writefile{lof}{\string\contentsline\space {figure}{\string\numberline\space {2}{\ignorespaces Building and using an instance of {\string\ptt\space WEB} (for language X)}}{3}} +\newlabel{building}{{2}{3}} +\@writefile{lof}{\string\contentsline\space {figure}{\string\numberline\space {3}{\ignorespaces Table Inversion}}{4}} +\newlabel{fragment}{{3}{4}} +\citation{oppen:prettyprinting} +\bibcite{bentley:lp}{Bentley\penalty \@M \ 86} +\bibcite{knuth:literate-programming}{Knuth\penalty \@M \ 84} +\bibcite{levy:cweb}{Levy\penalty \@M \ 87} +\bibcite{oppen:prettyprinting}{Oppen\penalty \@M \ 80} +\bibcite{ramsey:developing}{Ramsey\penalty \@M \ 89} +\bibcite{cvw:loom}{Van\penalty \@M \ Wyk\penalty \@M \ 87} diff --git a/web/spiderweb/doc/cacm.tex b/web/spiderweb/doc/cacm.tex new file mode 100644 index 0000000000..d16ccf5dff --- /dev/null +++ b/web/spiderweb/doc/cacm.tex @@ -0,0 +1,602 @@ +\documentstyle[11pt]{article} +\title{Building a Language-Independent {\tt WEB}\thanks{This research +has been sponsored in part by the USAF, Rome Air Development Center, +under contract number F30602--86--C--0071.}} +%\author{Norman Ramsey\\Department of Computer Science\\Princeton University} +\author{Norman Ramsey\thanks{Current address: Department of Computer +Science, Princeton University, Princeton, New Jersey 08544}% +\\Odyssey Research Associates} + +\newcommand{\token}{\cstok} +\def\sizedboxit#1#2{\vtop{\vbox{\hrule\hbox{\vrule\kern #2% + \vtop{\vbox{\kern #2\hbox{#1}}\kern #2}\kern #2\vrule}}\hrule}} +\def\boxit#1{\sizedboxit{#1}{3pt}} +\newcommand{\remark}{\marginpar} +\def\remark#1{\marginpar{\footnotesize\it #1}} +\def\cstok#1{\leavevmode\thinspace\hbox{\vrule\vtop{\vbox{\hrule\kern1pt + \hbox{\vphantom{\tt/}\thinspace{\tt#1}\thinspace}} + \kern1pt\hrule}\vrule}\thinspace} % control sequence token +\def\ttok#1{\leavevmode\thinspace\hbox{\vrule\vtop{\vbox{\hrule\kern1pt + \hbox{\vphantom{\tt(j}\thinspace{\tt#1}\thinspace}} + \kern1pt\hrule}\vrule}\thinspace} % token +\newcommand{\X}{} +\def\X:#1\X{\mbox{$\langle${#1}$\rangle$}} + +\begin{document} +\maketitle + +In the fall of~1987 I started planning the implementation of a +suite of tools for building verified Ada +programs~\cite{ramsey:developing}. +The first tool to be built was a +verification condition generator, which was to be formally defined +using the typed lambda calculus. +I was eager to include the definition with the code +so that it would be easy to check the code's correctness. +Using {\tt WEB} would have made this easy, but, +unfortunately, the target programming language was +SSL (a language for specifying structure editors), and the only +languages for which {\tt WEB} implementations were +available were Pascal and~C. + +Writing a new {\tt WEB} from scratch didn't make sense, so +I decided to modify Silvio Levy's implementation of {\tt WEB} +in~C~\cite{levy:cweb}, +to get a {\tt WEB} that would be written in C, but would read and +write SSL code. +From my previous experiences modifying {\tt WEB}, I knew that the +most time-consuming job would be fine-tuning the grammar that {\tt +WEAVE} uses to prettyprint code. +I believed I could make debugging that grammar a lot less painful +if, instead of trying to make dozens of small modifications by hand, I + wrote a simple program, perhaps an AWK script, that would read +a description of the grammar and generate C~code for {\tt WEAVE}. +That AWK script became {\tt SPIDER}, a program that turns language +descriptions into C~code for {\tt TANGLE} and {\tt WEAVE}. +I have used {\tt SPIDER} to generate {\tt WEB}s for C, AWK, SSL, Ada, +and a couple of other languages. +I won't go into the details of {\tt SPIDER}; instead, I'll try to +describe what {\tt SPIDER} does to accomplish its mission, or +how to take the ``essence of {\tt WEB}'' and make it +language-independent. + +\medskip + +When using {\tt WEB}, a programmer writes a single source file, {\tt +foo.{\tt web}}, that holds both code and documentation. +{\tt TANGLE} and {\tt WEAVE} read that file. +{\tt TANGLE} extracts +the code from the {\tt WEB} file and rewrites it in a form suitable +for compiling. +{\tt WEAVE} passes the documentation parts to a document formatter +({\TeX}), and prettyprints the code parts. +The whole process is shown in Figure~\ref{instance}, for C~programs +written in {\tt WEB}. +The~{\S} represents files that have to be written by hand. +{\sl Slant} type is used for the names of executable programs. +{\sl CTANGLE} and {\sl CWEAVE} are the C-language versions of {\tt +TANGLE} and {\tt WEAVE}, {\sl cc}~is a C~compiler, and {\sl ld}~is a +loader. + +\begin{figure} +\caption{Processing a C~{\tt web} file} +\label{instance} +\footnotesize +\setlength{\unitlength}{2pt} +\begin{picture}(170,80)(0,-40) +\tt +\put(20,12.5){\makebox(0,0)[l]{\ \sl CTANGLE}} +\put(20,-12.5){\makebox(0,0)[l]{\ \sl CWEAVE}} + +\put(0,-5){\framebox(30,10){foo.{\tt web}\smash{${}^{\S}$}}} +\put(15,5){\vector(1,2){7.5}} +\put(10,20){\framebox(30,10){foo.c}} +\put(15,-5){\vector(1,-2){7.5}} +\put(10,-30){\framebox(30,10){foo.tex}} + +\put(40,-25){\vector(1,0){20}} +\put(50,-23.5){\makebox(0,0)[b]{\sl {\TeX}}} +\put(60,-30){\framebox(30,10){foo.dvi}} +\put(90,-25){\vector(1,0){20}} +\put(100,-25){\makebox(0,0){\shortstack{\strut dvi\\\strut \rm driver}}} +\put(110,-25){\makebox(0,0)[l]{\rm\strut \ Typeset documentation for +{\tt foo}}} + +\put(40,25){\vector(1,0){20}} +\put(50,26.5){\makebox(0,0)[b]{\sl cc}} +\put(60,20){\framebox(30,10){foo.o}} +\put(90,25){\vector(1,0){20}} +\put(100,26.5){\makebox(0,0)[b]{\sl ld}} +\put(110,25){\makebox(0,0)[l]{\rm\strut \ Executable \sl foo}} + + + +\end{picture} + +\hrule +\end{figure} + +{\tt SPIDER} is used to construct {\em instances} of {\tt TANGLE} and +{\tt WEAVE}, and these instances are used to process programs as +shown in Figure~\ref{instance}. +Code for the language-dependent parts of these instances is generated +by {\tt SPIDER} when it +reads a language description file written by a {\tt WEB} designer. +Figure~\ref{building} shows how instances of {\tt TANGLE} and {\tt +WEAVE} are generated. +{\tt SPIDER} converts a hand-written description of a programming language +into C~{\tt WEB} code for the language-dependent parts of {\tt TANGLE} +and {\tt WEAVE}. +In Figure~\ref{building} the target programming language is a hypothetical +``X,'' and the description file is called ``{\tt x.spider}.'' +{\tt CTANGLE} combines the code {\tt SPIDER} writes with the ``master +copies'' of {\tt tangle.web} and {\tt weave.web}, which contain the +language-independent parts of {\tt TANGLE} and {\tt WEAVE}. +The result is C~source code for {\tt XTANGLE} and {\tt XWEAVE}. +After that code is compiled and loaded with {\tt WEB}'s I/O code, the +resulting executable versions of {\tt XTANGLE} and {\tt XWEAVE} can be +used to process X-language programs written in {\tt WEB} format, as +shown around the periphery of Figure~\ref{building}. + + +The master copies of {\tt tangle.web} and {\tt weave.web} are about +1800 and 3200 lines long, respectively. +About one third of these lines are comments. +To illustrate the other size, suppose X is the Ada programming language. +The {\tt ada.spider} file is about 260 lines long, and from it {\tt +SPIDER} generates +about 1400~lines of {\tt ADATANGLE} and {\tt ADAWEAVE}. +About one tenth of these lines are comments. +It is typical for {\tt SPIDER} to generate between $5n$ and $6n$ lines +of C~{\tt WEB} code from an $n$~line language description. + +\begin{figure} +\caption{Building and using an instance +of {\tt WEB} (for language X)} +\label{building} +\footnotesize +\setlength{\unitlength}{2pt} +\begin{picture}(215,115)(10,-55) +\tt +\put(185,-5){\framebox(30,10){x.spider\smash{${}^{\S}$}}} +\put(185,0){\line(-1,0){20}} +\put(174,1.5){\makebox(0,0)[b]{$\,$\sl SPIDER}} +\put(165,0){\vector(-1,1){10}} +\put(165,0){\vector(-1,-1){10}} + +\put(125,5){\framebox(30,10){xt.web}} +\put(125,-15){\framebox(30,10){xw.web}} +\put(125,25){\framebox(30,10){\shortstack{{\rm Master}\\tangle.{\tt web}}}} +\put(125,-35){\framebox(30,10){\shortstack{{\rm Master}\\weave.{\tt web}}}} +\put(125,-30){\line(-1,1){10}} +\put(125,-10){\line(-1,-1){10}} +\put(115,-20){\vector(-1,0){25}} + +\put(104,-18.5){\makebox(0,0)[b]{\scriptsize\sl CTANGLE}} + +\put(125,10){\line(-1,1){10}} +\put(125,30){\line(-1,-1){10}} +\put(115,20){\vector(-1,0){25}} + +\put(104,21.5){\makebox(0,0)[b]{\scriptsize\sl CTANGLE}} + +\put(60,15){\framebox(30,10){xtangle.c}} +\put(60,-25){\framebox(30,10){xweave.c}} +\put(60,-20){\vector(-1,0){20}} +\put(50,-18.5){\makebox(0,0)[b]{\sl cc, ld}} +\put(60,20){\vector(-1,0){20}} +\put(50,21.5){\makebox(0,0)[b]{\sl cc, ld}} +\put(38,20){\makebox(0,0)[r]{\sl XTANGLE}} +\put(38,-20){\makebox(0,0)[r]{\sl XWEAVE}} + +\put(-6.25,-5){\framebox(30,10){foo.{\tt web}\smash{${}^{\S}$}}} +\put(8.75,5){\vector(1,4){6.25}} +\put(0,30){\framebox(30,10){foo.x}} +\put(8.75,-5){\vector(1,-4){6.25}} +\put(0,-40){\framebox(30,10){foo.tex}} + +\put(30,-35){\vector(4,-1){20}} +\put(50,-48.75){\framebox(30,10){foo.dvi}} +\put(80,-47.5){\vector(4,-1){20}} +\put(100,-52.5){\makebox(0,0)[l]{\rm\strut \ Typeset documentation for +{\tt foo}}} + +\put(30,35){\vector(4,1){20}} +\put(50,38.75){\framebox(30,10){foo.o}} +\put(80,47.5){\vector(4,1){20}} +\put(100,52.5){\makebox(0,0)[l]{\rm\strut \ Executable \sl foo}} + + + +\end{picture} + +\hrule +\end{figure} + +\medskip + +A {\tt WEB} program is a collection of ``sections,'' each of which has a +documentation part, a definition part, and a code part. +The documentation part describes what the section is supposed to do, +and is intended to be processed by a formatter---my {\tt WEB}s use +{\TeX}, which is especially convenient for mathematical symbols like +those used in writing a formal semantics. +The definition part contains macro definitions. +Each macro may have parameters or not, as the programmer chooses. +The code in the code part is a fragment of the whole program. +It is called a ``module'' and can be named or unnamed. +When the module is named, the module name ``stands for'' that code, +just as a macro name stands for the code in its definition. +The unnamed module is special; the code in the unnamed module is +considered to be ``the program.'' + +Figure~\ref{fragment} shows a fragment of a {\tt WEB} program; the +fragment inverts an +EBCDIC-to-ASCII table to obtain an ASCII-to-EBCDIC table. +The target programming language is C. +One module, \X:Invert {\it to\_ascii}, producing {\it to\_ebcdic}\X, +uses the code defined in the other, \X:Set ${\it +to\_ebcdic}[i]\leftarrow {\it UNDEFINED\_CODE}$ for all $i$\X. +The program, {\tt foo}, of which this fragment is a part, can be input +to {\tt CTANGLE} and {\tt CWEAVE}, to produce {\tt foo.c} and {\tt +foo.tex} respectively, as shown in Figure~\ref{instance}. + +\begin{figure} +\caption{Table Inversion} +\label{fragment} +\begin{verbatim} +@ The array |to_ascii| converts an EBCDIC code to +an ASCII code, or to |-1| if there is no ASCII +equivalent to the given code. +@d UNDEFINED_CODE = -1 +@<Invert |to_ascii|, producing |to_ebcdic|@>= + @<Set |to_ebcdic[i]=UNDEFINED_CODE| for all |i|@>@; + for (i=0; i<256; i++) + if (to_ascii[i] != UNDEFINED_CODE) + to_ebcdic[to_ascii[i]]=i; + +@ @<Set |to_ebcdic[i]=UNDEFINED_CODE| for all |i|@>= + for (i=0; i<128; i++) to_ebcdic[i] = UNDEFINED_CODE; +\end{verbatim} +\hrule +\end{figure} + + + +{\tt TANGLE}'s job is to take a collection of sections and to +produce a compilable program. +{\tt TANGLE} reads all the sections, skipping the documentation parts +completely, but storing the macro definitions from the definition parts +and the module definitions from the code parts. +After it has read all the sections, {\tt TANGLE} then +writes out the code in the unnamed module. +But whenever it encounters a module name in that code, instead of +writing out the name, it writes out the code for which this name +stands. +That code may itself contain module names, which are replaced with the +code for which they stand, and so on until {\tt TANGLE} reaches code +which contains no occurrences of module names. +{\tt TANGLE} processes macros similarly, except that macros may +have parameters (modules may not). + +As I've described it, the ``essence of tangling'' is +language-independent. +In the full implementation of {\tt TANGLE} there are only a few +language-dependent details, and almost all of them come up only in +lexical analysis. +During its input phase, {\tt TANGLE} converts macro definitions and +module definitions into token lists. +%%%Every token is represented using either eight or sixteen bits. +The major kinds of tokens are +module name tokens, identifier tokens, and ordinary tokens. +Identifier tokens may be expandable (when they are macro names) or +unexpandable (when they are programming-language identifiers). +Module name tokens are always expandable, and ordinary tokens are +never expandable. +{\tt TANGLE} uses a stack to write out the token list corresponding to +the unnamed module, expanding expandable tokens as it goes. +No token is ever expanded until the time comes to write that token on +the output. + +To build the language-dependent part of {\tt TANGLE}, it is enough to +tell {\tt TANGLE} how to tokenize the input and how to write out a +token list. +{\tt TANGLE} uses a ``lowest common denominator'' lexical analyzer to +tokenize its input. +The set of tokens recognized by this lexical analyzer is the union of +the sets of legal tokens of many different languages. +For example, different ways of delimiting string literals are +recognized. +Identifiers may have underscores, even though some languages +(e.g.~Pascal) may not permit underscores in identifiers, and others +(e.g.~Ada) may not permit consecutive underscores in an identifier. +In general, {\tt TANGLE} and {\tt WEAVE} do the right thing with legal +programs, but they do not detect illegalities in a program. + +{\tt TANGLE}'s lexical analyzer recognizes a fixed set of tokens +representing identifiers, string literals, and numeric literals. +Any printable ASCII character which is not part of some other +token forms a token all by itself. +A {\tt WEB} builder can specify that certain strings should +be treated as single tokens, and +{\tt SPIDER} will convert the specifications into appropriate code for +{\tt TANGLE}. +For example, when building {\tt WEB} for~C, we tell {\tt SPIDER} +that the strings {\tt ++}, {\tt ==}, and {\tt \&\&} (and many others) +should be treated as single tokens, by putting the statements +\begin{quote}\tt +token ++ ...\\ +token == ...\\ +token \&\&\ ... +\end{quote} +into the language description file, {\tt c.spider}. + +{\tt TANGLE} discards comments, rather than attempting to tokenize +them. +Comments are assumed to begin with a special string, and to end either +with another string or with a newline. +We specify C comment conventions by telling {\tt SPIDER} +\begin{quote}\tt +comment begin <"/*"> end <"*/"> +\end{quote} + + +On output, {\tt TANGLE} converts tokens to text by inverting the +process of lexical analysis, so, for example, the token \token{++} is +written out as ``{\tt ++}''. +{\tt TANGLE}'s output phase inserts white space between adjacent +identifiers and numeric literals, but otherwise does not write white +space. +This can cause problems in some cases; for example, in older +C~compilers the string +``{\tt =-}'' is ambiguous. +We can solve this problem by telling {\tt SPIDER} to build a {\tt +TANGLE} that uses the text + ``{\tt =~}'' when writing the \token{=}: +\begin{quote}\tt +token = tangleto <"= "> +\end{quote} + +In sum, we can make {\tt TANGLE} language-independent with almost no +effort. +We do this by using a lowest common denominator lexical analyzer whose +only parameter is a description of comments, and by providing a way to +fine-tune the way {\tt TANGLE} writes tokens. + + + +\medskip +Unlike {\tt TANGLE}, {\tt WEAVE} does no rearranging of the sections; +its job is to translate its input into a prettyprinted program +listing. +The documentation part of each section is simply copied to the output, +but the definition and code parts are prettyprinted. +{\tt WEAVE}'s output is handed to a document formatter, which is +assumed to implement a prettyprinting algorithm like that described by +Oppen~\cite{oppen:prettyprinting}. +Since my {\tt WEB}s use {\TeX} as the document formatter, the back-end +prettyprinting is implemented by {\TeX} macros. + +{\tt WEAVE} copies the documentation parts as texts, but it converts +definition and code parts to token lists using the same lexical +analyzer used by {\tt TANGLE}. +{\tt WEAVE}'s part of the prettyprinting task (as distinct from +{\TeX}'s part) is converting these token lists to streams of {\TeX} +text, possibly with prettyprinting instructions intercalated between +tokens. +If you like, {\tt WEAVE}'s job is to produce the input to Oppen's +algorithm. +For simplicity, we'll discuss only three prettyprinting instructions: +{\em indent} +(increase the level of indentation), {\em outdent} (decrease the level +of indentation), and {\em force} (force a line break). + +We tell {\tt WEAVE} how to convert tokens to {\TeX} text by specifying +a {\em translation} for each token. +Suppose we want the C token \token{!=} to be printed as~``$\ne$'', +which is produced by the {\TeX} text ``\verb+\ne+''. +Then we write +\begin{quote} +\begin{verbatim} +token != translation <"\\ne"> +\end{verbatim} +\end{quote} +(Two backslashes appear in the translation because {\tt SPIDER} uses +C~conventions for string literals. +The angle brackets {\tt <...>} delimit translations.) +The default for translation is just as in {\tt TANGLE}, so if we want +``{\tt +}'' on input to produce ``$+$'' on output we need not specify a +translation for the token \token{+}. + +The process of deciding where to put line breaks and indentation is +the most complicated part of {\tt WEAVE}. +We have to do this based on the sequence of tokens we have, but the +exact details of which token is where usually aren't needed to do +prettyprinting. +Hence we introduce the {\em scrap}, which abstracts away from the +detail not needed to do prettyprinting. +A scrap has two parts: the translation, which we have already seen, +and the {\em category}, which + corresponds to a ``part of speech'' or a symbol in a grammar. +{\tt WEAVE} uses categories to decide where to put +indentation and line breaks. +Since there are usually many different tokens having the same category, +prettyprinting is simplified enormously. + +{\tt WEAVE} begins processing a program fragment by tokenizing the +fragment, then converting each token in the resulting token list into +a scrap. +It then attempts to reduce the length of the resulting scrap list by +combining adjacent scraps into a single scrap, possibly intercalating +additional translations, which may include +{\em indent}, {\em outdent}, and {\em force} instructions. +The scraps are combined according to one of many {\em reduction rules}. +{\tt WEAVE} decides which adjacent scraps are eligible to be reduced +based only on the categories of the scraps and a knowledge of the +reduction rules. +The reduction rules are the productions of the {\em prettyprinting +grammar}. +{\tt WEAVE}'s reductions of scraps are like the reductions done in +bottom-up parsing. + +To take an example, suppose that we want statements to be separated by +line breaks. +If we can guarantee that any scrap representing a statement has +category {\tt stmt}, it will be enough to specify the reduction rule +\begin{quote}\tt +stmt <force> stmt --> stmt +\end{quote} +which says ``two adjacent {\tt stmt} scraps may be reduced to a single +{\tt stmt} scrap by intercalating a forced line break between them.'' + +So we tell {\tt WEAVE} how to prettyprint a language by telling +how to assign a category to each token and how to combine scraps. +Here's another example: the language of C~expressions. + Let {\tt math} be the category of expressions, +{\tt binop} be the category of binary infix operators, and +{\tt unop} be the category of both unary prefix and unary postfix +operators. +Here are some sample tokens: +\begin{quote} +\begin{verbatim} +token identifier category math +token + category binop +token - category binop +token = category binop translation <"\\leftarrow"> +token == translation <"\\equiv"> category binop +token ( category open +token ) category close +\end{verbatim} +\end{quote} +Notice we print the \token{=} token (assignment) as $\leftarrow$, +whereas we print the \token{==}~token (comparison) as $\equiv$. +This makes it a bit easier for us to see when a programmer has +mistakenly used \token{=} instead of \token{==}. + + +The prettyprinting grammar for C~expressions is: +\begin{quote} +\begin{verbatim} +math binop math --> math +math unop --> math +unop math --> math +open math close --> math +\end{verbatim} +\end{quote} +Using this grammar, {\tt WEAVE} can take a long expression consisting +of many scraps, and reduce it all to a single scrap of category {\tt +math}. + +What about an operator like ``{\tt *}'', which is both binary infix +and unary prefix? +This does the job: +\begin{quote} +\begin{verbatim} +token * category unorbinop +unorbinop math --> math +math unorbinop math --> math +\end{verbatim} +\end{quote} + +% No Note about context-sensitive reductions? + +There is a mechanism for assigning categories and translations to +reserved words as well as to tokens, using slightly different syntax. + +To give an idea of the complexity of the grammars, the grammar +describing AWK uses 24~categories in 39~productions. +The Ada grammar uses 40~categories in 65~productions, and the +C~grammar uses 54~categories in 129~productions. + +\medskip + +{\tt SPIDER}-generated versions of {\tt TANGLE} and {\tt WEAVE} differ +subtly from the originals written by Donald Knuth. +The most important difference is that {\tt SPIDER}-generated {\tt WEB} +is not self-contained: where Knuth's Pascal {\tt WEB} required only a +Pascal compiler to bring up, {\tt SPIDER} would need a C~compiler and +an AWK~interpreter to generate a Pascal {\tt WEB}, and a Pascal +compiler for the resulting {\tt WEB} to be of any use. +Other differences are minor; for example, Knuth's {\tt TANGLE} +does arithmetic on constants at {\tt TANGLE} time, but {\tt +SPIDER}-generated {\tt TANGLE}s do not. +Knuth's {\tt TANGLE} provides three different kinds of macros, but +none with more than one parameter; +{\tt SPIDER}-generated {\tt TANGLE}s provide only one kind of macro, +but macros of that kind may have from zero to thirty-two parameters. + + + +{\tt SPIDER} is a {\tt WEB} generator, akin to parser generators. +Both read formal descriptions of some part of a programming language, +and both produce code that processes programs written in that language. +Since both produce code that is part of the ``compiler,'' using them +doesn't introduce any extra steps into the processing of user programs. +{\tt SPIDER} itself is a large AWK script, written as a {\tt WEB} +program. +{\tt spider.web} is about 2600 lines long; about a third of these are +comments. + + +The major cost of using {\tt SPIDER} is the cost of learning yet +another language. +Learning this language is supposed to substitute for learning how to +modify {\tt WEB}, so it is probably not an exorbitant cost. +Some other limitations are the the need for a C~compiler and an +AWK~interpreter, and the need to use a lowest-common-denominator +lexical analyzer. + +The major benefit of using {\tt SPIDER} is the ease with which new +{\tt WEB}s can be built. +%\remark{(Here is the place to talk about Oberon.)} +The {\tt SPIDER} description of a language is much smaller than the +{\tt WEB} implementation generated from that description, and {\tt +SPIDER} descriptions of similar languages are similar. +Using {\tt SPIDER} one can build a {\tt WEB} without understanding the +details of {\tt WEB}'s implementation, and one can easily adjust that +{\tt WEB} to change as a language definition changes. +%\remark{Could mention work with Larch/Ada-88} + + + +{\tt SPIDER} should make one literate programming tool, {\tt WEB}, +available to a much larger audience. +I hope that, by separating the language-independent parts of {\tt WEAVE} +and {\tt TANGLE}, {\tt SPIDER} will encourage us not just to think +about what the essence of tangling and weaving is, but also about what +the essence of literate programming is. + + +\medskip + +I enjoyed many useful discussions of {\tt WEB} with Charlie Mills. +I am grateful to +Silvio Levy for providing his {\tt CWEB} as the basis for the +``master copies'' of {\tt TANGLE} and {\tt WEAVE}, and to +Dave Hanson for comments on an earlier version of this paper. + +\begin{thebibliography}{van~Knuth~999} +\bibitem[Bentley~86]{bentley:lp} +Jon L. Bentley, ``Programming Pearls,'' +{\sl Communications of the ACM} {\bf 29:5} (May~1986), 364--368, and +{\bf 29:6} (June~1986), 471--483. +\bibitem[Knuth~84]{knuth:literate-programming} +Donald E. Knuth, ``Literate Programming,'' {\sl The Computer Journal} +{\bf 27:2}(1984), 97-111. +\bibitem[Levy~87]{levy:cweb} +Silvio Levy, ``{\tt WEB} Adapted to C, Another Approach,'' + {\sl TUGBoat} {\bf 8:1}(1987), 12--13. +\bibitem[Oppen~80]{oppen:prettyprinting} +Derek Oppen, ``Prettyprinting,'' TOPLAS~{\bf 2:4} (October 1980), +465--483. +\bibitem[Ramsey~89]{ramsey:developing} +Norman Ramsey, ``Developing Formally Verified Ada Programs,'' +Proceedings, {\sl Fifth International Workshop on Software +Specification and Design}, to appear. +\bibitem[Van~Wyk~87]{cvw:loom} +Christopher J. Van~Wyk, ``Literate Programming,'' +{\sl Communications of the ACM} {\bf 30:7} (July~1987), 593--599, and +{\bf 30:12} (December~1987), 1000--1010. +\end{thebibliography} + +\end{document} diff --git a/web/spiderweb/doc/overview.aux b/web/spiderweb/doc/overview.aux new file mode 100644 index 0000000000..67eea2a819 --- /dev/null +++ b/web/spiderweb/doc/overview.aux @@ -0,0 +1,12 @@ +\relax +\citation{bentley:lp,cvw:loom} +\citation{knuth:literate-programming} +\citation{levy:cweb} +\@writefile{toc}{\string\contentsline\space {section}{Introduction}{1}} +\@writefile{toc}{\string\contentsline\space {section}{Features of Spidery {\string\ptt\space WEB}}{2}} +\@writefile{toc}{\string\contentsline\space {section}{Scope of {\string\ptt\space SPIDER}}{2}} +\bibcite{bentley:lp}{Bentley\penalty \@M \ 86} +\bibcite{knuth:literate-programming}{Knuth\penalty \@M \ 84} +\bibcite{levy:cweb}{Levy\penalty \@M \ 87} +\bibcite{cvw:loom}{Van\penalty \@M \ Wyk\penalty \@M \ 87} +\@writefile{toc}{\string\contentsline\space {section}{Conclusions}{3}} diff --git a/web/spiderweb/doc/overview.tex b/web/spiderweb/doc/overview.tex new file mode 100644 index 0000000000..0e568d0392 --- /dev/null +++ b/web/spiderweb/doc/overview.tex @@ -0,0 +1,149 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +\documentstyle[11pt]{article} +\title{A note about a new implementation of {\tt WEB}} +\author{Norman Ramsey\\Odyssey Research Associates} +\date{July 4, 1988} +\setcounter{secnumdepth}{0} +\begin{document} +\maketitle + +\begin{abstract} +Literate programming has received recent attention in the {\sl +Communications of the ACM}~\cite{bentley:lp,cvw:loom}. +{\tt WEB} is a tool intended for literate programming, but +until recently it was useful only for writing PASCAL programs. +The author has developed a new tool, {\tt SPIDER}, which reads a +description of a programming language and writes a {\tt WEB} system +that can be used to write programs in that language. +{\tt SPIDER} has been used in the author's organization to build {\tt +WEB} systems for Ada, C, AWK, and other languages. +The author hopes that {\tt SPIDER} will enable people to write +literate programs in many more languages than they could before. +\end{abstract} + + +\section{Introduction} +Donald Knuth developed the {\tt WEB} system of structured documentation +as part of the {\TeX} project~\cite{knuth:literate-programming}. +His implementation of {\tt WEB} combined PASCAL and {\TeX}. + The {\tt WEB} idea suggests a way of combining {\em any} +programming language with {\em any} document formatting language, +but until recently there was no software support for writing in {\tt +WEB} anything but PASCAL programs. +In~1987, Silvio Levy rewrote the {\tt WEB} system in C for C, +while retaining {\TeX} as the formatting language~\cite{levy:cweb}. +I have has modified Levy's implementation by removing the parts +that make C the target programming language, and I have + added a third tool, {\tt SPIDER}, which complements {\tt WEAVE} +and {\tt TANGLE}. +{\tt SPIDER} reads a description of a programming language, and writes +source code for a {\tt WEAVE} and {\tt TANGLE} which support that +language. +Using {\tt SPIDER}, a C~compiler, and an AWK~interpreter, an experienced +systems programmer can generate in a few hours a {\tt WEB} system for +an Algol-like language. + +\section{Features of Spidery {\tt WEB}} +An exhaustive list of Spidery {\tt WEB}'s features would interest only +{\tt WEB} experts, +but I do want to mention some features that I hope will encourage +people to use Spidery {\tt WEB}. +\begin{itemize} +\item +{\tt TANGLE} and {\tt WEAVE} can read from multiple files (this +feature is present in Levy's {\tt CWEB}), and +{\tt TANGLE} can write to multiple files. +Included files will be searched for on a path if not found in the +current directory. +These features make Spidery {\tt WEB} more usable on systems that have +{\tt make}. +\item +{\tt TANGLE} can expand macros with multiple parameters. +\item +The starred sections in Spidery {\tt WEB} can be organized +hierarchically (in three levels). +We have a UNIX tool that can extract different pieces of the hierarchy +from the output of {\tt WEAVE}, so that it is possible to take +excerpts from {\tt WEB} documents. +\item +{\tt TANGLE} writes {\tt \#line} directives, so you can debug at the +{\tt WEB} source level if your compiler respects the C~conventions for +{\tt\#line}. +\item +Many features of {\tt WEB} seem to exist only to compensate for +deficiencies in PASCAL, and most of those were dropped in {\tt CWEB}. +I have changed much of {\tt CWEB} in order to avoid being bound too +much by C conventions. +As a result, there are dozens of minor differences between Spidery +{\tt WEB} and original {\tt WEB}. +To give just one example, Spidery {\tt WEB} supports +octal and hexadecimal constants using {\tt WEB}-style +notation, not the C~notation used in {\tt CWEB}. +\end{itemize} + +\section{Scope of {\tt SPIDER}} +{\tt SPIDER} can generate {\tt WEB} systems for a variety +of languages. +The author has written {\tt SPIDER} description files for C, AWK, Ada, +SSL (a language that describes attribute grammars to the +Cornell Synthesizer Generator), +the Larch Shared Language (a language for describing equational +theories), +and Dijkstra's language of guarded commands. +Debugging the grammar that {\tt WEAVE} uses to +prettyprint the language is the most time-consuming part of creating a +{\tt WEB} system for a new target language, +and {\tt SPIDER} makes it trivial to change that grammar. +To make a {\tt SPIDER} description file for an Algol-like language +that uses infix expression notation, an experienced systems programmer +should be able to adapt an existing {\tt SPIDER} description file very +quickly. + +{\tt SPIDER}'s major limitations are lexical. + All Spidery {\tt WEB}s +assume that spaces and tabs in the input are not significant, except +as separators; +this makes it impossible to construct Spidery {\tt WEB}s for languages +like Fortran and Miranda, where the position of text on a line is +significant. +The lexical structures of identifiers, string literals, and numeric +literals are fixed. + +\section{Conclusions} +{\tt SPIDER} is a modest piece of engineering; it does not introduce +new ideas. +{\tt SPIDER} does make it possible to create a new {\tt WEB} quickly, +and to tinker with it easily. +The author's group routinely uses Spidery {\tt WEB} to write programs +in Ada, C, and~SSL, and has been pleased with the result. +We have written in {\tt WEB} an application of eighteen thousand +lines, and +we are very pleased at how easy it has been to review and maintain +this code. +The author hopes that the availability of Spidery {\tt WEB} will +encourage other groups to try literate programming, and that they, +too, will be pleased with the results. + + + +\begin{thebibliography}{Van~Wyk~9999} +\bibitem[Bentley~86]{bentley:lp} +Jon L. Bentley, ``Programming Pearls,'' +{\sl Communications of the ACM} {\bf 29:5} (May~1986), 364--368, and +{\bf 29:6} (June~1986), 471--483. +\bibitem[Knuth~84]{knuth:literate-programming} +Donald E. Knuth, ``Literate Programming,'' {\sl The Computer Journal} +{\bf 27:2} (1984), 97--111. +\bibitem[Levy~87]{levy:cweb} +Silvio Levy, ``{\tt WEB} Adapted to C, Another Approach,'' + {\sl TUGBoat} {\bf 8:1} (1987), 12--13. +\bibitem[Van~Wyk~87]{cvw:loom} +Christopher J. Van~Wyk, ``Literate Programming,'' +{\sl Communications of the ACM} {\bf 30:7} (July~1987), 593--599, and +{\bf 30:12} (December~1987), 1000--1010. +\end{thebibliography} + +\end{document} diff --git a/web/spiderweb/doc/spdjman.tex b/web/spiderweb/doc/spdjman.tex new file mode 100644 index 0000000000..bcb6b28a8a --- /dev/null +++ b/web/spiderweb/doc/spdjman.tex @@ -0,0 +1,2065 @@ +% $Header: /usr2/nabe/Tools/WEB_Tool/Spiderweb/doc-j/RCS/spdjman.tex,v 1.5 92/02/28 16:34:11 nabe Exp $ +% This file is translated from English into Japanese by Izumi Watanabe, +% (nabe@miya.fujifilm.co.jp). +% As Mr. Ramsey wrote, to be used for reserch purposes only. +% This file contains Japanese Kanji-character codes, called EUC (Extended +% Unix Code), and is written for Japanese-LaTeX, called ASCII-jLaTeX. + + +%% Copyright 1989 by Norman Ramsey and Odyssey Research Associates +%% To be used for research purposes only +%% For more information, see file COPYRIGHT in the parent directory + +% ¤³¤ÎÆüËܸìÌõ¤Ï»²¹Í¤È¤·¤Æ ÅÏÊÕÀô(nabe@miya.fujifilm.co.jp)¤¬¹Ô¤Ê¤¤¤Þ¤·¤¿¡£ +% ¤³¤Î¥É¥¥å¥á¥ó¥È¤Ï¥ª¥ê¥¸¥Ê¥ë¤Î spider.man ¤ò½¤Àµ¤·¤¿¤â¤Î¤Ê¤Î¤Ç¡¢ +% Mr. Ramsey ¤Î»ØÄêÄ̤ê¤Ë¸¦µæÌÜŪ¤Ë¤Î¤ß»ÈÍѲÄǽ¤Ç¤¹¡£ +% °·¤¤¤Ë¤ÏÃí°Õ¤·¤Æ²¼¤µ¤¤¡£ + +%% spiderman.tex, with apologies to Stan Lee + +%%\documentstyle[11pt]{article} +\documentstyle[a4j]{jarticle} +\setcounter{secnumdepth}{0} +\newcommand{\syntax}[1]{\mbox{$\langle\hbox{\sl #1\/}\rangle$}} +\newcommand{\produces}{\mbox{${}::={}$}} +\newcommand{\opt}[1]{$[$#1$]$} +\newcommand{\BS}{\relax} +\chardef\BS=`\\ % backslash in a string +\def\jem{\em\gt} +\def\P#1#2{#2:#1} +\newcommand {\WEB}{{\tt WEB}} + +\title{{Spider} ¥æ¡¼¥¶¡¼¥º¥¬¥¤¥É} +\author{Norman Ramsey\thanks{ + Department of Computer Science, Princeton University, + ``A {Spider} User's Guide'',{July 1989}.}\ Ãø \\ + ÅÏÊÕÀô\thanks{Æü·Ðmix:w.izumi, nabe@miya.fujifilm.co.jp}\ Ìõ} +\date{Feb 1992 \\ J-$Revision: 1.5 $} + +\begin{document} +\maketitle + +\section{¤Ï¤¸¤á¤Ë} +Donald Knuth ¤Ï {\tt WEB} ¤È¤¤¤¦¡¢¹½Â¤²½¥É¥¥å¥á¥ó¥Æ¡¼¥·¥ç¥ó¡¦¥·¥¹¥Æ¥à¤ò +{\TeX} ¥×¥í¥¸¥§¥¯¥È~\cite{knuth:literate-programming} ¤Î°ìÉô¤È¤·¤Æ³«È¯¤·¤¿¡£ +{\tt WEB}¤ò»È¤¦¤È¡¢¥×¥í¥°¥é¥Þ¡¼¤Ï¼«Ê¬¤Î¥×¥í¥°¥é¥à¤ò¤¤¤¯¤Ä¤â¤Î¤«¤¿¤Þ¤ê ( +{\jem ¥â¥¸¥å¡¼¥ë}) ¤Ëʬ³ä¤·¤Æ¡¢¤½¤ì¤é¤Ëʸ¾Ï¤òÉÕÍ¿¤·¡¢¹¥¤¤Ê½çÈÖ¤ËÀâÌÀ¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¤è¤¦¤Ë¤Ê¤ë¡£ +Knuth ¤¬ºî¤Ã¤¿¤â¤Î¤Ç¤Ï¡¢³Æ¥â¥¸¥å¡¼¥ë¤Ï PASCAL ¥×¥í¥°¥é¥à¤Ç¤¢¤ê¡¢ +¤½¤ì¤é¤¬ {\TeX} ¤ò»ÈÍѤ·¤ÆÀ¶½ñ¤µ¤ì¤ë¡£ + + {\tt WEB} ¤Î¥¢¥¤¥Ç¥¢¤Ï¡¢{\jem Ǥ°Õ}¤Î¥×¥í¥°¥é¥ß¥ó¥°¸À¸ì¤È +{\jem Ǥ°Õ}¤Îʸ½ñÀ¶½ñ¸À¸ì\index{\P{document formatting language}{ʸ½ñÀ¶½ñ¸À¸ì}} +¤ò·ë¹ç¤¹¤ëÊýË¡¤òÄó°Æ¤·¤Æ¤¤¤ë¡£ +¤·¤«¤·¡¢ºÇ¶á¤Þ¤Ç¤Ï¡¢PASCAL ¥×¥í¥°¥é¥àÍѤΠ\WEB °Ê³°¤Î +»Ù±ç¥½¥Õ¥È¥¦¥§¥¢¤Ï¤Ê¤«¤Ã¤¿¡£ +\hbox{1987ǯ}¤Ë¡¢Silvio Levy ¤¬ C¤Î¤¿¤á¤Î{\tt WEB} ¥·¥¹¥Æ¥à¤òC ¤Ç½ñ¤Ä¾¤·¤¿¡£ +¤³¤Î»þ¤âʸ½ñÀ¶½ñ¸À¸ì¤È¤·¤Æ¤Ï {\TeX} ¤¬°ú¤Â³¤»È¤ï¤ì¤¿~\cite{levy:cweb}¡£ +É®¼Ô¤Ï¡¢Levy ¤Î½ñ¤¤¤¿¤â¤Î¤ò½¤Àµ¤·¡¢ C ¤ò¥¿¡¼¥²¥Ã¥È¸À¸ì¤È¤¹¤ëÉôʬ¤ò¼è¤ê½ü¤¤¤¿¡£ +¤½¤·¤Æ¡¢{Spider}¤È¤¤¤¦ {\tt WEAVE}¤È{\tt TANGLE}¤òºî¤ë +Â裳¤Î¥Ä¡¼¥ë¤òÄɲä·¤¿¡£ +{Spider} ¤Ï¡¢¤¢¤ë ¥×¥í¥°¥é¥ß¥ó¥°¸À¸ì¤Ë¤Ä¤¤¤Æ¤Îµ½Ò¤òÆɤߡ¢ +¤½¤Î¸À¸ì¤ò¥µ¥Ý¡¼¥È¤·¤¿ {\tt WEAVE} ¤È {\tt TANGLE} ¤Î¥½¡¼¥¹¥³¡¼¥É¤ò +½ñ¤½Ð¤¹¡£ + {Spider}¡¢ C~¥³¥ó¥Ñ¥¤¥é¡¢ Awk~¥¤¥ó¥¿¥×¥ê¥¿¤ò»È¤¨¤Ð¡¢ + ·Ð¸³¤òÀѤó¤À¥·¥¹¥Æ¥à¥×¥í¥°¥é¥Þ¤Ê¤é Algol ¤Î¤è¤¦¤Ê¸À¸ì¤Î +{\tt WEB} ¥·¥¹¥Æ¥à¤ò ¿ô»þ´Ö¤ÇÀ¸À®¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¤À¤í¤¦¡£ + +¤³¤Î¥É¥¥å¥á¥ó¥È¤Ï¡¢Ç¤°Õ¤Î¥×¥í¥°¥é¥à¸À¸ì¤Î¤¿¤á¤Î{\WEB}¥·¥¹¥Æ¥à¤òºî¤ë¤¿¤á¤Î +{Spider} ¤Î»È¤¤Êý¤òÀâÌÀ¤·¤Æ¤¤¤ë (¥×¥í¥°¥é¥ß¥ó¥°¸À¸ì¤ÎÁªÂò¤Ï¡¢ +¸å¤Ç¸«¤ë¤³¤È¤Ë¤Ê¤ë¤¬¡¢Spidery {\tt WEB}¤ÎÃæ +¤Ëºî¤ê¹þ¤Þ¤ì¤¿»ú¶ç¹½Â¤\index{\P{lexical structure}{»ú¶ç¹½Â¤}} +¤ÎÀ©¸Â¤Ë¤Î¤ßÀ©¸Â¤ò¼õ¤±¤ë)¡£ +»²¹Í½ñ¤È¤·¤Æ +¡ÖThe Spidery {\WEB} system of structured documentation¡×¤Ç¡¢ +{\WEB} system ¤Îºî¤êÊý¤ò³Ø¤ó¤Ç¤ª¤¯¤È¤è¤¤¡£ + + +\paragraph{»öÁ°½àÈ÷} +{Spider} ¤ò»È¤Ã¤Æ {\WEB} ¥·¥¹¥Æ¥à¤ò +ºî¤í¤¦¤È¤·¤Æ¤¤¤ë¤Ê¤é¡¢{\tt WEB}¤Ë¤Ê¤¸¤ó¤Ç¤ª¤¯¤³¤È¡£ +{\tt WEB} ¤¬²¿¤ò¤É¤¦¤¹¤ë¤Î¤«¤òÃΤꤿ¤±¤ì¤Ð¡¢ +Knuth ¤Î½ñ¤¤¤¿{\WEB}~\cite{knuth:literate-programming}¤Î¾Ò²ðµ»ö: + {\WEB} users' manual ¤òÆɤó¤Ç¤ª¤¯¤Ù¤¤Ç¤¢¤ë ( {\WEB} user's manual ¤Ï¡¢ +¼ê»Ï¤á¤È¤·¤Æ¤Ï¤«¤Ê¤ê½ÅÎ̵é¤Ç¤¢¤ë¡£ +»²¹Íʸ¸¥¤ÎÃæ¤Ë¡¢{\WEB}¤Î¤â¤Ã¤ÈƳÆþŪ¤Ê¤â¤Î¤òÁܤ·µá¤á¤Æ¤âÎɤ¤¡£ +Wayne Sewell ¤Î {\it Weaving a Program: Literate Programming in {\tt +WEB}} +¤ÏÌò¤ËΩ¤Ä¤À¤í¤¦~\cite{sewell:weaving})¡£ + +¤³¤ì°Ê¹ß¤Ï¡¢ÆɼԤ¬{\tt WEAVE} ¤È {\tt TANGLE} ¤È¤Ï¤Ê¤Ë¤«¤òÃΤäƤª¤ê¡¢ +¤½¤ì¤é¤¬²¿¤òÆþÎϤȤ·¡¢½ÐÎϤ¹¤ë¤â¤Î¤¬¤Ê¤Ë¤«¤òÃΤäƤ¤¤ë¤â¤Î¤È¤·¤ÆÏäò¿Ê¤á¤ë¡£ + + +\paragraph{¤³¤Î¥¬¥¤¥É¤Î¿Ê¤áÊý} +¤Þ¤º¡¢weaving ¤È tangling ¤ÎÉü½¬¤«¤é»Ï¤á¡¢¸À¸ì¤Ë°Í¸¤·¤Ê¤¤ {\WEB}¤ò +ºî¤ë¤Î¤ËɬÍפʥ¢¥¤¥Ç¥¢¤ò¤Ä¤«¤á¤ë¤è¤¦¤Ë¤¹¤ë¡£ +¤½¤ì¤«¤é¡¢{\WEB}¤Ë¥×¥í¥°¥é¥ß¥ó¥°¸À¸ì¤Ë¤Ä¤¤¤Æ¶µ¤¨¤ë¤È¤¤¤¦¡¢ +{Spider} ¤ÎÆÃħ¤Ë¤Ä¤¤¤Æ¤ÎµÄÏÀ¤ò½Ò¤Ù¤ë¡£ +¤³¤ì¤é¤ò¾ÜºÙ¤ËÄêµÁ¤·¡¢¤¤¤¯¤Ä¤«¤ÎÎã¤ò¼¨¤¹¡£ +¤½¤·¤ÆºÇ¸å¤Ë¡¢ +{Spider} ¸À¸ì¤È¥Ä¡¼¥ë¤Ë¤Ä¤¤¤Æ¤Î´°Á´¤Êµ½Ò¤ò¤â¤Ã¤Æ½ª¤ï¤ë¤³¤È¤Ë¤¹¤ë¡£ + + +\section{{\tt WEAVE} ¤È {\tt TANGLE} ¤«¤é¸«¤¿À¤³¦} +{\tt WEAVE} ¤È {\tt TANGLE} ¤Ï¤¤¤º¤ì¤âƱ°ì¤Î{\WEB}¥Õ¥¡¥¤¥ë¤òÆþÎϤȤ¹¤ë¡£ +{\tt WEAVE} ¤Ï¡¢ÆþÎϤò¸¡ºº¤·¡¢{\TeX}¥Æ¥¥¹¥È¤òÀ¸À®¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£°ìÊý¡¢ +{\tt TANGLE} ¤Ï¡¢Æ±¤¸ÆþÎϤ«¤é¥×¥í¥°¥é¥à¥Æ¥¥¹¥È¤òÀ¸À®¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ +ÆþÎϤϡ¢{\TeX}Éô¡¢ÄêµÁÉô¡¢¥³¡¼¥ÉÉô¤«¤é¤Ê¤ë¡£ + {\TeX}Éô¤Ï¤â¤Ã¤È¤â°·¤¤¤¬ÍưפǤ¢¤ë: {\tt WEAVE} ¤Ç¤Ï¥³¥Ô¡¼¤·¡¢ + {\tt TANGLE} ¤Ç¤Ï¼Î¤Æ¤ì¤ÐÎɤ¤¡£ +ÄêµÁÉô¤Ï¾¯¤·Ê£»¨¤Ç¤¢¤ë: {\tt WEAVE}¤Î»Å»ö¤Ï¡¢¤½¤ì¤é¤òÁÈÈǤ·¡¢ +°ìÊý{\tt TANGLE} ¤ÏÄêµÁ¤òµ²±¤·Å¬ÀڤʤȤ¤ËŸ³«¤¹¤ë¡£ +¥³¡¼¥ÉÉô¤Ï°ìÈÖÊ£»¨¤Ç¤¢¤ë: {\tt WEAVE} ¤Ï¤½¤ì¤é¤òÀ¶½ñ¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤·¡¢ +{\tt TANGLE} ¤Ï°ì´Ó¤·¤¿¥×¥í¥°¥é¥à¥Æ¥¥¹¥È¤ËÀ°Íý¤·Ä¾¤µ¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ + + +\paragraph{{\WEB}¤Î»ú¶ç²òÀÏ} +{\tt WEAVE} ¤È {\tt TANGLE} ¤Î¤¤¤º¤ì¤â¡¢¥³¡¼¥ÉÉô¤ò{\jem ¥È¡¼¥¯¥ó}¤ÎÏ¢¤Ê¤ê¤È¤·¤Æ +²ò¼á¤¹¤ë¡£ +¤¹¤Ù¤Æ¤Î¥×¥í¥°¥é¥ß¥ó¥°¸À¸ì¤¬Æ±¤¸¥È¡¼¥¯¥ó¤ò»ý¤Ã¤Æ¤¤¤ë¤ï¤±¤Ç¤Ï¤Ê¤¤¤Î¤Ç¡¢ +{Spider}¤Î»Å»ö¤Ï¡¢ {\tt WEAVE} ¤È {\tt TANGLE} ¤Ë +ÆþÎϤò¥È¡¼¥¯¥ó¤Ëʬ²ò¤¹¤ë¤ä¤êÊý¤ò¶µ¤¨¤ë¤³¤È¤Ë¤Ê¤ë +\footnote{% +¸½ºß¤Î{\tt WEB}¤Î»ú¶ç²òÀϤμÂÁõ¤Ï¸ÂÄꤵ¤ì¤Æ¤¤¤ë¡£ +¤³¤ì¤Ï¡¢Àµµ¬É½¸½¤ò»È¤Ã¤¿¤â¤Î¤ËÃÖ¤´¹¤¨¤é¤ì¤ë¤Ù¤¤Ç¤¢¤ë¡£ +}¡£ +Spidery {\WEB} ¥·¥¹¥Æ¥à¤Ï°Ê²¼¤Î¥È¡¼¥¯¥ó¤òǧ¼±¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¡£ +\begin{itemize} +\item ¼±ÊÌ»Ò(identifiers) +\item ¿ôÃÍÄê¿ô¤Èʸ»úÎóÄê¿ô +\item ²þ¹Ô +\item ``µ¿»÷¥»¥ß¥³¥í¥ó'' ({\tt @;}) +\item ͽÌó¸ì +\item Èó±Ñ¿ô»ú¥È¡¼¥¯¥ó +\end{itemize} + +{\tt TANGLE} ¤Ï¡¢¤³¤ì¤é¤Î¥È¡¼¥¯¥ó¤ò1¤Ä¤ÎŤ¤¥×¥í¥°¥é¥à¥Æ¥¥¹¥È¤È¤·¤ÆºÆÀ°Íý +¤·¤¿¤Î¤Á¡¢¥È¡¼¥¯¥óËè¤Ë¥×¥í¥°¥é¥à¥Æ¥¥¹¥È¤ò½ñ¤½Ð¤¹¡£ +Ä̾ï {\tt TANGLE} ¤Ï¡¢¥È¡¼¥¯¥ó¤Î´Ö¤Ë¶õÇòʸ»ú¤òÁÞÆþ¤·¤Ê¤¤¡£ +¤·¤«¤·¡¢¼±Ê̻ҡ¢Í½Ìó¸ì¡¢¿ôÃÍÄê¿ô¤Î²ó¤ê¤Ë¤Ï¶õÇò¤ò¤ª¤¯¡£ +ÆþÎϤ¬¡¢ +\begin{quote} +\tt if 0 > x-y then z := -1; +\end{quote} +¤Ê¤é¤Ð¡¢½ÐÎϤϡ¢ +\begin{quote} +\tt if 0>x-y then z:=-1; +\end{quote} +¤È¤Ê¤ê¡¢²òÀϤǤ¤Ê¤¤¤è¤¦¤Ê +\begin{quote} +\tt if0>x-ythenz:=-1; +\end{quote} +¤È¤Ï¤Ê¤é¤Ê¤¤¡£ +{\tt TANGLE} ¤¬ÊÑ´¹¤¹¤ë¤Î¤È°ã¤¦¥È¡¼¥¯¥ó¤ò˾¤à»þ¤Ë¤Ï¡¢ +³Æ¥È¡¼¥¯¥ó¤Ë {\tt tangleto}°À¤òÍ¿¤¨¤ë¤³¤È¤¬¤Ç¤¤ë¡£ +¤³¤Î»ØÄê¤Ï¡¢¤½¤Î¥È¡¼¥¯¥ó¤ò¥×¥í¥°¥é¥à¥Æ¥¥¹¥È¤È¤·¤Æ¤É¤¦°õºþ¤¹¤Ù¤¤«¤ò»ØÄꤹ¤ë +¤â¤Î¤Ç¤¢¤ë¡£ +Î㤨¤Ð¡¢ +C{\WEB}¤òÀ¸À®¤¹¤ë¤¿¤á¤Î{\tt spider}¥Õ¥¡¥¤¥ë¤Ç¤Ï¡¢{\tt =} ¤ò\ {\tt "=\ "} +¤È¤¤¤¦Ê¸»úÎó¤Ç°õºþ¤µ¤ì¤ë¥È¡¼¥¯¥ó¤È¤·¤Æ¤ª¤¤¿¤¤¡£ C ¤Ç¤Ï\ {\tt "=-"} ¤È¤¤¤¦ +ʸ»úÎó¤Î°ÕÌ£¤¬Û£Ëæ¤Ë¤Ê¤Ã¤Æ¤·¤Þ¤¦¤«¤é¤Ç¤¢¤ë¡£ + +%{\tt WEAVE} must turn the token stream into a {\TeX} text that will +{\tt WEAVE} ¤Ï¥È¡¼¥¯¥ó¤ÎʤӤò{\TeX} ¥Æ¥¥¹¥È¤ËÊÑ´¹¤·¡¢ +À°·Á°õºþ¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ +¤³¤ì¤Ï 3¤Ä¤Î¥¹¥Æ¥Ã¥×¤Ç¼Â¸½¤µ¤ì¤ë¡£ +\begin{enumerate} +\item +{\tt WEAVE} ¤Ï¡¢³Æ¥È¡¼¥¯¥ó¤ò {\jem ¥¹¥¯¥é¥Ã¥×}¤ËÊÑ´¹¤¹¤ë¡£ +¥¹¥¯¥é¥Ã¥×¤Ï¡¢2¤Ä¤Î½ÅÍפÊÆÃÀÃͤò»ý¤Ä: ¤½¤ì¤Ï¡¢ +¹½Ê¸¾å¤Î{\jem ¥«¥Æ¥´¥ê¡¼} ¤È +{\jem ËÝÌõ$($translation$)$}\index{\P{translation}{ËÝÌõ}} +¤Ç¤¢¤ë¡£ +¥«¥Æ¥´¥ê¡¼¤Ï¡¢À¶½ñ¤ò¤¹¤ë¤¿¤á¤Îʸˡ¾å¤Îµ¹æ¤Ç¤¢¤ë; +¤³¤Îʸˡ¤È¤Ï¡¢{\tt WEAVE} ¤¬À¶½ñÍѤÎÌ¿Îá¤ò»È¤Ã¤Æ¥¹¥¯¥é¥Ã¥×¤òÁȤ߹ç¤ï¤»¤ë +ÊýË¡¤Ç¤¢¤ë¡£ +%The translations are the {\TeX} texts that will tell {\TeX} exactly +%how to print the scraps. +translation\index{translation}¤È¤Ï¡¢{\TeX}¤¬¥¹¥¯¥é¥Ã¥×¤ò°õºþ¤¹¤ë¤¿¤á¤Î +{\TeX}¥Æ¥¥¹¥È¤Ç¤¢¤ë¡£ +\item +{\tt WEAVE}¤Ï¡¢¥¹¥¯¥é¥Ã¥×¤ÎʤӤòÀ¶½ñʸˡ¤Ë¤·¤¿¤¬¤Ã¤Æ´Ô¸µ¤·¤Æ¤¤¤¯( +{\tt WEAVE} ¤Ï¡¢shift-reduce ¹½Ê¸²òÀϤΰì¼ï¤ò¹Ô¤Ê¤¦)¡£ +translation \index{translation} ¤ò·ë¹ç¤·¤Æ¤¤¤ë¤¢¤¤¤ÀÃæ¡¢{\tt WEAVE} ¤Ï +¥¤¥ó¥Ç¥ó¥È¡¢¥¢¥¦¥È¥Ç¥ó¥È¡¢¹ÔÊѤ¨¤Ê¤É¤ò¤¹¤ë¤¿¤á¤Î +{\TeX} ¥Æ¥¥¹¥È¤òÄɲ䷤Ƥ¤¤¯¡£ +\item +ÍýÁÛŪ¤Ê¾ì¹ç¤Ë¤Ï¡¢{\tt WEAVE}¤ÏÈó¾ï¤ËŤ¤ translation\index{translation}¤ò»ý¤Ã¤¿ +°ì¤Ä¤Î¥¹¥¯¥é¥Ã¥×¤Ë¤Ê¤ë¤Þ¤Ç¡¢´Ô¸µ¤·¤¿¥¹¥¯¥é¥Ã¥×¤òÊÝ»ý¤¹¤ë¡£ +¤·¤«¤·¡¢¤¿¤Ö¤ó¡¢´Ô¸µ¤Ç¤¤Ê¤¤¥¹¥¯¥é¥Ã¥×¤ÎʤӤˤè¤Ã¤Æ½ª¤Ã¤Æ¤·¤Þ¤¦¤À¤í¤¦¡£ +¤¤¤º¤ì¤Ë¤»¤è¡¢¤½¤ì°Ê¾å´Ô¸µ¤Ç¤¤Ê¤¯¤Ê¤Ã¤¿¸å¤Ï¡¢ +»Ä¤Ã¤¿¥¹¥¯¥é¥Ã¥×¤Î translation\index{translation}¤ò°ì¤Ä¤º¤Ä½ÐÎϤ¹¤ë¡£ +\end{enumerate} + + +\section{{Spider}¤ò»È¤Ã¤Æ {\WEB}¤Î¥È¡¼¥¯¥óʬ²ò¤ò·è¤á¤ë} +{Spider} ¤Ï ¥È¡¼¥¯¥ó¤ò ͽÌó¸ì¤È¤½¤Î¾ ¤Î 2¼ïÎà¤Ë¶èÊ̤¹¤ë¡£ +ͽÌó¸ì¤Ï¡¢¥³¥Þ¥ó¥É {\tt reserved} ¤È {\tt ilk} +¤ò»È¤Ã¤Æ»ØÄꤹ¤ë¡£ +¤½¤Î¾¤Î¥È¡¼¥¯¥ó¤Ï¡¢¥³¥Þ¥ó¥É{\tt token}¤ò»È¤Ã¤Æ»ØÄꤹ¤ë( +%This somewhat unusual setup is dictated by the way {\tt +%WEAVE} works; its advantage is that is is easy to define a whole group +%of reserved words that will be treated identically.) +¤³¤Î¤¤¤µ¤µ¤«ÈóÄê¾ïŪ¤ÊÀßÄê¤Ï¡¢{\tt WEAVE}¤ÎÊʤ˹ç¤ï¤»¤ë¤¿¤á¤Ç¤¢¤ë¡£ +¤³¤ì¤Ï¡¢¶èÊ̤·¤Æ°·¤Ã¤ÆÍߤ·¤¤Í½Ìó¸ì¤Î¥°¥ë¡¼¥×Á´ÂΤò´Êñ¤ËÄêµÁ¤Ç¤¤ë¤È¤¤¤¦ +Ĺ½ê¤ò»ý¤Ä)¡£ +%Here's how it works: the {\tt reserved} command designates +Ư¤¤ò°Ê²¼¤Ë¼¨¤½¤¦: {\tt reserved} ¥³¥Þ¥ó¥É¤ÏÆÃÄê¤Î¼±Ê̻Ҥò +ͽÌó¸ì¤È¤·¤Æ¤ß¤Ê¤·¡¢¤É¤Î¤è¤¦¤Ê{\jem ilk $($°À$)$}¤È¤·¤Æ°·¤ï¤ì¤ë¤«¤ò +ÌÀ¼¨¤¹¤ë¡£ +% a particular identifier as a reserved word, and says +%what {\jem ilk} it belongs to. +%The {\tt token} and {\tt ilk} commands tell {\tt WEAVE} and {\tt +%TANGLE} what to do with a particular token, or with all the reserved +%words of a particular ilk. +¥³¥Þ¥ó¥É {\tt token} ¤È {\tt ilk} ¤Ï¡¢{\tt WEAVE} ¤È {\tt TANGLE}¤Ë +¤½¤Î¥È¡¼¥¯¥ó¤ò¤É¤¦¤¹¤ë¤«¡¢¤Þ¤¿¤Ï¤½¤Î°À¤ò»ý¤ÄÁ´¤Æ¤ÎͽÌó¸ì¤ò +¤É¤¦¤¹¤ë¤«¤ò»ØÄꤹ¤ë¡£ + +%For each token or ilk one can specify the {\jem tangleto} field, the +%token's {\jem mathness} (whether it has to be typeset in math mode), and +%its {\jem category} and {\jem translation} (for conversion to scraps). +³Æ¥È¡¼¥¯¥ó¤È°À¤Ï {\jem tangleto} ¥Õ¥£¡¼¥ë¥É¤ò»ý¤Ä¤³¤È¤¬¤Ç¤¡¢ +¥È¡¼¥¯¥ó¤Î {\jem mathness} (¿ô¼°¥â¡¼¥É¤ÇÁÈÈǤ¹¤ë¤³¤È¤Î»ØÄê)¤È¡¢ +{\jem ¥«¥Æ¥´¥ê¡¼}¡¢{\jem translation}\index{translation} (¥¹¥¯¥é¥Ã¥×¤Ç¤Î +µ½Ò¤ò»²¾È)¤ò +»ØÄê¤Ç¤¤ë¡£ +¥«¥Æ¥´¥ê¡¼°Ê³°¤Ï¡¢{\tt defaults}¤Ç¤½¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤòÀßÄꤹ¤ë¤³¤È¤¬¤Ç¤¤ë¡£ +¥«¥Æ¥´¥ê¡¼Ì¾¤Ï¥æ¡¼¥¶¡¼¤ÎǤ°Õ¤Ç¤¢¤ë¡£ + +¥È¡¼¥¯¥óʬ²ò¤Î¥³¥Þ¥ó¥É¤Ë¤Ä¤¤¤Æ¤Ï¡¢¸å¤Û¤É{Spider}¤Î¹½Ê¸¤ò¾ÜºÙ¤ËÀâÌÀ¤¹¤ë»þ¤Ë +µÄÏÀ¤·¤¿¤¤¡£ +¤È¤â¤«¤¯¡¢ +C~¸À¸ìÍѤÎ{\tt spider} ¥Õ¥¡¥¤¥ë¤Î¥È¡¼¥¯¥óʬ²ò¥³¥Þ¥ó¥É¤ÎÎã¤ò +¸«¤ë¤³¤È¤Ë¤·¤è¤¦: +\begin{verbatim} +token + category unorbinop +token - category unorbinop +token * category unorbinop +token = category equals translation <"\\leftarrow"> tangleto <"="-space> +token ~ category unop translation <"\\TI"> +token & category unorbinop translation <"\\amp"> +token ^ translation <"\\^"> category binop +token ? translation <"\\?"> category question +token % translation <"\\%"> category binop +token # translation <"\\#"> category sharp +token ! category unop translation <"\\neg"> +token ( category lpar +token ) category rpar +token [ category lpar +token ] category rpar +token { translation <"\\{"> category lbrace +token } translation <"\\}"> category rbrace +token ++ category unop translation <"\\PP"> +token -- category unop translation <"\\MM"> +token != translation <"\\I"> category binop +token == translation <"\\S"> category binop +token && translation <"\\W"> category binop + +ilk case_like category case +ilk int_like category int + +reserved auto ilk int_like +reserved break ilk case_like +reserved case ilk case_like +reserved char ilk int_like +\end{verbatim} +¤³¤³¤Ë¤Ï¡¢C¤Ç»È¤ï¤ì¤ë¥È¡¼¥¯¥ó¤Î¤¤¤¯¤Ä¤«¤ÎÄêµÁÎ㤬¼¨¤µ¤ì¤Æ¤¤¤ë¡£ +{\tt tangleto}¥ª¥×¥·¥ç¥ó¤¬ ¤Û¤È¤ó¤É¤Î¾ì¹ç¥Ç¥Õ¥©¥ë¥È¤Î¤Þ¤Þ¤Ç¤¢¤ë¤³¤È¤È¡¢ +¤½¤·¤Æ {\tt translation} ¥ª¥×¥·¥ç¥ó¤¬¤·¤Ð¤·¤Ð¥Ç¥Õ¥©¥ë¥È¤Î¤Þ¤Þ¤Ç¤¢¤ë¤³¤È¤Ë +Ãí°Õ¤·¤ÆÍߤ·¤¤¡£ + +%Once the tokens are specified, and each has a {\tt tangleto} string, +%we can almost construct a {\tt TANGLE} for the language. +°ìÅ٥ȡ¼¥¯¥ó¤¬»ØÄꤵ¤ì¡¢¤½¤ì¤¾¤ì{\tt tangleto} ʸ»úÎó¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢ +¸À¸ì¤È¤·¤Æ¤Î{\tt TANGLE} ¤Ï¡¢¤Û¤È¤ó¤É¹½ÃۤǤ¤¿¤è¤¦¤Ê¤â¤Î¤Ç¤¢¤ë¡£ +% Before we can construct a {\tt WEAVE}, we have to tell it how to +%combine and reduce scraps. +{\tt WEAVE}¤ò¹½ÃÛ¤¹¤ë¤¿¤á¤Ë¤Ï¡¢¥¹¥¯¥é¥Ã¥×¤Î·ë¹ç¤È´Ô¸µ¤Ë¤Ä¤¤¤Æ¤Î¤ä¤êÊý¤ò +»ØÄꤷ¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ + + + +\section{{Spider}¤Ç{\tt WEAVE}¤Î¥¹¥¯¥é¥Ã¥×¤Î´Ô¸µ¤Î»ÅÊý¤ò»ØÄꤹ¤ë} +%The most intricate part of {\tt WEAVE} is its mechanism for converting +%programming language code into \TeX\ code. +{\tt WEAVE}¤Î¤â¤Ã¤È¤âÊ£»¨¤ÊÉôʬ¤Ï¡¢¥×¥í¥°¥é¥à¸À¸ì¤Î¥³¡¼¥É¤ò \TeX\ ¥³¡¼¥É¤Ë +ËÝÌõ¤¹¤ë¤È¤³¤í¤Ë¤¢¤ë¡£ +%{\tt WEAVE} uses a simple bottom-up parsing algorithm, since it +% must deal with fragmentary +%constructions whose overall ``part of speech'' is not known. +{\tt WEAVE} ¤Ï¡¢Ã±½ã¤Ê ¾å¾º·¿¹½Ê¸²òÀÏ¥¢¥ë¥´¥ê¥º¥à¤ò»È¤Ã¤Æ¤¤¤ë¡£ +¤½¤ì¤Ï¡¢ ´ûÃΤΡÖÏä·¸ÀÍդΰìÉô¡×¤Ç¤Ï¤Ê¤¤¡¢Ê¬ÃǤµ¤ì¤Æ¤¤¤ë¹½Â¤¤ò +°·¤ï¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤¿¤á¤Ç¤¢¤ë¡£ + +ÆþÎϤϡ¢{\jem ¥¹¥¯¥é¥Ã¥×} ¤ÎʤӤȤ·¤ÆÍ¿¤¨¤é¤ì¡¢ +³Æ¥¹¥¯¥é¥Ã¥×¤Ï 2¤Ä¤Î¾ðÊó¤ò´Þ¤ó¤Ç¤¤¤ë¡£ +{\jem category} ¤È {\jem translation}\index{translation}¤Ç¤¢¤ë¡£ +¥«¥Æ¥´¥ê¡¼¤Ï´ðËÜŪ¤Ë¹½Ê¸Åª¤Ê¥¯¥é¥¹¤ò¼¨¤·¡¢ +translation\index{translation} ¤Ï{\TeX}¥³¡¼¥É¤ò¼¨¤·¤Æ¤¤¤ë¡£ +¹½Ê¸µ¬Â§¤È°ÕÌ£µ¬Â§¤ÏÎÙ¤¢¤Ã¤¿¥¹¥¯¥é¥Ã¥×¤ò¤è¤êÂ礤ʤâ¤Î¤Ë¤Þ¤È¤á¤ëÊýË¡¤òµ¬Äꤹ¤ë¡£ +±¿¤¬Îɤ±¤ì¤Ð¡¢¥×¥í¥°¥é¥à¥Æ¥¥¹¥ÈÁ´Éô¤¬¡¢ +²¿É´¤â¤Î¾®¤µ¤Ê¥¹¥¯¥é¥Ã¥×¤À¤Ã¤¿¤È¤³¤í¤«¤é¡¢¸ß¤¤¤Ë·ë¹ç¤µ¤ì¤Æ¹Ô¤¡¢ +°ì¤Ä¤ÎµðÂç¤Ê¥¹¥¯¥é¥Ã¥×¤Ë¤Ê¤ê¡¢ +¤½¤Î translation\index{translation} ¤¬´üÂÔ¤·¤Æ¤¤¤¿ \TeX\ ¥³¡¼¥É¤Ë¤Ê¤ë¤À¤í¤¦¡£ +±¿¤¬°¤±¤ì¤Ð¡¢¤¤¤¯¤Ä¤«¤Î¥¹¥¯¥é¥Ã¥×¤Ï·ë¹ç¤µ¤ì¤Ê¤¤¤Þ¤Þ¤Ë¤Ê¤ë¤À¤í¤¦; +¤½¤ì¤é¤Î translation\index{translation} ¤Ïñ½ã¤Ë°ì¤Ä¤º¤Ä½ÐÎϤµ¤ì¤ë¤³¤È¤Ë¤Ê¤ë¡£ + +·ë¹çµ¬Â§¤Ï¡¢º¸¤«¤é±¦¤Ø¤Îʸ̮°Í¸À¸À®µ¬Â§\index{\P{context-sensitive productions}{ +ʸ̮°Í¸À¸À®µ¬Â§}} +¤È¤·¤ÆÍ¿¤¨¤é¤ì¤ë¡£ +º£¡¢ $s_1\,s_2\ldots s_n$ ¤È¤¤¤¦¥¹¥¯¥é¥Ã¥×¤ÎʤӤò½èÍý¤·¤Æ¤¤¤ë¤È¤¹¤ë¡£ +ºÇ½é¤ÎʤӤǤ¢¤ë$s_1\,s_2\ldots\,$ ¤ËÂФ¹¤ëºÇŤÎÀ¸À®µ¬Â§¤òõ¤¹¡£ +¤·¤«¤·¡¢¤â¤·¤½¤Î¤è¤¦¤ÊÀ¸À®µ¬Â§¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð¡¢ +¼¡¤Î $s_2\,s_3\ldots\,$ ¤ËÂФ·¤ÆºÇŤÎÀ¸À®µ¬Â§¤ò¼¡¡¹¤Ëõ¤·¤Æ¤æ¤¯¡£ +¤½¤·¤Æ¡¢¤½¤ì¤â¼ºÇÔ¤·¤¿¤é $s_3\,s_4\ldots\,$, etc. ¤È¤¤¤¦¶ñ¹ç¤Ë¥Þ¥Ã¥Á¥ó¥°¤ò»î¹Ô¤¹¤ë¡£ + +À¸À®µ¬Â§¤Ï¡¢¤¢¤é¤«¤¸¤áÍ¿¤¨¤é¤ì¤¿¥«¥Æ¥´¥ê¡¼¥³¡¼¥É¤Î¥Ñ¥¿¡¼¥ó¤ò»ý¤Ä»þ¤ËŬÍѤµ¤ì¤ë¡£ +Î㤨¤Ð¡¢¤¢¤ëÀ¸À®µ¬Â§¤¬ +$$\hbox{\tt open [ math semi <"\BS\BS,"-opt-5> ] --> +open math}$$ +¤Ç¤¢¤ì¤Ð¡¢¤½¤ì¤Ï¡¢ +¤½¤ì¤¾¤ì{\tt open}¡¢ {\tt math}¡¢ {\tt semi}¤È¤¤¤¦¥«¥Æ¥´¥ê¡¼¤ò»ý¤Ä3¤Ä¤Î +Ϣ³¤·¤¿¥¹¥¯¥é¥Ã¥×¤Ï¡¢ + {\tt open} ¤È {\tt math}¤È¤¤¤¦¥«¥Æ¥´¥ê¡¼¤ò»ý¤Ä +2¤Ä¤Î¥¹¥¯¥é¥Ã¥×¤ËÊÑ´¹¤µ¤ì¤ë¤³¤È¤ò°ÕÌ£¤¹¤ë¡£ +{\tt open}¥¹¥¯¥é¥Ã¥×¤ÏÊÑ´¹¤µ¤ì¤Ê¤¤¡£°ìÊý¡¢ +ʸ»úÎó {\tt <"\BS\BS,"-opt-5>} ¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¤Î¤Ç¡¢ +¿·¤·¤¤ {\tt math} ¥¹¥¯¥é¥Ã¥×¤Ï +¸µ¤Î{\tt math}¤Îtranslation\index{translation}¡¢ +{\tt semi} ¤Îtranslation\index{translation}¡¢ + `{\tt \BS,}'¡¢ `{\tt opt}'¡¢ `{\tt5}' +¤È¤¤¤¦°ìÏ¢¤Î¤â¤Î¤Ç¹½À®¤µ¤ë¤³¤È¤Ë¤Ê¤ë( + \TeX\ ¥Õ¥¡¥¤¥ë¤Ë¤ª¤¤¤Æ¡¢¤³¤ì¤ÏÄɲäµ¤¤¥¹¥Ú¡¼¥¹¤¬¥»¥ß¥³¥í¥ó¤Î¸å¤Ë +ÉÕ¤¡¢ +penalty 50 ¤Î optional line break ¤¬Â³¤¯¤³¤È¤ò°ÕÌ£¤¹¤ë)¡£ +translation\index{translation} ¤Ï ³Ñ³ç¸Ì ({\tt <>}) ¤Ç³ç¤é¤ì¤Æ¤ª¤ê¡¢ +°úÍÑÉä({\tt "})¤Ç³ç¤é¤ì¤¿Ê¸»úÎó( +C ¤Î´Ä¶¤Ç¤Ï¥Ð¥Ã¥¯¥¹¥é¥Ã¥·¥å({\tt \BS}) ¤Ç¥¨¥¹¥±¡¼¥×¤µ¤ì¤¿Ê¸»ú¤Ç¤âÎɤ¤)¡¢ +ÆÃÊ̤ʥ¡¼¥ï¡¼¥É¤ò´Þ¤à¤³¤È¤¬¤Ç¤¤ë¡£ + +Ìò¤ËΩ¤ÄÀ¸À®µ¬Â§¤ÎÎã¤ò¼¨¤¹Á°¤Ë¡¢ +{Spider}¤Î¹½Ê¸¤ÎÂçÉôʬ¤ò´Þ¤à¥µ¥Ö¥»¥Ã¥È¤Î¾ÜºÙ¤òÀâÌÀ¤·¤è¤¦¡£ + + + +\section{{\tt spider} ¥Õ¥¡¥¤¥ë¤Î¹½Ê¸} + +{Spider} ¤Ï¡¢{\tt WEAVE} ¤È {\tt TANGLE}¤Î¤¿¤á¤Ë +¸À¸ì¤Îµ½Ò¤òC¤Î¥³¡¼¥É¤ËÊÑ´¹¤¹¤ë Awk ¥×¥í¥°¥é¥à¤Ç¤¢¤ë¡£ +{Spider}¤¬ Awk ¥×¥í¥°¥é¥à¤Ê¤Î¤Ç¡¢ÆþÎϤϹԤΥ·¡¼¥±¥ó¥¹¤Ç¤¢¤ê¡¢ +Á´¤Æ¤Î {Spider} ¥³¥Þ¥ó¥É¤¬1¹Ô¤Ë¼ý¤Þ¤é¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ + +\paragraph{¥³¥á¥ó¥È¤È¶õÇò¹Ô} +{\jem Ǥ°Õ¤Î} ʸ»úÎó¤¬¥×¥í¥°¥é¥ß¥ó¥°¸À¸ì¤Î¥È¡¼¥¯¥ó¤Ë¤Ê¤êÆÀ¤ë¤Î¤Ç¡¢ +ÆÃÄê¤Îʸ»úʤӤò ``¥³¥á¥ó¥È¤Î³«»Ïµ¹æ''¤È¤·¤Æ·è¤á¤Æ¤ª¤¯¤³¤È¤¬¤Ç¤¤Ê¤¤¡£ +½¾¤Ã¤Æ¡¢ {Spider} ¤Ë¤Ï¥³¥á¥ó¥È¤Ï¤Ê¤¯¡¢ {\jem ¥³¥á¥ó¥È¹Ô}¤Î¤ß¤¬¤¢¤ë¡£ +¥³¥á¥ó¥È¹Ô¤Ï¡¢ºÇ½é¤¬ ``{\tt \#}'' ¤Ç»Ï¤Þ¤Ã¤Æ¤¤¤ë¹Ô¤Ç¤¢¤ë¡£ +{Spider}½èÍý·Ï¤Ï¥³¥á¥ó¥È¹Ô¤È¶õÇò¹Ô¤ò̵»ë¤¹¤ë¡£ + +\paragraph{¥Õ¥£¡¼¥ë¥É} +{\tt spider} ¤Î³Æ¥³¥Þ¥ó¥É¤Ï¡¢{\jem ¥Õ¥£¡¼¥ë¥É}¤ÎʤӤ«¤é¤Ê¤ë¡£ +¤³¤ì¤Ï¡¢Awk ¤Î¥Õ¥£¡¼¥ë¥É¤ÈƱ°ì¤Ç¡¢¥Û¥ï¥¤¥È¥¹¥Ú¡¼¥¹\index{white space} +¤Ç¶èÀÚ¤é¤ì¤Æ¤¤¤ë¡£ +¤³¤Î Awk ¤«¤é·Ñ¾µ¤·¤¿À¼Á¤Î¤æ¤¨¤Ë¡¢{Spider}¤Ï¥Õ¥£¡¼¥ë¥ÉÃæ¤Ë +¥Û¥ï¥¤¥È¥¹¥Ú¡¼¥¹¤Ï»ÈÍѤǤ¤Ê¤¤¡£ + + +\subsection{ËÝÌõ} +%Most fields in a {Spider} file are simple identifiers, or perhaps +%strings of non-alphanumeric characters. +{Spider}¥Õ¥¡¥¤¥ë¤ÎÂçÉôʬ¤Î¥Õ¥£¡¼¥ë¥É¤Ï¡¢Ã±½ã¤Ê¼±ÊÌ»Ò\index{identifier}¤«¡¢ +¤¿¤Ö¤óÈó±Ñ¿ô»úʸ»ú\index{non-alphanumeric character}¤Ç¤¢¤ë¡£ +%The major exception is {\jem translations}. +ºÇÂç¤ÎÎã³°¤Ï¡¢{\jem ËÝÌõ}\index{translations}¤Ç¤¢¤ë¡£ +%Translations are always surrounded by angle brackets ({\tt <>}), +ËÝÌõ¤Ï¾ï¤Ë³Ñ¥«¥Ã¥³\index{angle bracket} ({\tt <>}) ¤Ç°Ï¤Þ¤ì¤Æ¤ª¤ê¡¢ +%and consist of a (possibly empty) list of translation pieces. +(¶õ¤Ç¤âÎɤ¤)ËÝÌõÍ×ÁÇ\index{translation pieces}¤Î¥ê¥¹¥È¤Ç¤¢¤ë¡£ +%The pieces on a list are separated by dashes ({\tt -}). +¥ê¥¹¥ÈÃæ¤Î³ÆÍ×ÁǤϡ¢¥À¥Ã¥·¥å({\tt -})¤Ç¶èÀÚ¤é¤ì¤ë¡£ +ËÝÌõÍ×ÁǤϡ¢²¼µ¤Î°ì¤Ä¤Ç¤¢¤ë¡£ +\begin{itemize} +\item °úÍÑÉä¤Ç°Ï¤Þ¤ì¤¿Ê¸»úÎó. +¤³¤Îʸ»úÎó¤Ï¡¢``\verb+\+'' ¤Ç¥¨¥¹¥±¡¼¥×¤µ¤ì¤¿Ê¸»ú¤òµö¤¹¤¬¡¢ +¥Û¥ï¥¤¥È¥¹¥Ú¡¼¥¹¤È¥À¥Ã¥·¥å¤ò´Þ¤ó¤Ç¤Ï¤Ê¤é¤Ê¤¤¡£ +\item ``self'' ¥Þ¡¼¥«¡¼, ``{\tt *}'', + ¤Ï¡¢ËÝÌõ¤µ¤ì¤è¤¦¤È¤·¤Æ¤¤¤ë¥È¡¼¥¯¥ó¤Îʸ»úÎó¤ò»²¾È¤¹¤ë¡£ +%refers to the sequence of characters making up the token being translated. +%The self marker is permitted only in certain contexts, and its precise +%meaning depends on the context. +¥»¥ë¥Õ¥Þ¡¼¥«¤Ï³ÎÄꤷ¤Æ¤¤¤ëʸ̮¤ÎÃæ¤Ç¤Î¤ßµö¤µ¤ì¤Æ¤ª¤ê¡¢¤½¤Î°ÕÌ£¤¹¤ë¤È¤³¤í¤Ï +ʸ̮¤Ë°Í¸¤·¤Æ¤¤¤ë¡£ +\item ¿ô»ú +\item ¥¡¼¥ï¡¼¥É: +{Spider} ¤Î¥¡¼¥ï¡¼¥É¤Ï¡¢°Ê²¼¤ÎÄ̤ê¤Ç¤¢¤ë¡£ +\begin{description} +\item [\tt space] 1¤Ä¤Î¶õÇòʸ»ú ({\tt "\ "})¤ò°ÕÌ£¤¹¤ë. +\item[\tt dash] 1¤Ä¤Î¥À¥Ã¥·¥å ({\tt "-"})¤ò°ÕÌ£¤¹¤ë. +\end{description} +¤½¤Î¾¤Î¥¡¼¥ï¡¼¥É¤Ï{\tt WEAVE}¤ËÅϤµ¤ì¤ë¡£ + +{\tt WEAVE} ¤Ï¡¢°Ê²¼¤Î¥¡¼¥ï¡¼¥É¤òǧ¼±¤¹¤ë: +\begin{description} +\item[\tt break\_space] optional line break ¤Þ¤¿¤Ï ¶õÇò; +\item[\tt force] line break; +\item[\tt big\_force] ¿âľ¥¹¥Ú¡¼¥¹¤ò»ý¤Ä line break; +\item[\tt opt] optional line break ( °Ê¹ß¤Î¹Ô¤ÏÄ̾ï¤Î³«»Ï°ÌÃÖ¤è¤ê +2em ¥¤¥ó¥Ç¥ó¥È¤µ¤ì¤ë)--- +¤³¤Î¥³¡¼¥É¤Ï¡¢À°¿ô$n$ ¤òȼ¤¤¡¢break ¤Ï¥Ú¥Ê¥ë¥Æ¥£ $10n$ ¤È¤·¤Æ°·¤ï¤ì¤ë¡£ +%code is followed by an integer $n$, and the break will occur with penalty +%$10n$; +\item[\tt backup] 1em ¤Î backspace; +\item[\tt cancel] Àè¹Ô¤·¤Æ¤¤¤¿\ ¤Þ¤¿¤Ï³¤¯¤¹¤Ù¤Æ¤Î {\tt break\_space}, + {\tt force},{\tt big\_force} ¤ò¼è¤ê¾Ã¤¹¡£¤µ¤é¤Ë¡¢ +³¤¯ {\tt backup} ¥È¡¼¥¯¥ó¤â¥¥ã¥ó¥»¥ë¤¹¤ë; +\item[\tt indent] °Ê¹ß¤Î¹Ô¤ò 1em ¥¤¥ó¥Ç¥ó¥È¤¹¤ë +\item[\tt outdent] °Ê¹ß¤Î¹Ô¤ò -1em ¥¤¥ó¥Ç¥ó¥È¤¹¤ë +\item[\tt math\_rel] \verb+\mathrel{+ ¤ËÊÑ´¹¤µ¤ì¤ë +\item[\tt math\_bin] \verb+\mathbin{+ ¤ËÊÑ´¹¤µ¤ì¤ë +\item[\tt math\_op] \verb+\mathop{+ ¤ËÊÑ´¹¤µ¤ì¤ë +\end{description} +¿ô¼°¥â¡¼¥É¤Ç¤âÀµ¤·¤¯½èÍý¤µ¤ì¤ë {\jem Í£°ì} ¤Î¥¡¼¥ï¡¼¥É¤Ï¡¢{\tt +indent} ¤È {\tt outdent}¤À¤±¤Ç¤¢¤ë¡£ +¤â¤·¡¢Â¾¤Î¥¡¼¥ï¡¼¥É¤ò´Þ¤àËÝÌõ¤òÄêµÁ¤·¤¿¤¤»þ¤Ï¡¢ +¤½¤Î¥È¡¼¥¯¥ó¤Ë¤Ï{\tt mathness~no} ¤ò»È¤ï¤Í¤Ð¤Ê¤é¤Ê¤¤¡£ +%You may use any recognized key words in the translations of a +%production; there the mathness is automatically taken care of for you. +À¸À®µ¬Â§¤ÎËÝÌõ¤ÎÃæ¤Ç¤Ï¡¢¤É¤ó¤Ê¥¡¼¥ï¡¼¥É¤ò»È¤Ã¤Æ¤â¹½¤ï¤Ê¤¤¡£ +¤½¤ì¤é¤Î¿ô¼°À¤Ï¼«Æ°Åª¤Ë½èÍý¤µ¤ì¤ë¡£ +\end{itemize} + +°Ê²¼¤Ï¡¢ËÝÌõ\index{translation}¤ÎÎã¤Ç¤¢¤ë¡£: +\begin{verbatim} +<"\\"-space> +<indent-force> +<"{\\let\\\\=\\bf"-space> +<"}"-indent-"{}"-space> +\end{verbatim} + +\paragraph{À©¸Â¤µ¤ì¤¿ËÝÌõ}\index{Restricted translations} +¤¤¤¯¤Ä¤«¤Î¾ì¹ç¤Ï¡¢Î㤨¤Ð¡¢{\tt tangleto} µ½Ò¤Ê¤É¤Ç¤Ï¡¢ +ËÝÌõ\index{translations}¤ÏÀ©¸Â¤µ¤ì¤ë¡£ +À©¸Â¤µ¤ì¤¿ËÝÌõ\index{restricted translation} ¤Ï¡¢¥¿¥¤¥×¥»¥Ã¥Æ¥£¥ó¥°¥³¡¼¥É¤Ë +ÊÑ´¹¤µ¤ì¤ë¤³¤È¤Ï¤Ê¤¯ ¾ï¤Ë ASCII ʸ»úÎó¤È¤Ê¤ë¡£ +%is never converted to typesetting code, +%but is always converted to an ASCII string, +%usually for output by {\tt +%TANGLE}, but sometimes for other things. +¤¿¤¤¤Æ¤¤¤Ï{\tt TANGLE} ¤Î½ÐÎÏÍѤ˻Ȥï¤ì¤ë¤¬¡¢Ê̤ÎÍÑÅӤǤâ»È¤¦¡£ +À©¸Â¤µ¤ì¤¿ËÝÌõ\index{restricted translation}¤Ï¡¢ +{\jem °úÍÑÉä¤Ç³ç¤é¤ì¤¿Ê¸»úÎó} ¤ª¤è¤Ó¡¢ +{\tt space} ¤È{\tt dash} ¤Î2¤Ä¤Î¥¡¼¥ï¡¼¥É¤Î¤ß¤¬µö¤µ¤ì¤ë¡£ + + +\subsection{{\tt token} ¥³¥Þ¥ó¥É} +{\tt token} ¥³¥Þ¥ó¥É¤Î¹½Ê¸¤Ï¡¢¼¡¤ÎÄ̤ê¤Ç¤¢¤ë: +\begin{quote} +\tt +\syntax{command} \produces~token \syntax{token-designator} +\syntax{token-descriptions} +\end{quote} +¤³¤³¤Ç \syntax{token-descriptions} ¤Ï (¶õ¤Ç¤âÎɤ¤) ¥È¡¼¥¯¥óµ½Ò¤Î¥ê¥¹¥È¤Ç¤¢¤ë¡£ + +\paragraph{¥È¡¼¥¯¥óµ½Ò} +¥È¡¼¥¯¥óµ½Ò¤Ï +\begin{itemize}\parindent=0pt +\item +{\tt tangleto \syntax{restricted translation}} + +\syntax{restricted translation} ¤Ï {\tt TANGLE}¤Ë +¤³¤Î¥È¡¼¥¯¥ó¤ò¥×¥í¥°¥é¥à¥Æ¥¥¹¥È¤Ë½ñ¤½Ð¤¹¤â¤Î¤òµ¬Äꤹ¤ë¡£ +À©¸Â¤µ¤ì¤¿ËÝÌõ\index{restricted translation}¤Ç͸ú¤Ê¤â¤Î¤Ï¡¢ +{\jem °úÍÑÉä¤Ç³ç¤é¤ì¤¿Ê¸»úÎó} ¤ª¤è¤Ó¡¢ +{\tt space} ¤È{\tt dash} ¤Î2¤Ä¤Î¥¡¼¥ï¡¼¥É¤Î¤ß¤Ç¤¢¤ë¡£ +¤â¤· {\tt tangleto} µ½Ò¤¬¤Ê¤±¤ì¤Ð¡¢ {\tt TANGLE} ¤Ï +¥È¡¼¥¯¥ó¤ò¹½À®¤·¤¿Ê¸»úÎó¤ò½ñ¤½Ð¤¹¡£ + +\item +{\tt translation \syntax{translation}} + +%Tells {\tt WEAVE} what translation to assign when making this token into +%a scrap. +{\tt WEAVE} ¤¬¥È¡¼¥¯¥ó¤ò¥¹¥¯¥é¥Ã¥×¤ÎÃæ¤ËÃÖ¤¯»þ¤Ë¤É¤¦ËÝÌõ¤¹¤ë¤«¤ò»Ø¼¨¤¹¤ë¡£ +%The self +%marker~({\tt*}) stands for the sequence of characters that were read in to +%make up the token. +¥»¥ë¥Õ¥Þ¡¼¥«¡¼~({\tt*}) ¤Ï¡¢¥È¡¼¥¯¥ó¤ò¹½À®¤·¤Æ¤¤¤ëʸ»úÎ󤽤Τâ¤Î¤ò¼¨¤¹¡£ +ËÝÌõ¤Ï¤·¤Ð¤·¤Ð \verb+translation <*>+ ¤¬¥Ç¥Õ¥©¥ë¥È¤È¤Ê¤ë; {Spider} +¤Ï¤³¤ì¤ò¤¢¤é¤«¤¸¤á¥Ç¥Õ¥©¥ë¥È¤È¤·¤ÆÁȤ߹þ¤ó¤Ç¤¢¤ë¡£ + +\item +{\tt category \syntax{category-name}} + +%Tells {\tt WEAVE} what category to assign when making this token into +%a scrap. +{\tt WEAVE} ¤¬¤³¤Î¥È¡¼¥¯¥ó¤ò¥¹¥¯¥é¥Ã¥×¤Ë¤¤¤ì¤ë¤È¤¤Ë»È¤¦¥«¥Æ¥´¥ê¡¼¤ò»ØÄꤹ¤ë¡£ +{Spider} ¥Õ¥¡¥¤¥ë¤ò½ñ¤¯»þ¤Ï¹¥¤¤Ê¥«¥Æ¥´¥ê¡¼Ì¾¤ò +»È¤¦¤³¤È¤¬¤Ç¤¤ë¡£ +¼é¤ë¤Ù¤¾ò·ï¤Ï¡¢{Spider} ¤¬ÃΤäƤ¤¤ë¾¤Î̾Á°(ͽÌ󥡼¥ï¡¼¥É¡¢ +ilk¤Î̾Á° ¤Ê¤É)¤È¾×Æͤ·¤Ê¤¤¤è¤¦¤Ë¤¹¤ë¤³¤È¤À¤±¤Ç¤¢¤ë¡£ +%Using category names that are identical to reserved words of the +%target programming language (¤Þ¤¿¤Ï C~¤ÎͽÌó¸ì) is not only +%supported, it is strongly encouraged, for clarity. +%Using category names that are identical to reserved words of the +¥«¥Æ¥´¥ê¡¼Ì¾¤ò +¥¿¡¼¥²¥Ã¥È¸À¸ì¤ÎͽÌó¸ì(¤Þ¤¿¤Ï C~¤ÎͽÌó¸ì)¤ÈƱ°ì¤Ë¤·¤Æ¤ª¤¯¤³¤È¤Ï¡¢ +ÌÀ²÷¤µ¤Î°Ù¤À¤±¤Ç¤Ê¤¯¡¢¶¯¤¤Í×ÀÁ¤Ç¤¢¤ë¡£ +%Also, when we get to the sample grammars later on, you will see some +%other conventions we use for category names. +¸å¤Û¤Éʸˡ¤ÎÎã¤ò¸«¤ë¤³¤È¤Ë¤Ê¤ë¤¬¡¢ +¥«¥Æ¥´¥ê¡¼Ì¾¤ò»È¤¦¤¿¤á¤Î¤¤¤¯¤Ä¤«¤ÎÌó«»ö¤¬¤¢¤ë¡£ + +\item +{\tt mathness \syntax{mathness-indicator}} + +¤³¤³¤Ç¡¢\syntax{mathness-indicator} ¤Ï {\tt yes}¡¢{\tt no}¡¢{\tt +maybe}¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£ +%This indicates to {\tt WEAVE} whether the translation for this token +%needs to be typeset in {\TeX}'s math mode or not, or whether it +%doesn't matter. +¤³¤ì¤Ï {\tt WEAVE} ¤¬¤³¤Î¥È¡¼¥¯¥ó¤ò°õºþ¤¹¤ë¤¿¤á¤Î translation ¤È¤·¤Æ +{\TeX}¤Î¿ô¼°¥â¡¼¥É¤ò»È¤¦¤«Èݤ«¡¢¤Þ¤¿¤Ïµ¤¤Ë¤¹¤ëɬÍפ¬¤Ê¤¤¤«¤ò»Ø¼¨¤¹¤ë¡£ +¤³¤ÎÀ¸À®µ¬Â§¤¬Å¬ÍѤµ¤ì¤¿¤È¤¡¢ +{\tt WEAVE} ¤Ï¿ô¼°¥·¥Õ¥Èʸ»ú~(\verb+$+) ¤ò{\TeX}¥Æ¥¥¹¥ÈÃæ¤Ë¤ª¤¯¤³¤È¤Ç +Àµ¤·¤¤¥â¡¼¥É¤Ë¥È¡¼¥¯¥ó¤¬ÃÖ¤«¤ì¤ë¤³¤È¤òÊݾڤ·¤è¤¦¤È¤¹¤ë¡£ +%Tokens with the {\jem empty translation} (\verb+<>+) should always have +%{\tt mathness maybe}, lest they cause {\tt WEAVE} to place two +%consecutive math shift characters. +{\jem ¶õ¤Î translation} (\verb+<>+) ¤ò»ý¤Ä¥È¡¼¥¯¥ó¤Ï¾ï¤Ë +{\tt mathness maybe}¤Ç¤¢¤ë¤È¤ß¤Ê¤µ¤ì¡¢¤½¤Î·ë²Ì¤È¤·¤Æ {\tt WEAVE}¤¬ +2¤Ä¤Î¿ô¼°¥·¥Õ¥Èʸ»ú¤òÃÖ¤¯¤³¤È¤¬¤Ç¤¤ë¤è¤¦¤Ë°·¤ï¤ì¤ë¡£ + +\item +{\tt name \syntax{token-name}} + +¤³¤ì¤Ï¡¢{Spider} ¤Þ¤¿¤Ï {\WEB}¤Î¥Ç¥Ð¥Ã¥°¤Î»þ¤Î¤ß¤Ë»È¤ï¤ì¤ë¡£ +%It causes the specified name to be attached to the token, +¤³¤ì¤Ë¤è¤Ã¤Æ¡¢¥È¡¼¥¯¥ó¤Ï»ØÄꤵ¤ì¤¿Ì¾Á°¤¬ÉÕÍ¿¤µ¤ì¡¢ +%so that a programmer can search for that name in the C~code generated by +%{Spider}. +¥×¥í¥°¥é¥Þ¡¼¤Ï{Spider}¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤¿C~¥³¡¼¥É¤ÎÃ椫¤é¤³¤Î̾Á°¤ò +¸¡º÷¤¹¤ë¤³¤È¤¬²Äǽ¤Ë¤Ê¤ë¡£ + +\end{itemize} + +%\paragraph{Token designators} +\paragraph{¥È¡¼¥¯¥ó̾} +{Spider} ¤Ï°Ê²¼¤Î ¥È¡¼¥¯¥ó̾¤òǧ¼±¤¹¤ë: +\begin{description} +\item[{\tt ¼±ÊÌ»Ò(identifier)}] +¤³¤ì¤ò»È¤¦ {\tt token} ¥³¥Þ¥ó¥É¤Ï +{\tt WEAVE} ¤È {\tt TANGLE} ¤Ë¼±Ê̻ҥȡ¼¥¯¥ó¤ËÂФ¹¤ë½èÍý¤ò»Ø¼¨¤¹¤ë¡£ +»ÄÇ°¤Ê¤¬¤é¡¢{Spider} ¤Ë²¿¤ò¼±Ê̻ҤȤ¹¤Ù¤¤«¤ò»ØÄꤹ¤ë¤³¤È¤Ï¤Ç¤¤Ê¤¤¡£ +¼±Ê̻ҤÎÄêµÁ¤Ï{\tt WEAVE} ¤È {\tt TANGLE}¤ÎÆâÉô¤ËÁȤ߹þ¤Þ¤ì¤Æ¤¤¤ë¡£ +¼±Ê̻Ҥϰʲ¼¤ÎÀµµ¬É½¸½¼°¤Ë¹çÃפ¹¤ëºÇŤÎʸ»úÎó¤Ç¤¢¤ë% +\footnote{ÆɼԤ¬ Unix ¤ÎÀµµ¬É½¸½¤ËÆëÀ÷¤ß¤¬¤Ê¤¤¤Î¤Ç¤¢¤ì¤Ð¡¢ +{\it ed(1)} ¤Î¥Þ¥Ë¥å¥¢¥ë¥Ú¡¼¥¸¤ò»²¹Í¤Ë¤·¤ÆÍߤ·¤¤¡£}: +\begin{verbatim} +[a-zA-Z_][a-zA-Z0-9_]* +\end{verbatim} + +\item[{\tt ¿ôÃÍ(number)}] +{Spider} ¤È {\tt WEAVE}¤Î¸½¾õ¤Î¼Â¸½¤Î»ÅÊý¤Ç¤Ï¡¢ +{\tt token} ¥³¥Þ¥ó¥É¤Ï¿ôÃÍÄê¿ô¤Èʸ»úÎóÄê¿ô¤ÎξÊý¤ò¥«¥Ð¡¼¤¹¤ë¡£ +¼±Ê̻ҤÈƱÍͤˡ¢¿ôÃÍÄê¿ô¤Èʸ»úÄê¿ô¤¬²¿¤Ç¹½À®¤µ¤ì¤ë¤«¤È¤¤¤¦ÄêµÁ¤Ï +Êѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤¤Ê¤¤¡£ +{\samepage +¿ôÃÍÄê¿ô¤Ï°Ê²¼¤Î¤è¤¦¤ÊºÇĹ¹çÃפǤ¢¤ë% +\footnote{¸À¸ì¤¬»ý¤ÄÉâÆ°¾®¿ôÅÀɽµ¤ò¥µ¥Ý¡¼¥È¤¹¤ë¤¿¤á¤Î +{\WEB} ¥³¥ó¥È¥í¡¼¥ë¥·¡¼¥±¥ó¥¹¤¬¤¢¤Ã¤ÆÅöÁ³¤Ç¤¢¤ë¡£}: +\begin{verbatim} +[0-9]+(\.[0-9]*)? +\end{verbatim} +} +ʸ»úÎóÄê¿ô¤Ï°Ê²¼¤Î¤è¤¦¤ÊºÇĹ¹çÃפǤ¢¤ë +\begin{verbatim} +\"([^"]*\\\")*[^"]*\"|'[^@\]'|'\\.'|'@@' +\end{verbatim} +¥Ð¥Ã¥¯¥¹¥é¥Ã¥·¥å~(\verb+\+)¤Ç¥¨¥¹¥±¡¼¥×¤µ¤ì¤¿²þ¹Ô¤Ïʸ»úÎóÄê¿ô¤Ë +´Þ¤à¤³¤È¤¬¤Ç¤¤ë¡£ + +\item[{\tt newline}] +¤³¤ì¤ò»È¤¦{\tt token} ¥³¥Þ¥ó¥É¤Ï {\tt WEAVE} ¤È {\tt +TANGLE} ¤Ë²þ¹Ô¤Î°·¤¤Êý¤ò»Ø¼¨¤¹¤ë¡£ +¸å¤Û¤É¡¢{\tt WEAVE} ¤Ë²þ¹Ô¤ò̵»ë¤µ¤»¤ëÊýË¡¤ò¼¨¤¹¡£ + +\item[{\tt pseudo\_semi}] +¤³¤ì¤ò»È¤¦{\tt token} ¥³¥Þ¥ó¥É¤Ï¡¢ +{\tt WEAVE} ¤¬ +{\tt @;}¤È¤¤¤¦{\WEB} ¥³¥ó¥È¥í¡¼¥ë¥·¡¼¥±¥ó¥¹¤Ç½èÍý¤¹¤ë¤³¤È¤ò»ØÄꤹ¤ë¡£ +¤³¤Î¥³¥ó¥È¥í¡¼¥ë¥·¡¼¥±¥ó¥¹¤Ï{\tt TANGLE}¤Ç¤Ï¾ï¤Ë̵»ë¤µ¤ì¤ë¡£ + +\item[\syntax{characters}] +¤³¤³¤Ç¡¢characters ¤ÏÈó±Ñ¿ô»ú¤Ç¤¢¤ë¡£ +¤³¤ì¤ò»È¤¦ {\tt token} ¥³¥Þ¥ó¥É¤Ï¡¢ +ʸ»úÎó¤ò¥È¡¼¥¯¥ó¤È¤·¤ÆÄêµÁ¤·¡¢ +{\tt WEAVE} ¤È {\tt TANGLE} ¤¬¤³¤Î¥È¡¼¥¯¥ó¤ËÂФ·¤Æ¹Ô¤Ê¤¦½èÍý¤ò»Ø¼¨¤¹¤ë¡£ +¥È¡¼¥¯¥ó¤Ï¾¤Î¥È¡¼¥¯¥ó¤ÎÀÜƬ¼¤Ç¤¢¤Ã¤Æ¤âÎɤ¤; {\tt WEAVE} ¤È {\tt TANGLE} +¤ÏºÇŤΤâ¤Î¤òºÎÍѤ¹¤ë¡£ +¤½¤¦¤¤¤¦¤ï¤±¤Ç¡¢ C~{\WEB}¤Ç¤Ï¡¢ \verb+==+ ¤Ïñ°ì¤Î\ \verb+==+ ¥È¡¼¥¯¥ó +¤È¤·¤ÆÆɤ߹þ¤Þ¤ì¡¢ +Æó¤Ä¤Î \verb+=+ ¥È¡¼¥¯¥ó¤È¤µ¤ì¤ë¤³¤È¤Ï¤Ê¤¤¡£ +\end{description} + + + + +\subsection{ͽÌó¸ì¥È¡¼¥¯¥ó} +%Reserved words are attached to a particular {\jem ilk} using the {\tt +%reserved} command. +ͽÌó¸ì¤Ï{\tt reserved} ¥³¥Þ¥ó¥É¤ÇÆÃÄê¤Î {\jem ilk} ¤È·ë¤ÓÉÕ¤±¤é¤ì¤ë¡£ +\begin{quote} +\tt reserved \syntax{reserved-word} $[$ilk \syntax{ilk-name}$]$ +\end{quote} +%If you're writing a {Spider} file, you may choose any ilk +%names you like, subject only to the restriction that they not conflict +%with other names known to {Spider} (e.g.~predefined key words, +%names of categories, and so on). +{Spider} ¥Õ¥¡¥¤¥ë¤ò½ñ¤¯»þ¤Ï¹¥¤¤Ê¥«¥Æ¥´¥ê¡¼Ì¾¤ò +»È¤¦¤³¤È¤¬¤Ç¤¤ë¡£ +¼é¤ë¤Ù¤¾ò·ï¤Ï¡¢{Spider} ¤¬ÃΤäƤ¤¤ë¾¤Î̾Á°(ͽÌ󥡼¥ï¡¼¥É¡¢ +ilk¤Î̾Á°¡¢ ¤Ê¤É)¤È¾×Æͤ·¤Ê¤¤¤è¤¦¤Ë¤¹¤ë¤³¤È¤À¤±¤Ç¤¢¤ë¡£ +%The convention, however, is to use ilk {\tt with\_like} for a reserved +%word {\tt with}, and so on.% +¤·¤«¤·¤Ê¤¬¤é¡¢Ìó«»ö¤È¤·¤ÆÎ㤨¤Ð{\tt with}¤È¤¤¤¦Í½Ìó¸ì¤Ë¤Ï{\tt with\_like} +¤È¤¤¤¦ ilk ¤¬»È¤ï¤ì¤ë% +\footnote{% +¤³¤ÎÌó«»ö¤Î¤»¤¤¤Ç¡¢É®¼Ô¤Ïͳ²¤Êµ¡Ç½¤ò{Spider}¤Ë²Ã¤¨¤ë¤È¤¤¤¦Í¶ÏÇ¤Ë +É餱¤Æ¤·¤Þ¤Ã¤¿ --- ¤â¤· {\tt reserved}¡¡¥³¥Þ¥ó¥É¤Ç ilk ¤ò¾Êά¤·¤Æ¤·¤Þ¤Ã¤¿¤é¡¢ +%{Spider} will make an ilk name by appending {\tt \_like} +%to the name of the reserved word. +{Spider}¤ÏͽÌó¸ì¤Î̾Á°¤Î¸å¤í¤Ë{\tt \_like}¤òÉղä·¤¿ ilk ̾¤òºî¤í¤¦¤È¤¹¤ë¡£ +%Furthermore, if that ilk doesn't already exist, {Spider} will +%construct one. +¤µ¤é¤Ë¡¢¤½¤Î¤è¤¦¤Ê ilk ¤¬¤Þ¤À¸ºß¤·¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢ +{Spider}¤Ï¤½¤ì¤òºî¤Ã¤Æ¤·¤Þ¤¦¡£ +¤³¤Îµ¡Ç½¤ò»È¤Ã¤Æ¤Ï¤¤¤±¤Ê¤¤¡£ +}¡£ + +{\tt ilk}¥³¥Þ¥ó¥É¤È {\tt token} ¥³¥Þ¥ó¥É¤ÏÈó¾ï¤Ë»÷¤¿¹½Ê¸¤ò»ý¤Ä¡£ +{\tt ilk} ¥³¥Þ¥ó¥É¤Î¹½Ê¸¤Ï¡¢°Ê²¼¤ÎÄ̤ê: +\begin{quote}\tt +\syntax{command} \produces~ilk \syntax{ilk-name} +\syntax{token-descriptions} +\end{quote} +%In translations that appear in {\tt ilk} commands, the self +%marker~({\tt *}) designates the string of characters making up the +%reserved word, surrounded by \verb+\&{...}+, which makes the reserved +%words appear in bold face. +{\tt ilk}¥³¥Þ¥ó¥ÉÃæ¤Ë¸½¤ì¤ë translation ¤Ë¤ª¤¤¤Æ¡¢ +¥»¥ë¥Õ¥Þ¡¼¥«¡¼~({\tt *})¤ÏͽÌó¸ì¼«¿È¤ò¹½À®¤¹¤ëʸ»úÎó\ ¤ò°ÕÌ£¤·¡¢ +\verb+\&{...}+ ¤Ç°Ï¤Þ¤ì¤Æ +ͽÌó¸ì¤ò°ÕÌ£¤¹¤ë¥Ü¡¼¥ë¥ÉÂΤǰõºþ¤µ¤ì¤ë¡£ + + + + + + + + +\section{À°·Á°õºþʸˡ¤Î¹½Ê¸} +%Defining the tokens of a language is somewhat tedious, but it is +%essentially straightforward, and the definition usually does not need +%fine tuning. +¸À¸ì¤Î¥È¡¼¥¯¥ó¤òÄêµÁ¤¹¤ë¤³¤È¤Ï¡¢¤¤¤µ¤µ¤«Âà¶þ¤Ê¤â¤Î¤Ç¤¢¤ë¡£ +¤·¤«¤·¡¢´ðËÜŪ¤Ë¤ÏľÀÜŪ¤Ë¤Ç¤¡¢ +ÉáÄ̤ÏÄêµÁ¼«ÂΤ˥Á¥å¡¼¥Ë¥ó¥°¤ò¤¹¤ëɬÍפϤʤ¤¡£ +%When developing a new {\WEB} with {Spider}, you will spend most of +%your time writing the grammar that tells {\tt WEAVE} how to reduce +%scraps. +{Spider} ¤Ë¤è¤Ã¤Æ¿·¤·¤¤ {\WEB} ¤ò³«È¯¤¹¤ë¤È¤¤Ë¤Ï¡¢ +¤Û¤È¤ó¤É¤Î»þ´Ö¤ò {\tt WEAVE} ¤¬¥¹¥¯¥é¥Ã¥×¤ò´Ô¸µ¤¹¤ë¤¿¤á¤Îʸˡ¤ò½ñ¤¯¤³¤È¤Ë +Èñ¤ä¤¹¤³¤È¤Ë¤Ê¤ë¤À¤í¤¦¡£ +%The grammar is defined as a sequence of context-sensitive productions. +ʸˡ¤Ï¡¢Ê¸Ì®¤Ë°Í¸¤¹¤ëÀ¸À®µ¬Â§¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£ +%Each production has the form: +³Æ¡¹¤ÎÀ¸À®µ¬Â§¤Ï¼¡¤Î¤è¤¦¤Ê·Á¼°¤ò»ý¤Ä: +\begin{quote} +\tt +\syntax{left context} [ \syntax{firing instructions} ] \syntax{right context} +\\\null\qquad +--> \syntax{left context} \syntax{target category} \syntax{right context} +\end{quote} +%where the left and right contexts are (possibly empty) sequences of +%scrap designators, +¤³¤³¤Ç¡¢ left context ¤È right context ¤Ï(¶õ¤Ç¤âÎɤ¤) +¥¹¥¯¥é¥Ã¥×¥·¡¼¥±¥ó¥¹¤ò¼¨¤·¡¢ +%the firing instructions are a sequence of scrap +%designators and translations (containing at least one scrap +%designator), +firing instructions ¤Ï¡¢ +¥¹¥¯¥é¥Ã¥×̾¾Î¤È(¾¯¤Ê¤¯¤È¤â°ì¤Ä¤Î¥¹¥¯¥é¥Ã¥×¤ò»ØÄꤷ¤Æ¤¤¤ë) +¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤Î¥·¡¼¥±¥ó¥¹¤Ç¤¢¤ê¡¢¤½¤·¤Æ +%and the target category is a category designator. +target category ¤Ï¥«¥Æ¥´¥ê¡¼Ì¾¾Î¤Ç¤¢¤ë¡£ +%If the left and right contexts are both empty, the square brackets +%({\tt []}) can be omitted, and the production is context free. +¤â¤·¡¢ left context ¤È right context ¤Î¤¤¤º¤ì¤â¶õ¤Ç¤¢¤ì¤Ð¡¢ +³Ñ³ç¸Ì({\tt []}) ¤Ï¾Êά²Äǽ¤Ç¤¢¤ê¡¢À¸À®µ¬Â§¤Ïʸ̮¤Ë°Í¸¤·¤Ê¤¤¤â¤Î¤È¤Ê¤ë¡£ +%The left and right contexts must be the same on both sides of the {\tt +%-->}. +left context ¤È right context ¤Ï {\tt -->} ¤ÎξÊÕ¤ÇƱ°ì¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ + +%What does the production mean? +À¸À®µ¬Â§¤Î°ÕÌ£¤¹¤ë¤â¤Î¤Ï²¿¤À¤í¤¦¤« ? +%Well, {\tt WEAVE} is trying to reduce a sequence of scraps. +¤½¤¦¡¢{\tt WEAVE} ¤Ï¥¹¥¯¥é¥Ã¥×¤Î¥·¡¼¥±¥ó¥¹¤ò´Ô¸µ¤·¤è¤¦¤È¤¹¤ë¡£ +%So what {\tt WEAVE} does is look at the sequence, to find out whether +%the left hand side of some production matches an initial subsequence +%of the scraps. +¤·¤¿¤¬¤Ã¤Æ¡¢{\tt WEAVE} ¤Ï¥·¡¼¥±¥ó¥¹¤òÄ´¤Ù¡¢¤É¤ÎÀ¸À®µ¬Â§¤Îº¸ÊÕ¤¬ +ºÇ½é¤Ë¥¹¥¯¥é¥Ã¥×¤ÎÉôʬ¥·¡¼¥±¥ó¥¹¤Ë¹çÃפ¹¤ë¤«¤ò¸«¤Ä¤±¤è¤¦¤È¤¹¤ë¡£ +%{\tt WEAVE} picks the first matching production, and {\jem fires} it, +%reducing the scraps described in the firing instructions to a single +%scrap, and it gives the new scrap the {\jem target category}. +{\tt WEAVE} ¤ÏºÇ½é¤Ë¹çÃפ·¤¿À¸À®µ¬Â§¤ò¼è¤ê¾å¤²¡¢¤½¤ì¤ò {\jem ŬÍѤ·}¡¢ +{firing instructions} ¤Ëµ½Ò¤µ¤ì¤Æ¤¤¤¿¥¹¥¯¥é¥Ã¥×¤ò°ì¤Ä¤Î¥¹¥¯¥é¥Ã¥×¤Ë´Ô¸µ¤·¡¢ +¿·¤·¤¤¥¹¥¯¥é¥Ã¥×¤ò{\jem target category} ¤È¤¹¤ë¡£ +%The translation of the new scrap is formed by concatenating the +%translations in the {\jem firing instructions}, where a scrap +%designator stands for the translation of the designated scrap. +¿·¤·¤¤¥¹¥¯¥é¥Ã¥×¤Î¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤Ï{\jem fireing instructions} ¤Î +¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤È·ë¹ç¤¹¤ë¤³¤È¤Ë¤è¤Ã¤ÆÀ°·Á¤µ¤ì¤ë¡£ +¤³¤³¤Ç¡¢¥¹¥¯¥é¥Ã¥×̾¾Î¤Ï¡¢»ØÄꤵ¤ì¤¿¥¹¥¯¥é¥Ã¥×¤Î +¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤Î¤³¤È¤Ç¤¢¤ë¡£ + +%Here is the syntax that describes contexts, firing instructions, scrap +%designators, and so on. +°Ê²¼¤Ï¡¢Ê¸Ì®¡¢Ì¿Îá¤Îµ¯Æ°¡¢¥¹¥¯¥é¥Ã¥×¤Î»ØÄê¤Ê¤É¤òµ½Ò¤·¤¿¤â¤Î¤Ç¤¢¤ë¡£ +\begin{quote} +\tt +\syntax{left context} \produces~\syntax{scrap designators}\\ +\syntax{right context} \produces~\syntax{scrap designators}\\ +\syntax{firing instruction} \produces \syntax{scrap designator}\\ +\syntax{firing instruction} \produces \syntax{translation}\\ +\syntax{scrap designator} \produces~?\\ +\syntax{scrap designator} \produces~\opt{!}\syntax{category name}\opt{*}\\ +\syntax{scrap designator} + \produces~\opt{!}\syntax{category alternatives}\opt{*}\\ +\syntax{category alternatives} + \produces~\rlap{(\syntax{optional alternatives}\syntax{category name})}\\ +\syntax{optional alternative} \produces~\syntax{category name}|\\ +\syntax{target category} \produces~\#\syntax{integer}\\ +\syntax{target category} \produces~\syntax{category name}\\ +\end{quote} + + +%\paragraph{Matching the left hand side of a production} +\paragraph{À¸À®µ¬Â§¤Îº¸ÊդιçÃ×} +%When does a sequence of scraps match the left hand side of a +%production? +À¸À®µ¬Â§¤Îº¸ÊÕ¤¬¥¹¥¯¥é¥Ã¥×¤ÎʤӤȹçÃפ¹¤ë»þ¤È¤Ï¤¤¤Ä¤À¤í¤¦¤« ? +%For matching purposes, we can ignore the translations and the square +%brackets~({\tt []}), and look at the left hand side just as a sequence +%of scrap designators. +¹çÃפµ¤»¤ë¤È¤¤¤¦ÌÜŪ¤«¤é¤¤¤¨¤Ð¡¢¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤È³Ñ³ç¸Ì~({\tt []})¤Ï +̵»ë¤·¤Æ¡¢º¸ÊÕ¤ò¤¢¤¿¤«¤â¥¹¥¯¥é¥Ã¥×̾¾Î¤ÎʤӤ«¤é¤À¤±¤Ê¤ë¤â¤Î¤È¤ß¤Ê¤¹ +¤³¤È¤¬¤Ç¤¤ë¡£ +%A sequence of scraps matches a sequence of scrap designators if and +%only if each scrap on the sequence matches the corresponding scrap +%designator. +¤½¤ÎʤӤÎÃæ¤ÎÂбþ¤¹¤ë¤¹¤Ù¤Æ¤Î¥¹¥¯¥é¥Ã¥×¤Î̾¾Î¤¬°ìÃפ·¤¿¤È¤¤Ë¤Î¤ß +¥¹¥¯¥é¥Ã¥×¤ÎʤӤ¬¥¹¥¯¥é¥Ã¥×̾¾Î¤ÎʤӤ˰ìÃפ·¤¿¤È¸«¤Ê¤»¤ë¡£ +%Here are the rules for matching scrap designators (we can +%ignore starring% +¤³¤³¤Ç¡¢¥¹¥¯¥é¥Ã¥×̾¾Î¤Î°ìÃפΤ¿¤á¤Îµ¬Â§¤Ï°Ê²¼¤ÎÄ̤ê(¥¹¥¿¡¼¤Ï̵»ë¤·¤ÆÎɤ¤ +\footnote{¥ª¥×¥·¥ç¥ó¤Î {\tt *}¤òȼ¤¦¥«¥Æ¥´¥ê¡¼Ì¾¤Ï¡¢ +{\jem ¥¹¥¿¡¼ÉÕ¤(starred)}¤È¸Æ¤Ð¤ì¤ë¡£}% +): +\begin{itemize} +\item +%Every scrap matches the designator {\tt ?}. +¤¹¤Ù¤Æ¤Î¥¹¥¯¥é¥Ã¥×¤Ï {\tt ?}¤Ë°ìÃפ¹¤ë¡£ +\item +%A scrap matches \syntax{marked category} if and only if its category +%is the same as the category of the designator. +¤½¤Î¥¹¥¯¥é¥Ã¥×¤Î¥«¥Æ¥´¥ê¡¼¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¥¹¥¯¥é¥Ã¥×̾¤È°ìÃפ·¤¿¤È¤¤Ë¸Â¤ê¡¢ +¤½¤Î¥¹¥¯¥é¥Ã¥×¤Ï \syntax{marked category} ¤È°ìÃפ¹¤ë¡£ +\item +%A scrap matches {\tt!}\syntax{marked category} if and only if its category +%is {\jem not} the same as the category of the designator. +¥¹¥¯¥é¥Ã¥×¤Î¥«¥Æ¥´¥ê¡¼¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¥«¥Æ¥´¥ê¡¼Ì¾¤È°ìÃפ·¤Æ{\jem ¤¤¤Ê¤«¤Ã¤¿} +»þ¤Ë¤Î¤ß¡¢¤½¤Î¥¹¥¯¥é¥Ã¥×¤Ï {\tt!}\syntax{marked category} ¤È°ìÃפ¹¤ë +({\tt !} ¤ÏÈÝÄê¤ò°ÕÌ£¤¹¤ë)¡£ +\item +%A scrap matches a list of category alternatives if and only if its +%category is on the list of alternatives. +¥¹¥¯¥é¥Ã¥×¤Î¥«¥Æ¥´¥ê¡¼¤¬ÁªÂò¥ê¥¹¥È¤ÎÃæ¤Ë¤¢¤Ã¤¿¾ì¹ç¤Î¤ß¡¢ +¤½¤Î¥¹¥¯¥é¥Ã¥×¤Ï¥«¥Æ¥´¥ê¡¼¤ÎÁªÂò¥ê¥¹¥È¤Ë°ìÃפ¹¤ë¡£ +\item +%A scrap matches a {\jem negated} list of category alternatives if and +%only if its category is {\jem not} on the list of alternatives. +¥¹¥¯¥é¥Ã¥×¤Î¥«¥Æ¥´¥ê¡¼¤¬ÁªÂò¥ê¥¹¥È¤ÎÃæ¤Ë{\jem ̵¤«¤Ã¤¿}¾ì¹ç¤Ë¤Î¤ß¡¢ +¤½¤Î¥¹¥¯¥é¥Ã¥×¤Ï{\jem ÈÝÄꤵ¤ì¤¿}ÁªÂò¥ê¥¹¥È¤Ë°ìÃפ¹¤ë¡£ +\end{itemize} + + +%\paragraph{Firing a production} +\paragraph{À¸À®µ¬Â§¤ÎŬÍÑ} +%Once a match is found, {\tt WEAVE} fires the production by replacing +%the subsequence of scraps matching the firing instructions. +¤¤¤Ã¤¿¤ó¹çÃפ¹¤ë¤â¤Î¤¬¸«¤Ä¤«¤Ã¤¿¤é¡¢{\tt WEAVE} ¤ÏÀ¸À®µ¬Â§¤òŬÍѤ·¡¢ +ŬÍѤ·¤¿Ì¿Îá¤Ë°ìÃפ·¤¿¥¹¥¯¥é¥Ã¥×¤Î¥µ¥Ö¥·¡¼¥±¥ó¥¹¤òÃÖ¤´¹¤¨¤Æ¤æ¤¯¡£ +%{\tt WEAVE} replaces this subsequence with a new scrap whose category +%is the target category, and whose translation is the concatenation of +%all the translations in the firing instructions. +{\tt WEAVE}¤Ï¤³¤Î¥µ¥Ö¥·¡¼¥±¥ó¥¹¤òÌÜŪ¤Î¥«¥Æ¥´¥ê¡¼¤ò»ý¤Ä¿·¤·¤¤¥¹¥¯¥é¥Ã¥×¤Ç +ÃÖ¤´¹¤¨¡¢¤½¤Î¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤ÏŬÍѤµ¤ì¤¿µ¬Â§¤ÎÃæ¤Î +¤¹¤Ù¤Æ¤Î¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤ò¹ç¤ï¤»¤¿¤â¤Î¤È¤¹¤ë +%(When the new translation is constructed, the +%translations of the old scraps are included at the positions of the +%corresponding scrap designators.) +(¿·¤·¤¤¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤¬ºîÀ®¤µ¤ì¤ë¤È¤¤Ï¡¢ +¸Å¤¤¥¹¥¯¥é¥Ã¥×¤Î¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤Ï¥¹¥¯¥é¥Ã¥×¤ÎÂбþ¤¹¤ë¾ì½ê¤Ë¼è¤ê¹þ¤Þ¤ì¤ë +)¡£ +%If the target category is not given by name, but rather by +%number~({\tt \#$n$}), {\tt WEAVE} will take the category of the $n$th +%scrap in the subsequence that matches the left hand side of the +%production, and make that the target category. +¤â¤·ÌÜŪ¤Î¥«¥Æ¥´¥ê¡¼¤¬Ì¾Á°¤Ç¤Ï¤Ê¤¯ {\tt \#$n$}¤È¤¤¤¦ÈÖ¹æ¤Ç»ØÄꤵ¤ì¤Æ¤¤¤¿¤é¡¢ +{\tt WEAVE} ¤ÏÀ¸À®µ¬Â§¤Îº¸ÊÕ¤ÎÂбþ¤¹¤ë $n$ÈÖÌܤΥ«¥Æ¥´¥ê¡¼¤ò¼è¤ê¾å¤²¡¢ +¤½¤ì¤òÌÜŪ¤Î¥«¥Æ¥´¥ê¡¼¤È¤ß¤Ê¤¹¡£ + +\subparagraph{À¸À®µ¬Â§Å¬ÍѤÎÉûºîÍÑ} +À¸À®µ¬Â§¤¬Å¬ÍѤµ¤ì¤ë¤È¡¢ {\tt WEAVE} ¤Ï +%for the first identifier in any {\jem starred} scrap. +¥¹¥¿¡¼¥É¡¦¥¹¥¯¥é¥Ã¥×¤ÎºÇ½é¤Î¼±Ê̻Ҥò \hbox{\jem ²¼ÀþÉդθ«½Ð¤·¸ì}¤È¤¹¤ë¡£ + + +%\paragraph{If no initial subsequence matches any production} +\paragraph{ºÇ½é¤Î¥µ¥Ö¥·¡¼¥±¥ó¥¹¤¬À¸À®µ¬Â§¤Ë¹çÃפ·¤Ê¤«¤Ã¤¿¾ì¹ç} +%If the initial subsequence of scraps does not match the left hand side +%of any production, {\tt WEAVE} will try to match the subsequence +%beginning with the second scrap, and so on, until a match is found. +%Once a match is found, {\tt WEAVE} fires the production, changing its +%sequence of scraps. +%It then starts all over again at the beginning of the new sequence, +%looking for a match.% +½é´ü¥µ¥Ö¥·¡¼¥±¥ó¥¹¤¬º¸ÊÕ¤ÎÀ¸À®µ¬Â§¤È¹çÃפ·¤Ê¤±¤ì¤Ð¡¢ +{\tt WEAVE}¤Ï¼¡¤Î¥µ¥Ö¥·¡¼¥±¥ó¥¹°Ê¹ß¤Ç¹çÃפ¹¤ë¤â¤Î¤ò¸«¤Ä¤±¤è¤¦¤È¤¹¤ë¡£ +¹çÃפ¹¤ë¤â¤Î¤¬¸«¤Ä¤«¤ì¤Ð¡¢ {\tt WEAVE}¤ÏÀ¸À®µ¬Â§¤òŬÍѤ·¡¢ +³Æ¥¹¥¯¥é¥Ã¥×¤ÎʤӤòÊѹ¹¤¹¤ë¡£ +¤½¤·¤Æ¡¢¿·¤·¤¤¥·¡¼¥±¥ó¥¹¤ËÂФ·¤ÆºÇ½é¤«¤é¤â¤¦°ìÅÙ¤ä¤êľ¤¹% +\footnote{ +%The implementation is better than that; {Spider} figures out just +%how much {\tt WEAVE} must backtrack to get the same effect as +%returning to the beginning.% +¤³¤Î¼Â¸½ÊýË¡¤Ï¡¢ +¡ÖºÇ½é¤ËÌá¤ë¤ÈƱ¤¸¸ú²Ì¤òÆÀ¤ë¤¿¤á¤Ë¤Ï +{\tt WEAVE}¤¬²¿²ó¥Ð¥Ã¥¯¥È¥é¥Ã¥¯¤ò¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤«¤ò +{Spider}¤¬ »»½Ð¤¹¤ë¡× +¤È¤¤¤¦¤â¤Î¤è¤ê¤âÎɤ¤¡£ +}¡£ +%If {\jem no} subsequence of the scraps matches any production, then the +%sequence of scraps is irreducible, and {\tt WEAVE} writes out the +%translations of the scraps, one at a time. +¤¹¤Ù¤Æ¤Î¥µ¥Ö¥·¡¼¥±¥ó¥¹¤¬¤¤¤º¤ì¤ÎÀ¸À®µ¬Â§¤È¤â¹çÃפ·¤Ê¤«¤Ã¤¿¤Ê¤é¤Ð¡¢ +¥¹¥¯¥é¥Ã¥×¤Î¥·¡¼¥±¥ó¥¹¤Ï¸µ¤ËÌᤵ¤ì¤ë¤³¤È¤Ê¤¯ {\tt WEAVE} ¤Ï +°ì¤Ä¤º¤Ä¥¹¥¯¥é¥Ã¥×¤ÎËÝÌõ¤ò½ñ¤½Ð¤¹¡£ + + + + + +\section{{\tt WEAVE} ʸˡ¤ÎÎã} +%This all must seem very intimidating, but it's not really. +%In this section we present some grammar fragments and explain what's +%going on. +¤³¤³¤Þ¤Ç¤Î¤¹¤Ù¤Æ¤Î¤³¤È¤Ï¶¼¤·¤Î¤è¤¦¤Ë´¶¤¸¤¿¤«¤âÃΤì¤Ê¤¤¤¬¡¢Á´¤¯¤½¤ó¤Ê¤³¤È¤Ï¤Ê¤¤¡£ +¤³¤Î¾Ï¤Ç¤Ï¤¤¤¯¤Ä¤«¤Îʸˡ¤ò¼¨¤·¡¢²¿¤¬¤Ê¤µ¤ì¤ë¤«¤ò²òÀ⤹¤ë¡£ + +\paragraph{´Êñ¤ÊÎã} +\begin{verbatim} +? ignore_scrap --> #1 +\end{verbatim} +%This production should appear in every grammar, because Spidery {\tt +%WEAVE} expects category \verb+ignore_scrap+ to exist with roughly this +%semantics. +¤³¤ÎÀ¸À®µ¬Â§¤Ï¤¹¤Ù¤Æ¤Îʸˡ¤Ë¸ºß¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ +¤Ê¤¼¤Ê¤é¡¢Spidery {\tt WEAVE} ¤Ï +\verb+ignore_scrap+ ¤È¤¤¤¦¥«¥Æ¥´¥ê¡¼¤¬Íð˽¤Ë¤â¤³¤Î°ÕÌ£¤Ç¸ºß¤·¤Æ¤¤¤ë¤È +¤ß¤Ê¤·¤Æ¤¤¤ë¤¿¤á¤Ç¤¢¤ë +(Î㤨¤Ð¡¢¥³¥á¥ó¥È¤ÏÁ´¤Æ {\tt ignore\_scrap} ¤È¤¤¤¦¥«¥Æ¥´¥ê¡¼¤Î +¥¹¥¯¥é¥Ã¥×¤òÀ¸À®¤¹¤ë) ¡£ +%Any scrap of category \verb+ignore_scrap+ essentially doesn't affect +%the reduction of scraps: it is absorbed into the scrap to its left. +\verb+ignore_scrap+ ¤È¤¤¤¦¥«¥Æ¥´¥ê¡¼¤Î¤¤¤«¤Ê¤ë¥¹¥¯¥é¥Ã¥×¤â +´ðËÜŪ¤Ë¤Ï¥¹¥¯¥é¥Ã¥×¤Î´Ô¸µ¤Î±Æ¶Á¤ò¼õ¤±¤Ê¤¤: +¤½¤Î¤Þ¤Þ¥¹¥¯¥é¥Ã¥×¤ÎÃæ¤ËÃÖ¤«¤ì¤¿¤Þ¤Þ¤Ë¤Ê¤ë¡£ + +\begin{verbatim} +token newline category newline translation <> +newline --> ignore_scrap +\end{verbatim} +%This token definition and production, combined with the previous +%production, causes {\tt WEAVE} to ignore all newlines. +¤³¤ÎÄêµÁ¤ÈÀ¸À®µ¬Â§¤Ï¡¢Á°½Ò¤ÎÀ¸À®µ¬Â§¤ÈÁȤ߹ç¤ï¤µ¤ì¤Æ +¤¹¤Ù¤Æ¤Î newline ¤ò{\tt WEAVE}¤Ë̵»ë¤µ¤»¤ë¤³¤È¤Ë¤Ê¤ë¡£ + +%For this next example, from the C~grammar, you will need to know that +%{\tt math} represents a mathematical expression, {\tt semi} a +%semicolon, and {\tt stmt} a statement or sequence of statements. +¼¡¤Î C¤Îʸˡ¤ÎÎã¤Ç¤Ï¡¢{\tt math} ¤Ï»»½Ñ¼°¡¢ +{\tt semi}¤Ï¥»¥ß¥³¥í¥ó¡¢{\tt stmt}¤Ïʸ¤Þ¤¿¤Ïʸ¤ÎʤӤò°ÕÌ£¤·¤Æ¤¤¤ë¤³¤È¤ò +ÃǤäƤª¤³¤¦¡£ +\begin{verbatim} +math semi --> stmt +stmt <force> stmt --> stmt +\end{verbatim} +%The first production says that a mathematical expression, followed by +%a semicolon, should be treated as a statement. +Âè°ì¤ÎÀ¸À®µ¬Â§¤Ï¥»¥ß¥³¥í¥ó¤òȼ¤¦»»½Ñ¼°¤Ïʸ¤È¤·¤Æ°·¤ï¤ì¤ë¤³¤È¤ò»Ø¼¨¤¹¤ë¡£ +%The second says that two statements can be combined to make a single +%statement by putting a line break between them. +ÂèÆó¤ÎÀ¸À®µ¬Â§¤Ç¤Ï¡¢ 2 ¤Ä¤Îʸ¤Ï 1 ¤Ä¤Îʸ¤È¤·¤Æ·ë¹ç¤µ¤ì¡¢ +´Ö¤Ë²þ¹Ô¤¬ÃÖ¤«¤ì¤ë¤³¤È¤ò»Ø¼¨¤¹¤ë¡£ + +\paragraph{¼°} +%This more extended example shows the treatment of expressions in Awk. +¤³¤Î³ÈÄ¥¤µ¤ì¤¿Îã¤Ï¡¢ Awk ¤Î¼°¤Î°·¤¤¤ò¼¨¤·¤Æ¤¤¤ë¡£ +%This is identical to the treatment of expressions in C and in several +%other languages. +¤³¤ì¤Ï¡¢C ¤ä¤¤¤¯¤Ä¤«¤Î¸À¸ì¤Ë¤ª¤±¤ë¼°¤Î°·¤¤¤ÈƱ°ì¤Ç¤¢¤ë¡£ +%We will use the following categories: +°Ê²¼¤Î¤è¤¦¤Ê¥«¥Æ¥´¥ê¡¼¤ò»È¤¦¤³¤È¤Ë¤¹¤ë: +\begin{description} +\item[math] »»½Ñ¼° %A mathematical expression +\item[binop] Æó¹àÃæÃֱ黻»Ò %A binary infix operator +\item[unop] ñ¹àÁ°Ãֱ黻»Ò¤Þ¤¿¤Ïñ¹à¸åÃֱ黻»Ò + %A unary prefix or postfix operator +\item[unorbinop] Æó¹àÃæÃÖ¤«Ã±¹àÁ°Ã֤ˤʤꤦ¤ë±é»»»Ò + %An operator that could be binary infix or unary prefix +\end{description} +%To show you how these might be used, here are some sample token +%definitions using these categories: +¤É¤¦¤ä¤Ã¤Æ»È¤ï¤ì¤ë¤«¤ò¼¨¤¹¤¿¤á¤Ë¡¢¤³¤ì¤é¤Î¥«¥Æ¥´¥ê¡¼¤òÍѤ¤¤¿ +¥È¡¼¥¯¥ó¤ÎÄêµÁÎã¤ò¼¨¤¹¡£ +\begin{verbatim} +token + category unorbinop +token - category unorbinop +token * category binop +token / category binop +token < category binop +token > category binop +token , category binop translation <",\\,"-opt-3> +token = category binop translation <"\\K"> +token != translation <"\\I"> category binop +token == name eq_eq translation <"\\S"> category binop +token ++ name gt_gt category unop translation <"\\uparrow"> +token -- name lt_lt category unop translation <"\\downarrow"> +\end{verbatim} +%Notice that the translation for the comma specifies a thin space and +%an optional line break after the comma. +¤³¤³¤Ç¤Ï¥«¥ó¥Þ¤Ï¾®¤µ¤Ê¥¹¥Ú¡¼¥¹¤Î¸å optional line break +¤òÃÖ¤¯¤³¤È¤ËÃí°Õ¤·¤ÆÍߤ·¤¤¡£ +{\tt =}¡¢ {\tt !=}¡¢ {\tt ==} ¤ÎËÝÌõ¤Ï¤½¤ì¤¾¤ì +\ $\leftarrow$¡¢ $\ne$¡¢ $\equiv$ ¤È¤Ê¤ë¡£ + + +%Here is the grammar for expressions. +°Ê²¼¤Ï¡¢¼°¤Î¤¿¤á¤Îʸˡ¤Ç¤¢¤ë¡£ +\begin{verbatim} +math (binop|unorbinop) math --> math +(unop|unorbinop) math --> math +math unop --> math +math <"\\"-space> math --> math +\end{verbatim} +%In Awk there is no concatenation operator; concatenation is by +%juxtaposition. +Awk ¤Ç¤Ï¡¢Ê¸»úÎó¤Î·ë¹ç»Ò¤¬¤Ê¤¤; ·ë¹ç¤Ïʤ٤ÆÃÖ¤¯¤³¤È¤Çɽµ¤µ¤ì¤ë¡£ +%The last production tells {\tt WEAVE} to insert a space between two +%juxtaposed expressions. +ºÇ¸å¤ÎÀ¸À®µ¬Â§¤Ï {\tt WEAVE} ¤ËÊÂÃÖ¤µ¤ì¤¿¼°¤Î´Ö¤Ë +¥¹¥Ú¡¼¥¹¤òÁÞÆþ¤µ¤»¤ë¤¿¤á¤Î¤â¤Î¤Ç¤¢¤ë¡£ + +%So far we haven't dealt with parentheses, but that's easily done: +º£¤Þ¤Ç¤Ï³ç¸Ì¤ò½èÍý¤·¤Æ¤¤¤Ê¤«¤Ã¤¿¤¬¡¢°Ê²¼¤Î¤è¤¦¤ËÍưפ˵½Ò¤Ç¤¤ë: +\begin{verbatim} +token ( category open +token ) category close +token [ category open +token ] category close +open math close --> math +\end{verbatim} + + +%Now this grammar just given doesn't handle the Awk or C {\tt +=} +%feature very well; {\tt x+=1} comes out as~$x+\leftarrow 1$, and {\tt +%x/=2} is irreducible! +¤µ¤Æ¡¢¤³¤Îʸˡ¤Î¤Þ¤Þ¤Ç¤Ï Awk ¤ä C ¤Î {\tt +=} ¤È¤¤¤¦µ¡Ç½¤ò +¤¦¤Þ¤¯°·¤¦¤³¤È¤¬¤Ç¤¤Ê¤¤; +{\tt x+=1} ¤Ï $x+\leftarrow 1$ ¤Î¤è¤¦¤Ë¤Ê¤ê¡¢{\tt x/=2} ¤Ï +´Ô¸µ¤¹¤ë¤³¤È¤¬¤Ç¤¤Ê¤¤¡£ +%Here's the cure; first, we make a new category for assignment: +°Ê²¼¤Ë½¤Àµ¤Î»ÅÊý¤ò½Ò¤Ù¤ë; +¤Þ¤ººÇ½é¤Ë¡¢ÂåÆþ¤Î¤¿¤á¿·¤·¤¤¥«¥Æ¥´¥ê¡¼¤òºî¤ë¤³¤È¤Ë¤¹¤ë¡£ +\begin{verbatim} +token = category equals translation <"\\K"> +\end{verbatim} +%And then we write productions that reduces assignment (possibly +%preceded by another operator) to a binary operator: +¼¡¤Ë¡¢(¾¤Î±é»»»Ò¤¬Àè¹Ô¤·¤Æ¤â¤«¤Þ¤ï¤Ê¤¤)ÂåÆþ¤òÆó¹à±é»»»Ò¤Ë´Ô¸µ¤¹¤ë¤¿¤á¤Î +À¸À®µ¬Â§¤ò½ñ¤³¤¦¡£ +\begin{verbatim} +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +\end{verbatim} +%Notice that, given the rules stated above, the second production can +%fire only if {\tt equals} is {\jem not} preceded by an operator. +¾åµ¤Îµ¬Â§¤ÇÃí°Õ¤¹¤Ù¤¤³¤È¤Ï¡¢ÂèÆó¤ÎÀ¸À®µ¬Â§¤Ï +{\tt equals}¤¬±é»»»Ò¤òÁ°¤Ë{\jem ȼ¤ï¤Ê¤¤}»þ¤Ë¤Î¤ßŬÍѲÄǽ¤À¤È¤¤¤¦¤³¤È¤Ç¤¢¤ë¡£ +%On input~{\tt x+=1}, the first production fires, and we have the +%translation~$x\buildrel+\over{\leftarrow} 1$. +{\tt x+=1}¤È¤¤¤¦ÆþÎϤËÂФ·¤Æ¡¢Âè°ì¤ÎÀ¸À®µ¬Â§¤¬ºÇ½é¤ËŬÍѤµ¤ì¡¢ +$x\buildrel+\over{\leftarrow} 1$ ¤È¤¤¤¦ËÝÌõ¤òÆÀ¤ë¤³¤È¤Ë¤Ê¤ë¡£ + +\paragraph{¾ò·ïʸ} +%Here is the grammar for (possibly nested) conditional statements in +%Awk. +°Ê²¼¤Ï¡¢Awk ¤Ë¤ª¤±¤ë(¥Í¥¹¥È²Äǽ¤Ê)¾ò·ïʸ¤Îʸˡ¤Ç¤¢¤ë¡£ +\begin{verbatim} +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> close else <"\\"-space> if --> if +ifbrace <outdent-force> close else lbrace --> ifbrace +ifbrace <outdent-force> close else newline --> ifline +ifbrace <outdent-force> close --> stmt +(ifline|ifmath) <indent-force> stmt <outdent> --> stmt +\end{verbatim} +%It relies on the following token definitions: +°Ê²¼¤Î¥È¡¼¥¯¥ó¤ÎÄêµÁ¤Ë°Í¸¤¹¤ë: +\begin{verbatim} +ilk if_like category if +reserved if +ilk else_like category else +reserved else +token { translation <"\\;\\{"-indent> category lbrace +token } translation <"\\}\\"-space> category close +token newline category newline translation <> +\end{verbatim} + +\paragraph{C ¤Î¥×¥ê¥×¥í¥»¥Ã¥µÍÑÌ¿Îá¤Î°·¤¤} +¤³¤³¤Ç¤ÏC¥×¥ê¥×¥í¥»¥Ã¥µÍÑÌ¿Îá¤ò°·¤¦¤¿¤á¤Îʸˡ¤Î +´Êñ¤Ê¥Ð¡¼¥¸¥ç¥ó¤ò¼¨¤¹¡£ +¥×¥ê¥×¥í¥»¥Ã¥µÌ¿Îá¤Ï¹Ô¤Îº¸Ã¼¤Ë¤ª¤«¤ì¡¢¥Ð¥Ã¥¯¥¹¥é¥Ã¥·¥å¤Ç¥¨¥¹¥±¡¼¥×¤µ¤ì¤¿ +²þ¹Ô¤âÀµ¤·¤¯°·¤ï¤ì¤ë¡£ +(ºÇ½ª¥Ð¡¼¥¸¥ç¥ó¤Ï¥Õ¥¡¥¤¥ë̾¤ò {\tt <...>}¤È¤¤¤¦ +``¤è¤ê¾®¤µ¤¤'' ¤È ``¤è¤êÂ礤¤'' ¤ò°ÕÌ£¤¹¤ëƱ°ì¤Îµ¹æ¤Ç³ç¤Ã¤¿É½µ¤â +²Äǽ¤Ç¤¢¤ë¡£) + +{\small\advance\hsize 1in +\begin{verbatim} +# control sequence \8 puts things on the left margin +<"\\8"> sharp <"{\\let\\\\=\\bf"-space> math <"}"-indent-"{}"-space> --> preproc +preproc backslash <force-"\\8\\hskip1em"-space> newline --> preproc +<force> preproc <force-outdent> newline --> ignore_scrap +preproc math --> preproc +newline --> ignore_scrap +\end{verbatim} +} +ºÇ½é¤ÎÀ¸À®µ¬Â§¤Ë¤¢¤ë \verb+\let+ ¤Ë¤è¤Ã¤Æ¡¢ +{\tt \#} ¤Ë³¤¯¼±Ê̻Ҥò¥Ü¡¼¥ë¥ÉÂΤËÊѹ¹¤¹¤ë¡£ + + +%\subsection{Using context-dependent productions} +\subsection{ʸ̮°Í¸À¸À®µ¬Â§¤Î»ÈÍÑ} +%So far we've been able to do a lot without using the +%context-dependent features of {Spider} productions. +%(For example, the entire {\tt spider} file for Awk is written using +%only context-free productions.) +%Now we'll show some examples that use the context-dependence. +º£¤Þ¤Ç¤Î¤Ï¡¢Â¿¤¯¤Î¤³¤È¤òʸ̮¤Ë°Í¸¤·¤Ê¤¤ÊýË¡¤Ç¤ä¤Ã¤Æ¤³¤ì¤¿ +(Î㤨¤Ð¡¢Awk ÍѤΠ{\tt spider}¥Õ¥¡¥¤¥ë¤Ïʸ̮¼«Í³µ¬Â§¤Î¤ß¤Ç½ñ¤«¤ì¤Æ¤¤¤ë)¡£ +º£¤«¤é¡¢Ê¸Ì®°Í¸ʸˡ¤ò»È¤Ã¤¿Îã¤ò¼¨¤¹¤³¤È¤Ë¤¹¤ë¡£ + +%In the grammar for Ada, a semicolon is used as a terminator for +%statements. +%But semicolons are also used as {\jem separators} in parameter +%declarations. +%The first two productions here find the statements, but the third +%production supersedes them when a semicolon is seen in a parenthesized +%list. +Ada ¤Îʸˡ¤Ç¤Ï¡¢¥»¥ß¥³¥í¥ó¤Ïʸ¤Î½ªÃ¼µ¹æ¤Ç¤¢¤ë¡£ +¤·¤«¤·¡¢¥Ñ¥é¥á¡¼¥¿Àë¸À¤Ç¤Ï {\jem ¥»¥Ñ¥ì¡¼¥¿} ¤È¤·¤Æ¤â»È¤ï¤ì¤ë¡£ +°Ê²¼¤ÎºÇ½é¤Î 2 ¤Ä¤Îµ¬Â§¤Ïʸ¤ò¸«¤Ä¤±¤ë¤¿¤á¤Ë¤¢¤ë¡£ +¤·¤«¤·3ÈÖÌܤϡ¢³ç¸Ì¤Ç³ç¤é¤ì¤¿¥ê¥¹¥È¤ÎÃæ¤Ë¤¢¤ë¥»¥ß¥³¥í¥ó¤Î°·¤¤¤òÊѤ¨¤ë¡£ +\begin{verbatim} +semi --> terminator +math terminator --> stmt +open [ math semi ] --> open math +\end{verbatim} + + +%\paragraph{Underlining the index entry for the name of a declared +%function} +\paragraph{Àë¸À¤µ¤ì¤¿´Ø¿ô̾¤Î²¼ÀþÉÕ¤±¤µ¤ì¤¿º÷°úÅÐÏ¿} +%In SSL, function declarations begin with the type of the function +%being declared, followed by the name of that function. +SSL ¤Ç¤Ï¡¢´Ø¿ô¤ÎÀë¸À¤Ï´Ø¿ô̾¤ÎÁ°¤Ë´Ø¿ô¤Î·¿¤òÀë¸À¤¹¤ë¡£ +%The following production causes the index entry for that function to +%be underlined, so that we can look up the function name in the index +%and easily find the section in which the function is declared: +°Ê²¼¤ÎÀ¸À®µ¬Â§¤Ï¡¢´Ø¿ô¤ò²¼ÀþÉÕ¤¤Çº÷°ú¤ËÅÐÏ¿¤¹¤ë¡£¤·¤¿¤¬¤Ã¤Æ¡¢ +º÷°ú¤ÎÃæ¤Ç´Ø¿ô̾¤òÄ´¤Ù¤ë¤³¤È¤¬¤Ç¤¡¢Àë¸À¤µ¤ì¤Æ¤¤¤ë¥»¥¯¥·¥ç¥ó¤ò +¸«¤Ä¤±¤ë¤³¤È¤¬²Äǽ¤Ç¤¢¤ë¡£ +\begin{verbatim} +decl simp [ simp* ] --> decl simp math +\end{verbatim} +%Where we've relied on +¤³¤³¤Ç¤Ï¡¢°Ê²¼¤ÎÄêµÁ¤Ë°Í¸¤·¤Æ¤¤¤ë¡£ +\begin{verbatim} +token identifier category simp mathness yes +\end{verbatim} + + +\paragraph{¾ò·ï¼°} +%Suppose we want to format conditional expressions (for example in C) +%like this: +(Î㤨¤Ð C ¤Ë¤ª¤¤¤Æ)¼¡¤Î¤è¤¦¤Ë¾ò·ï¼°¤òÀ°·Á¤¹¤ë¤³¤È¤ò¹Í¤¨¤è¤¦¡£ +\begin{quote} +\syntax{condition}\\ +\mbox{\qquad}$?$ \syntax{expression}\\ +\mbox{\qquad}$:$ \syntax{expression} +\end{quote} +%The problem is that it's hard to know when the conditional expression +%ends. +¤³¤³¤Ç¤ÎÌäÂê¤Ï¡¢¤¤¤Ä¾ò·ï¼°¤¬½ª¤ë¤«¤òȽÃǤ¹¤ë¤Î¤¬Æñ¤·¤¤¤³¤È¤Ç¤¢¤ë¡£ +%It's essentially a question of precedence, +¤³¤ì¤Ï¡¢´ðËÜŪ¤ËÀèÆɤßÌäÂê¤Ç¤¢¤ê¡¢ +%and what we're going to do +%is look ahead until we see an operator with sufficiently low +%precedence that it terminates a conditional expression. +¤ä¤ë¤Ù¤¤³¤È¤Ï¡¢¾ò·ï¼°¤ò½ªÃ¼¤µ¤»¤ë¤Ë½½Ê¬¤ÊÄøÅÙ¤Ë +±é»»»Ò¤òÀèÆɤߤ¹¤ë¤³¤È¤Ç¤¢¤ë¡£ +%In SSL a conditional expression can be terminated by a semicolon, a +%right parenthesis, a comma, or a colon. +SSL ¤Ç¤Ï¡¢¾ò·ï¼°¤Ï¥»¥ß¥³¥í¥ó¡¢±¦³ç¸Ì¡¢¥«¥ó¥Þ¡¢¥³¥í¥ó¤Ç½ªÃ¼¤·ÆÀ¤ë¡£ +%We'll use the {\jem right context} to do the lookahead. +ÀèÆɤߤò¤¹¤ë¤¿¤á¤Ë¡¢{\jem right context} ¤ò»È¤¦¤³¤È¤Ë¤·¤è¤¦¡£ +{\small +\begin{verbatim} +token ? translation <"\\?"> category question +token : category colon + +<indent-force> question math <force> colon --> condbegin +[ condbegin math <outdent> ] (semi|close|comma|colon) --> math (semi|close|comma|colon) +\end{verbatim} +} + + + + +\subsection{À°·Á°õºþʸˡ¤Î¥Ç¥Ð¥Ã¥°} +{\tt WEAVE} ¤ÏÀ°·Á°õºþʸˡ¤Î¥Ç¥Ð¥Ã¥°¤ËÌòΩ¤Ä 2 ¤Ä¤Î¥â¡¼¥É¤ò»ý¤Ä¡£ +{\tt @1} ¤È¤¤¤¦À©¸æ¥·¡¼¥±¥ó¥¹¤ÏÉôʬ¥È¥ì¡¼¥¹¤ò³«»Ï¤·¡¢ +{\tt @2} ¤Ï¥Õ¥ë¥È¥ì¡¼¥¹¤ò³«»Ï¤¹¤ë¡£ +{\tt @0} ¤Ï¥È¥ì¡¼¥¹¤ò¥ª¥Õ¤Ë¤¹¤ë¡£%turns tracing back off again. +%In the partial tracing mode, {\tt WEAVE} applies all the productions +%as many times as possible, +Éôʬ¥È¥ì¡¼¥¹¥â¡¼¥É¤Ç¤Ï¡¢{\tt WEAVE} ¤Ï²Äǽ¤Ê¸Â¤ê¤¹¤Ù¤Æ¤ÎÀ¸À®µ¬Â§¤ò +ŬÍѤ·¡¢·ë²Ì¤È¤·¤Æ´Ô¸µ¤Ç¤¤Ê¤«¤Ã¤¿»Ä¤ê¤Î¥¹¥¯¥é¥Ã¥×¤ò¥×¥ê¥ó¥È¥¢¥¦¥È¤¹¤ë¡£ +%and then it prints out the irreducible +%scraps that remain. +%If the scraps reduce to a single scrap, no diagnostics are printed. +¥¹¥¯¥é¥Ã¥×¤¬¤¹¤Ù¤Æ°ì¤Ä¤Î¥¹¥¯¥é¥Ã¥×¤Ë´Ô¸µ¤Ç¤¤¿¾ì¹ç¤Ï¡¢ +¿ÇÃÇ¥á¥Ã¥»¡¼¥¸¤Ï¥×¥ê¥ó¥È¤µ¤ì¤Ê¤¤¡£ + +%When a scrap is printed, {\tt WEAVE} prints a leading +%{\tt+}~or~{\tt-}, the name of the category of that scrap, and a +%trailing {\tt+}~or~{\tt-}. +¥¹¥¯¥é¥Ã¥×¤¬¥×¥ê¥ó¥È¤µ¤ì¤ë¤È¤¡¢{\tt WEAVE} ¤Ï¡¢{\tt+}~¤«~{\tt-}¤Î¥ê¡¼¥À¡¼¡¢ +¤½¤Î¥¹¥¯¥é¥Ã¥×¤Î¥«¥Æ¥´¥ê¡¼Ì¾¡¢{\tt+}~¤«~{\tt-}¤Î¥È¥ì¡¼¥é¡¼¤ò¥×¥ê¥ó¥È¤¹¤ë¡£ +%The {\tt+} indicates that {\TeX} should be in math mode, and the +%{\tt-} that {\TeX} should not be in math mode, at the beginning and +%end of the scrap's translation, respectively. +¤½¤ì¤¾¤ì¤Î¥¹¥¯¥é¥Ã¥×¤Î¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤Î»Ï¤á¤È½ª¤ï¤ê¤Ç¡¢ +{\tt+} ¤Ï {\TeX} ¤¬¿ô¼°¥â¡¼¥É¤ËÆþ¤Ã¤¿¤³¤È¤ò¼¨¤·¡¢ +{\tt-} ¤Ï {\TeX} ¤¬¿ô¼°¥â¡¼¥É¤Ç¤Ê¤¯¤Ê¤Ã¤¿¤³¤È¤ò¼¨¤¹ +%(You can see the translations by looking at the {\tt.tex} file, since +%that's where they're written out.) +(¥È¥é¥ó¥¹¥ì¡¼¥·¥ç¥ó¤Ï{\tt.tex}¥Õ¥¡¥¤¥ë¤ò¸«¤ì¤Ð²ò¤ë)¡£ + +%For beginners, the full trace is more helpful. +½é¿´¼Ô¤Ë¤È¤Ã¤Æ¤Ï¡¢¥Õ¥ë¥È¥ì¡¼¥¹¤ÎÊý¤¬Ìò¤ËΩ¤Ä¡£ +%It prints out the following information every time a production is +%fired: +¥Õ¥ë¥È¥ì¡¼¥¹¥â¡¼¥É¤Ç¤Ï¡¢À¸À®µ¬Â§¤¬Å¬ÍѤµ¤ì¤ëÅ٤˰ʲ¼¤Î¾ðÊó¤ò¥×¥ê¥ó¥È¤¹¤ë: +\begin{itemize} +\item +%The number of the production just fired (from {\tt productions.list}); +ŬÍѤ·¤¿À¸À®µ¬Â§¤Î({\tt productions.list}¤Ë½ñ¤½Ð¤µ¤ì¤¿)ÈÖ¹æ; +\item +%The sequence of scraps {\tt WEAVE} is now trying to reduce; +{\tt WEAVE}¤¬¸½ºß´Ô¸µ¤·¤è¤¦¤È¤·¤Æ¤¤¤ë¥¹¥¯¥é¥Ã¥×¤ÎʤÓ; +\item +%A {\tt*} indicating what subsequence {\tt WEAVE} will try to reduce next. +{\tt*} ¤Ç¼¨¤µ¤ì¤ë {\tt WEAVE} ¤¬¼¡¤Ë´Ô¸µ¤·¤è¤¦¤È¤·¤Æ¤¤¤ë¥µ¥Ö¥·¡¼¥±¥ó¥¹¡£ +\end{itemize} +%A good way to understand how À°·Á°õºþʸˡ work is to take +%a {\tt productions.list} file, and look at a full trace of the +%corresponding {\tt WEAVE}. +À°·Á°õºþʸˡ ¤ÎƯ¤¤òÃΤëÎɤ¤ÊýË¡¤Ï¡¢ +{\tt productions.list} ¥Õ¥¡¥¤¥ë¤ò¼ê¤Ë¤È¤Ã¤Æ¡¢ +{\tt WEAVE} ¤¬¥×¥ê¥ó¤È¤·¤¿¥Õ¥ë¥È¥ì¡¼¥¹¤È +Æͤ¹ç¤ï¤»¤ë¤³¤È¤Ç¤¢¤ë¡£ +%Or, if you prefer, you can simulate by hand the action of {\tt WEAVE} +%on a sequence of scraps. +¤â¤·¤¯¤Ï¡¢¤ªË¾¤ß¤Ê¤é¤Ð¡¢{\tt WEAVE} ¤¬¥¹¥¯¥é¥Ã¥×¤ÎʤӤËÂФ·¤Æ¹Ô¤¦Æ°ºî¤ò¼ê¤Ç +¥·¥ß¥å¥ì¡¼¥È¤·¤Æ¤â¤¤¤¤¤À¤í¤¦¡£ + + +\section{{Spider} ¸À¸ì¤Î»Ä¤ê} +%The tokens and the grammar are not quite the whole story. +%Here's the rest of the truth about what you can do with {Spider}. +¥È¡¼¥¯¥ó¤Èʸˡ¤ÇÏä·¤¬¤¹¤Ù¤Æ½ª¤Ã¤¿¤ï¤±¤Ç¤Ï¤Ê¤¤¡£ +¤³¤Î¾Ï¤Ç¤Ï¡¢ {Spider} ¤Ç¤Ç¤¤ë¤³¤È¤Î̤ÀâÌÀ¤ÎÉôʬ¤ò½Ò¤Ù¤ë¡£ + +\subsection{¥¿¡¼¥²¥Ã¥È¸À¸ì¤Î̿̾} +%When a Spidery {\tt WEAVE} or {\tt TANGLE} starts up, it prints the +%target language for which it was generated, and the date and time of +%the generation. +Spidery {\tt WEAVE} ¤Þ¤¿¤Ï Spidery {\tt TANGLE} ¤¬µ¯Æ°¤µ¤ì¤¿»þ¡¢ +¥¿¡¼¥²¥Ã¥È¸À¸ì¤ÈºîÀ®Æü»þ¤òɽ¼¨¤¹¤ë¡£ +{\tt language} ¥³¥Þ¥ó¥É¤Ï¥¿¡¼¥²¥Ã¥È¤Ë¤¹¤ë¸À¸ì¤ò»ØÄꤹ¤ë¡£ + +¹½Ê¸¤Ï°Ê²¼¤ÎÄ̤ꡣ +\begin{quote} +\tt language \syntax{language-name} +\opt{extension \syntax{extension-name}}\\ +\mbox{\qquad\qquad}\opt{version \syntax{version-name}} +\end{quote} +extension--name ¤Ï¡¢{\tt TANGLE} ¤¬¥×¥í¥°¥é¥à¤ò½ñ¤½Ð¤¹ +³ÈÄ¥»Ò¤È¤·¤Æ({\tt .web}¥Õ¥¡¥¤¥ë¤ËËä¤á¹þ¤à¤¿¤á¤Ë)»È¤ï¤ì¤ë¡£ +extension ¤Ï¡¢{\tt WEAVE} ¤Ç»È¤ï¤ì¤ë ¸À¸ì¤Ë¸ÇͤΠ+{\TeX} ¥Þ¥¯¥í¥Õ¥¡¥¤¥ë¤òÀ¸À®¤¹¤ë»þ¤Ë¤â»È¤ï¤ì¤ë¡£ +¤·¤¿¤¬¤Ã¤Æ¡¢°Û¤Ê¤ë¸À¸ì¤Ï°Û¤Ê¤ë³ÈÄ¥»Ò(extension) ¤ò»ý¤¿¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ +extension ¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤¤»þ¤Ï¡¢¸À¸ì̾¤¬¥Ç¥Õ¥©¥ë¥È¤È¤Ê¤ë¡£ +version ¾ðÊ󤬻ØÄꤵ¤ì¤Æ¤¤¤ì¤Ð¡¢¤½¤ì¤â¥×¥í¥°¥é¥àµ¯Æ°»þ¤Ëɽ¼¨¤µ¤ì¤ë¤è¤¦¤Ë¤Ê¤ë¡£ + +É®¼Ô¤¬ Unix ¤Ç»È¤Ã¤Æ¤¤¤ë {\tt c.spider} ¤Ç¤Ï¡¢°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡£ +\begin{verbatim} +language C extension c +\end{verbatim} + + + + +\subsection{{\TeX} ¥Þ¥¯¥í¤ÎÄêµÁ} +%In addition to the ``kernel'' {\WEB} macros stored in {\tt +%webkernel.tex}, you may want to create some {\TeX} macros of your +%own for use in translations. +{\tt webkernel.tex}¤Ëµ½Ò¤µ¤ì¤Æ¤¤¤ë¡Ö¥«¡¼¥Í¥ë¡×{\WEB}¥Þ¥¯¥í¤ò³ÈÄ¥¤¹¤ë¤¿¤á¤Ë¡¢ +translations ¤ÎÃæ¤Ç»È¤¦ÀìÍѤÎ{\TeX}¥Þ¥¯¥í¤ò +ÄêµÁ¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¡£ +%Any macro definitions you put between lines saying {\tt macros begin} +%and {\tt macros end} will be included verbatim in the {\TeX} macro +%file for this language. +¤É¤ó¤Ê¥Þ¥¯¥í¤Ç¤â¡¢{\tt macros begin}¹Ô¤È +{\tt macros end} ¹Ô¤Î´Ö¤Ë¤¢¤ë¤â¤Î¤Ï +¤½¤Î¤Þ¤Þ¤½¤Î¸À¸ìÍѤΠ{\TeX} ¥Þ¥¯¥í¥Õ¥¡¥¤¥ë¤ÎÃæ¤Ë¼è¤ê¹þ¤Þ¤ì¤ë¡£ +%That macro file will automatically be \verb+\input+ by every {\TeX} +%file generated by this {\tt WEAVE}. +¤³¤Î¥Þ¥¯¥í¥Õ¥¡¥¤¥ë¤Ï¡¢%That macro file will automatically be +{\tt WEAVE}¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤ë¤¹¤Ù¤Æ¤Î {\TeX}¥Õ¥¡¥¤¥ë¤Ë +\verb+\input+ Ì¿Îá¤Ç¼«Æ°Åª¤Ë¼è¤ê¹þ¤Þ¤ì¤ë¤è¤¦¤Ë¤Ê¤ë¡£ + +%For example, the C grammar includes productions to handle preprocessor +%directives. +%These directives may include file names that are delimited by angle +%brackets. +%I wanted to use the abbreviations \verb+\LN+ and \verb+\RN+ for left +%and right angle brackets, so I included +Î㤨¤Ð¡¢C ¤Îʸˡ¤Ï¥×¥ê¥×¥í¥»¥Ã¥µÌ¿Îá¤ò°·¤¦µ¬Â§¤ò´Þ¤ó¤Ç¤¤¤ë¡£ +¤³¤ÎÌ¿Îá¤Ï³Ñ¥«¥Ã¥³¤Ç³ç¤Ã¤¿¥Õ¥¡¥¤¥ë̾¤ò»È¤¦¡£ +É®¼Ô¤Ï¡¢\verb+\LN+ , \verb+\RN+ ¤òº¸³Ñ¥«¥Ã¥³, +±¦³Ñ¥«¥Ã¥³¤Îû½Ì·Á¤È¤·¤Æ»È¤¦¤¿¤á¡¢ +°Ê²¼¤ÎÄêµÁ¤ò{\tt c.spider} ¥Õ¥¡¥¤¥ë¤Ë½ñ¤¤¤Æ¤¢¤ë¡£ +\begin{verbatim} +macros begin +\let\LN\langle +\let\RN\rangle +macros end +\end{verbatim} + + +\subsection{¥Ç¥Õ¥©¥ë¥È¤Î¥È¡¼¥¯¥ó¾ðÊó¤ÎÀßÄê} +%It's possible to set default values for the {\tt translation} and {\tt +%mathness} properties of tokens, so that they don't have to be +%repeated. +¥È¡¼¥¯¥ó¤Î \hbox{\tt translation} ¤È \hbox{\tt mathness} ¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤò +ÀßÄꤹ¤ë¤³¤È¤Ë¤è¤ê¡¢Ëè²ó·«¤êÊÖ¤·¤Æµ½Ò¤¹¤ëɬÍפ¬¤Ê¤¯¤Ê¤ë¡£ +%This is done with the {\tt default} command, whose syntax is: +¤³¤ì¤Ï\hbox{\tt default} ¥³¥Þ¥ó¥É¤ò»È¤¦¡£½ñ¼°¤Ï°Ê²¼¤ÎÄ̤ê: +\begin{quote} +\tt +default \syntax{token descriptions} +\end{quote} +%The initial defaults (when {Spider} begins execution) are {\tt +%translation~<*>} and {\tt mathness~maybe}. +({Spider}¤¬¼Â¹Ô³«»Ï¤·¤¿¤È¤¤Î)¥Ç¥Õ¥©¥ë¥ÈÃͤνé´üÃÍ¤Ï +{\tt translation~<*>} ¤È {\tt mathness~maybe}¤Ç¤¢¤ë¡£ + + + + + + +\subsection{¥â¥¸¥å¡¼¥ë¤Î°·¤¤Êý¤Î»ØÄê} +{\WEB} ¤Ï¡¢Â¾¤Î¤É¤ó¤Ê¥×¥í¥°¥é¥ß¥ó¥°¸À¸ì¤Ë¤â¤Ê¤«¤Ã¤¿¼ïÎà¤Î¥È¡¼¥¯¥ó +¡Ö¥â¥¸¥å¡¼¥ë̾¡×¤òƳÆþ¤·¤¿({\tt @<...@>} ¤Þ¤¿¤Ï {\tt @(...@>})¡£ +%introduces a new kind of token that isn't in any programming +%language, and that's the module name ({\tt @<...@>} or {\tt @(...@>}). +{\tt TANGLE}¤Î»Å»ö¤Ï¡¢¤³¤Î¥â¥¸¥å¡¼¥ë̾¤ò¥×¥í¥°¥é¥à¥Æ¥¥¹¥È¤Ë¤¹¤ë¤³¤È¤Ç¤¢¤ê¡¢ +%'s job is to convert the module names to program text, and +¥â¥¸¥å¡¼¥ë̾¤¬¤Ê¤¯¤Ê¤Ã¤¿»þ¤Ë½ªÎ»¤¹¤ë¡£ +%when {\tt TANGLE} is finished no module names remain. +¤·¤«¤·¡¢{\tt WEAVE} ¤Ï¥â¥¸¥å¡¼¥ë̾¤òÁÈÈǤ·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤Î¤Ç¡¢ +%has to typeset the module names, and we need to tell +{\tt WEAVE} ¤¬¥â¥¸¥å¡¼¥ë̾¤ò¤É¤ó¤Ê¥«¥Æ¥´¥ê¡¼¤Î¥¹¥¯¥é¥Ã¥×¤Ë¤¹¤ë¤«¤ò +µ¬Äꤷ¤Æ¤ä¤ëɬÍפ¬¤¢¤ë¡£ +%what category to give a scrap created from a module name. +2¤Ä¤Î¥«¥Æ¥´¥ê¡¼¤¬µö¤µ¤ì¤ë¡£ +%We allow two different categories, +1¤Ä¤Ï¥â¥¸¥å¡¼¥ë̾¤ÎÄêµÁ (¥â¥¸¥å¡¼¥ë¤Î³«»Ï)ÍѤǤ¢¤ê¡¢ +¤â¤¦°ì¤Ä¤Ï¡¢¥â¥¸¥å¡¼¥ë̾¤Î»ÈÍÑ»þ¤Î¤â¤Î¤Ç¤¢¤ë¡£ +{\samepage +{\tt module}¥³¥Þ¥ó¥É¤Î¹½Ê¸¤Ï°Ê²¼¤ÎÄ̤ꡣ +\begin{quote} +\tt +module \opt{definition \syntax{category name}} +\opt{use \syntax{category name}} +\end{quote} +} + +{\tt c.spider} ¤Ç¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ¤¤¤ë¡£ +\begin{verbatim} +module definition decl use math +\end{verbatim} + +\subsection{at sign ¤Î·èÄê} +{Spider}¤Ç{\WEB}¥·¥¹¥Æ¥à¤òºî¤ë¤Ê¤é¤Ð¡¢ + ``{\tt @}'' ¤ò ``magic at sign'' ¤È¤·¤Æ{\WEB}¤ÎÀ©¸æ¥³¥Þ¥ó¥É¤Î +³«»Ï¥¥ã¥é¥¯¥¿¤Ë¤¹¤ëɬÍפϤʤ¤¡£ +¤·¤«¤·¤Ê¤¬¤é¡¢´·Îã¤È¤·¤Æ¡¢Ë¾¤Þ¤·¤¯¤Ê¤¤¾ì¹ç°Ê³°¤Ï ``{\tt @}'' +¤ò»È¤¦¤³¤È¤Ë¤·¤è¤¦¡£ +``{\tt @}'' ¤¬Ë¾¤Þ¤·¤¯¤Ê¤¤»þ¤Ï¡¢Âå¤ï¤ê¤Ë ``{\tt \#}''¤ò»È¤¦¤³¤È¤Ë¤¹¤ë¡£ +{Spider} ¤Ç {\tt WEAVE} ¤È {\tt TANGLE} ¤Î C~{\WEB} ¥³¡¼¥É¤ò½ñ¤¯¤Ë¤Ï¡¢ +¿¤¯¤Î {\tt @} ¤ò½ñ¤¯¤³¤È¤Ë¤Ê¤ë¡£ +°ì¤Ä°ì¤Ä¤ò¥¨¥¹¥±¡¼¥×¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤»þ¤ËÉ®¼Ô¤Ï¤½¤¦¤Ï¤·¤Ê¤«¤Ã¤¿¡£ +``{\tt \#}'' Awk~{\WEB}¤Î at~sign ¤ò ``{\tt \#}'' ¤Ë¤·¤¿: +\begin{verbatim} +at_sign # +\end{verbatim} +»ØÄꤵ¤ì¤Ê¤¤»þ¤Ë¤Ï¥Ç¥Õ¥©¥ë¥È¤Ï ``{\tt @}'' ¤Î¤Þ¤Þ¤Ç¤¢¤ë¡£ + +\paragraph{¥³¥ó¥È¥í¡¼¥ë¥·¡¼¥±¥ó¥¹¤ÎÊѹ¹} +at~sign ¤ÎÊѹ¹¤Ï¤Ò¤È¤Ä¤«Æó¤Ä¤Î¥³¥ó¥È¥í¡¼¥ë¥·¡¼¥±¥ó¥¹¤Î°ÕÌ£¤òÊѹ¹¤¹¤ë¡£ +%This is more easily illustrated by example than explained. +¸ÀÍÕ¤ÇÀâÌÀ¤¹¤ë¤è¤ê¤ÏÎã¤ò¼¨¤·¤¿Êý¤¬²ò¤ê¤ä¤¹¤¤¤Î¤Ç¡¢ +at~sign ¤ò{\tt\#}¤ËÊѤ¨¤¿¾ì¹ç¤ò¼¨¤½¤¦¡£ +·ë²Ì¤È¤·¤Æ {\WEB} ¤ÎÆó¤Ä¤Î¥³¥ó¥È¥í¡¼¥ë¥·¡¼¥±¥ó¥¹¤Ï¿·¤·¤¤°ÕÌ£¤ò»ý¤Ä¤³¤È¤Ë¤Ê¤ë: +\begin{description} +\item[{\tt \#\#}] +%Stands for a {\tt \#} in the input, by analogy with {\tt @@} in normal +%{\WEB}. +Ä̾ï¤Î{WEB}¤Î{\tt @@}¤ÈƱÍͤʰÕÌ£¤Ç¡¢ÆþÎÏÃæ¤Î{\tt\#}¤ò¼¨¤¹¡£ +%You will need this when defining {\TeX} macros that take parameters. +¥Ñ¥é¥á¡¼¥¿¤òȼ¤¦{\TeX} ¥Þ¥¯¥í¤òÄêµÁ¤¹¤ë¤È¤¤ËɬÍפˤʤ롣 +\item[{\tt \#@}] +%This is the new name of the control sequence normally represented by +%{\tt@\#}. +¤³¤ì¤Ï¡¢Ä̾ï¤Î{\tt@\#}¤È¤¤¤¦À©¸æ¥·¡¼¥±¥ó¥¹¤Î¿·¤·¤¤Ì¾Á°¤Ç¤¢¤ë¡£ +% You would use {\tt\#@} to get a line break followed by vertical +%white space. +{\tt\#@}¤Ï¡¢¿âľ¥¹¥Ú¡¼¥¹¤òȼ¤¦²þ¹Ô¤òÆÀ¤ë¤È¤¤Ë»È¤¦¡£ +\end{description} +%If you change the at sign to something other than {\tt@}~or~{\tt\#}, +%the above will still hold provided you substitute your at sign for +%{\tt\#}. +¤â¤·¤¢¤Ê¤¿¤¬ at~sign ¤ò {\tt@}~¤Þ¤¿¤Ï~{\tt\#} °Ê³°¤Î²¿¤«¤ËÊѤ¨¤¿¤Ê¤é¡¢ +¾å¤Îµ½Ò¤Î{\tt\#}¤ò¤¢¤Ê¤¿¤¬»ØÄꤷ¤¿ at~sign ¤ËÃÖ¤´¹¤¨¤ÆÆɤá¤ÐÎɤ¤¡£ + + + + +\subsection{¥×¥í¥°¥é¥à¸À¸ìÆâ¤Ç¤Î¥³¥á¥ó¥È} +{\tt WEAVE} ¤È {\tt TANGLE} ¤Ë¥¿¡¼¥²¥Ã¥È¸À¸ì¤ÎÃæ¤Î¥³¥á¥ó¥È¤Î°·¤¤¤ò +»ØÄꤷ¤Æ¤ª¤«¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ +¥³¥á¥ó¥È¥Æ¥¥¹¥È¤Ï¡¢ +{\tt WEAVE}¤Ç¤Ï{\TeX}¥Æ¥¥¹¥È¤È¤·¤Æ°·¤ï¤ì¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤·¡¢ +{\tt TANGLE}¤Ç¤Ï̵»ë¤µ¤ì¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ +{\tt comment} ¥³¥Þ¥ó¥É¤Î¹½Ê¸¤Ï¡¢°Ê²¼¤ÎÄ̤ꡣ +\begin{quote} +\tt +comment begin \syntax{restricted translation} \\ +\null\qquad end $(\syntax{restricted translation}|{\tt newline})$ +\end{quote} +³ç¤é¤ì¤¿Ê¸»úÎó¡¢{\tt space}¡¢{\tt dash} ¤Î¤ß¤¬¡¢ +À©¸Â¤Ä¤¤Î translation ¤È¤·¤Æµ½Ò¤Ç¤¤ë¡£ +%They give the character sequences that begin and end comments. +¤³¤ì¤é¤Ï¥³¥á¥ó¥È¤Î³«»Ï¤È½ªÎ»¤Îʸ»úÎó¤Ç¤¢¤ë¡£ +¥³¥á¥ó¥È¤¬²þ¹Ô¤Ç½ªÎ»¤¹¤ë¤Î¤Ê¤é¡¢Àµ¤·¤¤¤ª¤Þ¤¸¤Ê¤¤¤Ï {\tt end +newline}¤Ç¤¢¤ë¡£ + +¤â¤·¥³¥á¥ó¥Èʸ»ú¤¬ ``at sign''¤ÈƱ¤¸¤Ç¤¢¤ì¤Ð¡¢ +{\WEB} ¥Õ¥¡¥¤¥ë¤ÎÃæ¤Ç¤ÏÆó½Å¤Ë½ñ¤«¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ +%file to have any effect. +É®¼Ô¤¬Ëº¤ì¤Æ¤·¤Þ¤Ã¤¿¤»¤¤¤Ç¡¢ +{Spider} ¤³¤ì¤ò¸¡½Ð¤Ç¤¤Ê¤¤Çϼ¯¼Ô¤Ë¤Ê¤Ã¤Æ¤·¤Þ¤¤¡¢ +%is too dumb to figure this out +{\jem {\tt Spider} ¥Õ¥¡¥¤¥ë¤ÎÃæ¤Ç +¥³¥á¥ó¥Èʸ»ú¤òÆó½Å¤Ë½ñ¤«¤Í¤Ð¤Ê¤é¤Ê¤¯¤Ê¤Ã¤Æ¤·¤Þ¤Ã¤¿}¡£ +%This is not totally unreasonable since any at sign that actually appears in a +%{\WEB} file will have to be double to be interpreted correctly. +{\WEB}¥Õ¥¡¥¤¥ë¤¬Àµ¤·¤¯²ò¼á¤¹¤ë¤¿¤á¤Ë at~sign ¤¬¸½¼Â¤Ë¤Ï +Æó½Å¤Ë½ñ¤«¤ì¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤Î¤Ç¡¢Áí¹çŪ¤Ë¤ÏÁ´¤¯ÉÔÅö¤È¤¤¤¦¤ï¤±¤Ç¤Ï¤Ê¤¤¡£ + + +{\tt WEAVE} ¤Ï \verb+\commentbegin+ ¤È +\verb+\commentend+ ¤È¤¤¤¦¥Þ¥¯¥í¤ò +¥³¥á¥ó¥È¤Î³«»Ï¤È½ªÎ»¤Ë»È¤¦¡£ +%at the beginning and end of comments, so you can +¤è¤Ã¤Æ¡¢{Spider}¤Î¥Ç¥Õ¥©¥ë¥È¤¬µ¤¤ËÆþ¤é¤Ê¤±¤ì¤Ð +({\tt macros}¥³¥Þ¥ó¥É¤ò»È¤Ã¤Æ)¹¥¤¤Ê¤è¤¦¤ËÄêµÁ¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¡£ +{Spider} ¤Ï{\TeX}¤Î¥Ç¥Õ¥©¥ë¥È¤ÎÆüìʸ»ú¤ò²óÈò¤¹¤ëÄøÅ٤ˤϽ½Ê¬¥¹¥Þ¡¼¥È¤Ç¤¢¤ë¡£ +%is smart enough to escape {\TeX}'s special characters in +%coming up with these defaults. + +%Here's a real-world ugly example of how things really are, from the +%{\tt spider} file for Awk: +°Ê²¼¤Ë¼ÂºÝ¤Ë¤É¤¦¤·¤Æ¤¤¤ë¤«¤ò Awk ¤Î{\tt spider} ¥Õ¥¡¥¤¥ë¤«¤é°úÍѤ¹¤ë: +\begin{verbatim} +comment begin <"##"> end newline +macros begin +\def\commentbegin{\#} % we don't want \#\# +macros end +\end{verbatim} + + + +\subsection{¹ÔÈÖ¹æ¤ÎÀ©¸æ} + ¥³¥ó¥Ñ¥¤¥é¤¬{\WEB}¥Õ¥¡¥¤¥ë¤òľÀܸ«¤ë¤³¤È¤Ï¤Ê¤¤¡£{\tt TANGLE} ¤Î +½ÐÎϤòÆɤޤͤФʤé¤Ê¤¤¡£ +{\tt TANGLE}¤¬ºî¤Ã¤¿¥Õ¥¡¥¤¥ë¤Î¹ÔÈÖ¹æ¤ò¼¨¤¹¥¨¥é¡¼¥á¥Ã¥»¡¼¥¸¤Ï¡¢ +Èó¾ï¤Ë͸ú¤À¤È¤Ï¸À¤¤Æñ¤¤¡£¤½¤³¤Ç¡¢ +Spidery {\tt TANGLE} ¤Ï¡¢Â¿¾¯²þÁ±¤·¤¿¾õ¶·¤òÄ󶡤¹¤ë¤¿¤á¡¢ + C~¥×¥ê¥×¥í¥»¥Ã¥µ¡¼ÍѤΠ{\tt \#line} Ì¿Îá¤ò½ÐÎϤ˽ñ¤¯( +{\tt TANGLE} ¤â{\WEB} ¥½¡¼¥¹¤Î²þ¹Ô¾ðÊó¤òÊÝ»ý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢ + {\tt \#line} ¾ðÊó¤ÏÍÍѤÀ¤í¤¦)¡£ +{\tt cc} ¤È {\tt dbx}¤ò»ý¤Ã¤¿ +Unix ¤Î¤è¤¦¤Ê¥·¥¹¥Æ¥à¤Ç¤Ï¡¢¥³¥ó¥Ñ¥¤¥ë»þ¤È¥é¥ó¥¿¥¤¥à»þ¤ÎξÊý¤Ç +{\WEB}¥½¡¼¥¹¤ÎÍѸì¤Ç¥Ç¥Ð¥Ã¥°¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¡£ +Ãæ´Ö¤Î¥×¥í¥°¥é¥ß¥ó¥°¥½¡¼¥¹¤Ï¤±¤Ã¤·¤ÆÄ´¤Ù¤ëɬÍפ¬¤Ê¤¤¡£ + +Á´¤Æ¤Î¥³¥ó¥Ñ¥¤¥é¤¬{\tt \#line}Ì¿Îá¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¤ï¤±¤Ç¤Ï¤Ê¤¤¤Î¤Ç¡¢ +{Spider}¤Ï {\tt line} ¥³¥Þ¥ó¥É¤Ç + {\tt \#line} Ì¿Îá¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤òÊѹ¹¤Ç¤¤ë¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡£ +¼«Ê¬¤Î¥³¥ó¥Ñ¥¤¥é¤¬ {\tt \#line} ¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢ +{\tt line} ¥³¥Þ¥ó¥É¤ò»È¤Ã¤Æ¹ÔÈÖ¹æ¾ðÊó¤ò¥³¥á¥ó¥È¤ÎÃæ¤ËÆþ¤ì¤ë¤è¤¦¤Ë +Êѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤¤ë\footnote{% +¹ÔÈÖ¹æ¤ò½Ð¤µ¤Ê¤¤¥³¥Þ¥ó¥É¤¬¤¢¤ë¤Ù¤¤Ç¤¢¤ë¡£% +}¡£ +¹½Ê¸¤Ï°Ê²¼¤ÎÄ̤ê: +\begin{quote} +\tt +line begin \syntax{restricted translation} end \syntax{restricted translation} +\end{quote} +{\tt begin} ¤Ï¥Õ¥¡¥¤¥ë̾¤È¹ÔÈÖ¹æ¤ÎÁ°¤ËÃÖ¤¯Ê¸»úÎó¤ò»ØÄꤷ¡¢ +{\tt end} ¤Ï¸å¤ËÃÖ¤¯Ê¸»úÎó¤ò»ØÄꤹ¤ë¡£ +¥Ç¥Õ¥©¥ë¥È¤Ï (CÍѤËÀßÄꤵ¤ì¤Æ¤¤¤ë¤¬)°Ê²¼¤ÎÄ̤ꡣ +\begin{verbatim} +line begin <"#line"> end <""> +\end{verbatim} +¼¡¤Î¤Ï Ada~{Spider}¥Õ¥¡¥¤¥ë¤Ç¤ÎÎã¤Ç¤¢¤ë¡£ +¤³¤³¤Ç¤Ï¡¢¹ÔÈÖ¹æ¾ðÊó¤ò Ada ¤Î¥³¥á¥ó¥È¤È¤·¤Æ¤¤¤ë: +\begin{verbatim} +line begin <"--"-space-"line"> end <""> +\end{verbatim} + + + + +\subsection{ºîÀ®Æü»þ¤Îɽ¼¨} +Spidery {\tt WEAVE} ¤È{\tt TANGLE}¤¬½èÍý¤ò»Ï¤á¤ë»þ¡¢ +{Spider}¥Õ¥¡¥¤¥ë¤ò½èÍý¤·¤¿Æü»þ¤¬É½¼¨¤µ¤ì¤ë¡£ +¤³¤ì¤Ï¡¢{Spider}¤Î {\tt date}¥³¥Þ¥ó¥É¤Ë¤è¤Ã¤Æ¼¡¤Î¤è¤¦¤ËÀßÄꤵ¤ì¤ë¡£ +\begin{quote} +\tt +date \syntax{date} +\end{quote} +¤³¤³¤Ç \syntax{date} ¤Ï¡¢{\tt "Fri Dec 11 11:31:18 EST 1987"} ¤Ê¤É¤Ç¤¢¤ë¡£ +Ä̾{\tt date} ¥³¥Þ¥ó¥É¤ÎɬÍפϤʤ¤¡£ +{Spider} ¥Ä¡¼¥ë¤¬¼«Æ°Åª¤ËÁÞÆþ¤¹¤ë¡£ +¤·¤«¤·¡¢Unix ¥Þ¥·¥ó¤Ç¤Ê¤¤¥·¥¹¥Æ¥à¤Ë{Spider}¤ò°Ü¿¢¤¹¤ë»þ¤Ë¤Ï¡¢ +¾åµ¤Î¤³¤È¤¬É¬Íפˤʤ롣 + + + + + +\section{Spider¤Î¥¨¥é¡¼¥á¥Ã¥»¡¼¥¸} +{Spider} ¤Ï»ÅÍ;å¤Î¥¨¥é¡¼¤ò¸¡½Ð¤¹¤ë¤¿¤á¤ËÈó¾ï¤ÊÅØÎϤò¤¹¤ë¡£ +{Spider}¤Î¥¨¥é¡¼¥á¥Ã¥»¡¼¥¸¤ÏÆɤá¤Ð¤ï¤«¤ë¤è¤¦¤Ëºî¤ë¤Ä¤â¤ê¤Ç¤¢¤ë¤¬¡¢ +¤¦¤Þ¤¯À®¸ù¤µ¤»¤ëÊýË¡¤òÃΤé¤Ê¤¤¡£ +¥È¥é¥Ö¥ë¤Ë¤¢¤Ã¤¿»þ¤Î¤¿¤á¤Ë¡¢°Ê²¼¤Ë{Spider}¤¬¸¡½Ð¤·¤è¤¦¤È¤·¤Æ¤¤¤ë¾ò·ï¤ò¼¨¤·¤Æ¤ª¤¯: +\begin{itemize} +\item + ̤ÄêµÁ¤Ê¥³¥Þ¥ó¥É¡¢¸í¤Ã¤¿¥Õ¥£¡¼¥ë¥É¤ò´Þ¤à¹Ô¡¢ +%Garbled commands, lines with bad fields in them, or commands with +»È¤ï¤ì¤Ê¤¤¥Õ¥£¡¼¥ë¥É¤ò»ý¤Ä¥³¥Þ¥ó¥É¡£ +%Any command with a field {Spider} can't follow or with an extra +%field is ignored from the bad field onward, but the earlier fields may +%have an effect. +¥Õ¥£¡¼¥ë¥É¤¬É¬Íפʤ¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë¤Ä¤¤¤Æ¡¢ +{Spider}¤Ï¥Õ¥£¡¼¥ë¥É¤òÊä¤ï¤Ê¤¤¤·¤è¤±¤¤¤Ê¥Õ¥£¡¼¥ë¥É°Ê¹ß¤ò̵¸ú¤È¤¹¤ë¡£ +¤¿¤À¤·¡¢¤½¤ì°ÊÁ°¤Î¥Õ¥£¡¼¥ë¥É¤Ï͸ú¤Ë¤Ê¤ë¤«¤âÃΤì¤Ê¤¤¡£ +¸í¤Ã¤¿¥Õ¥£¡¼¥ë¥É¤ä¥¨¥é¡¼¤Î¤¢¤ëÀ¸À®µ¬Â§¤Ï´°Á´¤Ë̵¸ú¤È¤µ¤ì¤ë¡£ +\item +{\tt language} ¥³¥Þ¥ó¥É¤¬¤Ê¤¤¡£ +\item +{\tt macros} ¤Þ¤¿¤Ï {\tt comment} ¥³¥Þ¥ó¥É¤¬ {\tt language} ¥³¥Þ¥ó¥É¤Î +Á°¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£ +{Spider} ¤Ï {\tt extension} ¾ðÊó¤ò +from the {\tt language} ¥³¥Þ¥ó¥É¤«¤éÆÀ¤Æ¤ª¤ê¡¢ +¥Þ¥¯¥í¤ò½ñ¤½Ð¤¹¥Õ¥¡¥¤¥ë̾¤ò·èÄꤹ¤ë¤¿¤á¤Ë»È¤¦¡£ +¤Þ¤¿{\tt comment} ¥³¥Þ¥ó¥É¤Ï +{Spider} ¤¬{\TeX}¤Î¤¿¤á¤Ë¥³¥á¥ó¥È¤Î»Ï¤Þ¤ê¤È½ª¤ê¤ò +¥Þ¥¯¥í¥Õ¥¡¥¤¥ë¤Ë½ñ¤¯¤³¤È¤òÍ×ÀÁ¤¹¤ë¡£ +\item +ʸ̮¤¬º¸Æ³½Ð¡¢±¦Æ³½Ð¤Î¤¤¤º¤ì¤Ë¤â¹çÃפ·¤Ê¤¤¡£ +\item +%A numbered target token doesn't fall in the range defined by the +%left hand side of its production. +ÈÖ¹æ¤Ç»²¾È¤µ¤ì¤¿¥È¡¼¥¯¥ó¤¬¤½¤ÎÀ¸À®µ¬Â§¤Îº¸Êդˤʤ¤¡£ +\item +{\jem ÄɲäǤ¤Ê¤¤}¥«¥Æ¥´¥ê¡¼¤¬¤¢¤ë¡£ +¤³¤ì¤Ï¡¢¤½¤Î¥«¥Æ¥´¥ê¡¼¤¬¥¹¥¯¥é¥Ã¥×¤òÀ¸À®¤¹¤ëÊýË¡¤¬¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£ +{Spider} ¤Ïñ¤Ë¤¹¤Ù¤Æ¤Î¥«¥Æ¥´¥ê¡¼¤¬¾¯¤Ê¤¯¤È¤â°ìÅÙ¤Ï +¥È¡¼¥¯¥ó¤«¥¿¡¼¥²¥Ã¥È¥È¡¼¥¯¥ó¤È¤·¤ÆÀ¸À®µ¬Â§¤ÎÃæ¤Ë¸½¤ì¤ë¤³¤È¤ò +Ä´¤Ù¤Æ¤¤¤ë¤À¤±¤Ç¤¢¤ë¡£ +(¤â¤·¤±¤·¤ÆŬÍѤµ¤ì¤Ê¤¤À¸À®µ¬Â§¤¬¤¢¤ë¤Ê¤é¤Ð) +{Spider}¤Ï¾ò·ï¤ò¸¡½Ð¤Ç¤¤Ê¤¤¤Î¤Ç¼ºÇÔ¤¹¤ë¡£ +\item +{\jem ´Ô¸µ¤Ç¤¤Ê¤¤}¥«¥Æ¥´¥ê¡¼¤¬¤¢¤ë¡£ +¤³¤ì¤Ï¡¢¤³¤Î¥«¥Æ¥´¥ê¡¼¤¬À¸À®µ¬Â§¤ÎÃæ¤Ç»²¾È¤µ¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£ +%This means that the category never appears in a scrap +%designator from the firing instructions of a production. +¥«¥Æ¥´¥ê¡¼¤¬´Ô¸µ¤Ç¤¤Ê¤±¤ì¤Ð¡¢ +{Spider} ¤Ïñ¤Ë·Ù¹ð¤ò½Ð¤¹¤Î¤ß¤Ç¡¢ +¥¨¥é¡¼¤Ë¤è¤Ã¤Æ½èÍý¤òÄä»ß¤¹¤ë¤³¤È¤Ï¤Ê¤¤¡£ + +¥«¥Æ¥´¥ê¡¼Ì¾¤ÎÄ֤θí¤ê¤Ë¤è¤ëÄɲäȴԸµ¤Î¥Á¥§¥Ã¥¯¤Ï¤¿¤¤¤Æ¤¤¸¡½Ð¤µ¤ì¤ë¡£ +\item +{\tt WEAVE} ¤È {\tt TANGLE} ¤¬°·¤¨¤ë°Ê¾å¤Î +¥È¡¼¥¯¥ó¤ò»ØÄꤷ¤Æ¤¤¤ë¡£ +\item +¥È¡¼¥¯¥ó¤Î¾ðÊó¤¬ÉÔ´°Á´; ¼±Ê̻ҡ¢¿ôÃÍÄê¿ô¡¢newline¡¢ +µ¿»÷¥»¥ß¥³¥í¥ó~({\tt @;})¡¢¥â¥¸¥å¡¼¥ëÄêµÁ¡¢¥â¥¸¥å¡¼¥ë¤Î»ÈÍѤò˺¤ì¤Æ¤¤¤ë¡£ +\item +ilk ¤¬ translation ¤ò»ý¤¿¤Ê¤¤¡¢¤Þ¤¿¤ÏͽÌó¸ì¤ò»ý¤¿¤Ê¤¤ ilk ¤¬¤¢¤Ã¤¿¡£ +%no reserved words. +\end{itemize} + + + + +\section{{Spider}¤Î½ÐÎÏ¥Õ¥¡¥¤¥ë} +{Spider} ¤Ï¿¤¯¤Î½ÐÎÏ¥Õ¥¡¥¤¥ë¤òÀ¸À®¤¹¤ë¡£É¬Íפʤ餽¤ì¤é¤òÄ´¤Ù¡¢ +²¿¤¬¤Ê¤µ¤ì¤Æ¤¤¤ë¤«¤ò²òÀϤǤ¤ë¡£ +°Ê²¼¤Ï¤½¤Î°ìÉô¤Ç¤¢¤ë (´°Á´¤Ê¥Õ¥¡¥¤¥ë¤Î¥ê¥¹¥È¤Ï +{\tt spider.web}¤òÄ´¤Ù¤ì¤Ð¤ï¤«¤ë): +\begin{description} +\item[\tt cycle.test] +ʸˡ¤Î¥ë¡¼¥×²ÄǽÀ¤ò¸¡½Ð¤¹¤ë¤Î¤Ë»ÈÍѤµ¤ì¤ë¡£ +¤³¤Î¤è¤¦¤Ê¥ë¡¼¥×¤Ï ÆÃÄê¤ÎÆþÎϤËÂФ·{\tt WEAVE} ¤ò̵¸Â¤Ë (¥á¥â¥ê¡¼¤ò»È¤¤¤¤ë¤Þ¤Ç) +Áö¤é¤»¤ë¤³¤È¤Ë¤Ê¤ë¤è¤¦¤Ê¤â¤Î¤Ç¤¢¤ë¡£ +¸å¤Ç {Spider}¥Ä¡¼¥ë¤È°ì½ï¤ËµÄÏÀ¤¹¤ë¡£ +\item[\tt spider.slog] +{Spider} ¤¬¥Õ¥¡¥¤¥ë¤ò½èÍýÃæ¤Î¤¹¤Ù¤Æ¤Î¾éŤÊÆâÍÆ¡£ +¤Ò¤É¤¤¤³¤È¤¬µ¯¤¤¿»þ¤ËÄ´¤Ù¤ë¤¿¤á¤Î¤â¤Î¤Ç¤¢¤ë¡£ +\item[\tt *web.tex] +À¸À®¤µ¤ì¤¿{\WEB}¤Î¤¿¤á¤Î¥Þ¥¯¥í¡£ +\item[\tt productions.list] +¤¹¤Ù¤Æ¤Îµ¬Â§¤ÎÈÖ¹æÉÕ¤±¤·¤¿¥ê¥¹¥È¡£ +Spidery {\tt WEAVE}¤Î¥È¥ì¡¼¥¹µ¡Ç½ ({\tt @2})¤ò»È¤Ã¤Æʸˡ¤Î¥Ç¥Ð¥Ã¥°¤ò +¤¹¤ëºÝ¤Ë½ÅÊõ¤¹¤ë¡£ +\end{description} + + + + +\section{{Spider} ¤Ç{\WEB}¤òºî¤ë ({Spider} tools)} +¿¤¯¤Î {Spider} ¥Ä¡¼¥ë¤¬¥¨¥é¡¼¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£Î㤨¤Ð: +\begin{itemize} +\item +¥«¥Æ¥´¥ê¡¼¡¢ilk¡¢translation ¤Î¥¡¼¥ï¡¼¥É̾¤Î½ÅÊ£¥Á¥§¥Ã¥¯¤ò¤¹¤ë¡£ +\item +translation ¥¡¼¥ï¡¼¥É¤¬{\tt WEAVE}¤Î¥¡¼¥ï¡¼¥É¤È¾×Æͤ·¤Æ¤¤¤Ê¤¤¤«¤ò¥Á¥§¥Ã¥¯¤·¡¢ +¾×Æͤ·¤Æ¤¤¤ì¤Ð·Ù¹ð¤òȯ¤¹¤ë¡£ +%keywords against a list of those recognized by +% and yelps if trouble happens. +\item +{\tt WEAVE}¤¬Ìµ¸Â¥ë¡¼¥×¤Ë´Ù¤ë¤è¤¦¤Ê¡ÖÀ¸À®µ¬Â§¤Î½Û´Ä¡×¤¬¤Ê¤¤¤«¤ò¸¡½Ð¤¹¤ë¡£ +%Try to determine whether there is a ``production cycle'' that could +%cause to loop infinitely by firing the productions in the +%cycle one after another. +\end{itemize} + +¤³¤³¤Ç¤Ï¡¢¤½¤ì¤é¤¬¤É¤¦¤Ê¤Ã¤Æ¤¤¤ë¤«¡¢{\tt WEAVE} ¤ä {\tt TANGLE}¤ò +¤É¤¦¤ä¤Ã¤ÆÀ¸À®¤¹¤ë¤«¤Ë¤Ä¤¤¤Æ¡¢Â¿¤¯¤òÀâÌÀ¤¹¤ë¤Ä¤â¤ê¤Ï¤Ê¤¤¡£ +%I'm not going to say much about how to do all this, or how to make +Âå¤ï¤ê¤Ë¡¢{\tt Makefile} ¤òÄ󼨤·¡¢¾¯¡¹¥³¥á¥ó¥È¤¹¤ë¤³¤È¤Ë¤·¤è¤¦¡£ +%and comment on it a little bit. +%Since right now Spidery {\tt WEB} is available only on Unix systems, +%chances are you have the {\tt Makefile} and can just type ``{\tt +%make~tangle}'' or ``{\tt make~weave}.'' +¸½ºß¤Î¤È¤³¤í¡¢ Spidery {\tt WEB} ¤Ï Unix ¥·¥¹¥Æ¥à¤Î¾å¤Ë¤·¤«Â¸ºß¤·¤Æ¤¤¤Ê¤¤¡£ +{\tt Makefile} ¤òÆþ¼ê¤·¡¢ + ``{\tt make~tangle}'' ¤Þ¤¿¤Ï ``{\tt make~weave}'' ¤È¥¿¥¤¥×¤¹¤ë¤À¤±¤Ç +¤è¤¤²ÄǽÀ¤¬¤¢¤ë¡£ +%If not, reading the Makefile is still your best bet to figure out what +%the tools do. +¤½¤¦¤Ç¤Ê¤¤¤È¤·¤Æ¤â¡¢ Makefile ¤òÆɤó¤Ç¥Ä¡¼¥ë¤Î¤¹¤ë¤³¤È¤òÍý²ò¤¹¤ë¤Î¤¬ +ºÇÁ±¤ÎÊýË¡¤Ç¤¢¤ë¡£ + +%We assume that you are making {\tt WEAVE} and {\tt TANGLE} in some +%directory, and that the ``master sources'' for Spidery {\WEB} are kept +%in some other directory. +¤¢¤Ê¤¿¤Ï´û¤Ë {\tt WEAVE} ¤È {\tt TANGLE} ¤ò¤É¤³¤«¤Î¥Ç¥£¥ì¥¯¥È¥ê¡¼¤Ëºî¤Ã¤Æ¤¢¤ê¡¢ +Spidery {\WEB} ¤Î ``master sources'' ¤¬¤É¤³¤«Ê̤Υǥ£¥ì¥¯¥È¥ê¡¼¤Ë +Êݴɤµ¤ì¤Æ¤¤¤ë¤Î¤òÁ°Äó¤È¤¹¤ë¡£ +%Some of the {\tt Makefile} macros deserve special mention: +{\tt Makefile} ¤Î ¥Þ¥¯¥í¤Î¤¤¤¯¤Ä¤«¤ÏÆä˸ÀµÚ¤¹¤ë²ÁÃͤ¬¤¢¤ë: +\begin{description} +\renewcommand{\makelabel}[1]{{\tt#1}\hfil} +\item[THETANGLE] +À¸À®¤·¤è¤¦¤È¤·¤Æ¤¤¤ë {\tt TANGLE} ¤Î̾Á°¡£ +\item[THEWEAVE] +À¸À®¤·¤è¤¦¤È¤·¤Æ¤¤¤ë{\tt WEAVE} ¤Î̾Á°¡£ +\item[SPIDER] +{Spider} ¤ÎÆþÎÏ¥Õ¥¡¥¤¥ë̾¡£ +\item[DEST] +\verb+$(TANGLE)+ ¤È\verb+$(WEAVE)+ ¤È¤·¤ÆÄêµÁ¤µ¤ì¤¿¼Â¹Ô¥Õ¥¡¥¤¥ë¤¬ÃÖ¤«¤ì¤ë¤Ù¤ +¥Ç¥£¥ì¥¯¥È¥ê¡¼¡£ +\item[WEBROOT] +Spidery {\WEB} ÇÛÉÛʪ¤Î¥ë¡¼¥È¥Ç¥£¥ì¥¯¥È¥ê¡¼¡£ +\item[MASTER] +``¥Þ¥¹¥¿¡¼¥½¡¼¥¹''¤Î¤¢¤ë¾ì½ê¡£ +¤³¤ì¤Ï¡¢É¬¤º {\tt make} ¤¬¼Â¹Ô¤µ¤ì¤ë¥Ç¥£¥ì¥¯¥È¥ê¡¼¤È°Û¤Ê¤Ã¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ +¤µ¤â¤Ê¤±¤ì¤ÐÂæ̵¤·¤Ë¤Ê¤Ã¤Æ¤·¤Þ¤¦¤À¤í¤¦¡£ +%This should always be different from the directory in which {\tt make} +%is called, or havoc will result. +\item[CTANGLE] +tangle ¤Î C ¥³¡¼¥É¤Ç»È¤ï¤ì¤ë¥×¥í¥°¥é¥à̾¡£ +\item[AWKTANGLE] +Awk¤Î¥³¡¼¥É¤ò tangle ¤¹¤ë¥×¥í¥°¥é¥à¤Î̾Á°¡£ + +\item[MACROS] +%The name of a directory in which to put {\TeX} macro definitions (a +%{\tt *web.tex} file. +{\TeX}¥Þ¥¯¥í¥Õ¥¡¥¤¥ë({\tt *web.tex} )¤ò³ÊǼ¤¹¤ë¤Ù¤¥Ç¥£¥ì¥¯¥È¥ê¡¼Ì¾¡£ +\end{description} + +%Usually we will only be interested in two commands: ``\/{\tt +%make~weave}'' and ``\/{\tt make~tangle}.'' +ÉáÃÊÎɤ¯»È¤¦¤Î¤Ï \hbox{``{\tt make~weave}''} ¤È +\hbox{``\/{\tt make~tangle}''} ¤Î +2¤Ä¤Î¥³¥Þ¥ó¥É¤À¤±¤Ç¤¢¤í¤¦¡£ +%It's safe to use ``\/{\tt make~clean}'' only if you use the current +%directory for nothing exception spidering; ``\/{\tt make~clean}'' is +%really vicious. +\hbox{``{\tt make~clean}''} ¤Ï¡¢ ¸½ºß¤Î¥Ç¥£¥ì¥¯¥È¥ê¡¼¤Ç +{\WEB} ºîÀ®ºî¶È°Ê³°¤Î¤³¤È¤ò¤·¤Ê¤¤»þ¤Ç¤Ê¤±¤ì¤Ð°ÂÁ´¤Ç¤Ï¤Ê¤¤¡£ +%only if you use the current directory +%for nothing exception spidering; +\hbox{``\/{\tt make~clean}''}¤Ï¡¢ ËÜÅö¤Ë¤Ò¤É¤¤¤³¤È¤ò¤¹¤ë¡£ + +ËÜÅö¤Ë¶½Ì£¿¼¤¤¹Ô¤Ï¡¢ +{\tt grammar.web} ¤Î°Í¸´Ø·¸¤òɽµ¤·¤Æ¤¤¤ë¤È¤³¤í¤Ç¤¢¤ë¡£ +Âè°ì¤Ë¡¢ {Spider}¤òµ¯Æ°¤¹¤ë¡£ +¼¡¤Ë¡¢À°·Á°õºþʸˡ ¤ÎÃæ¤Ë¡¢´Ö°ã¤Ã¤¿ translation ¥¡¼¥ï¡¼¥É¤ä +½Û´Ä¤Î²ÄǽÀ¤¬¤Ê¤¤¤«¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£ +¤½¤·¤Æ¡¢Ì¾Á°¤Î¤Ë½ÅÊ£ÄêµÁ¤¬¤Ê¤¤¤³¤È¤ò¥Á¥§¥Ã¥¯¤·¡¢ +ºÇ¸å¤Ë (Á´¤Æ¤¬OK¤À¤Ã¤¿¤é) +{\tt *web.tex} ¥Õ¥¡¥¤¥ë¤ò½ÐÎϤ¹¤ë¡£ + +\newpage +°Ê²¼¤Ï¡¢ \verb+$(MASTER)/WebMakefile+¤Ç¤¢¤ë: +\begingroup\small +\begin{verbatim} +# Copyright 1989 by Norman Ramsey and Odyssey Research Associates. +# To be used for research purposes only. +# For more information, see file COPYRIGHT in the parent directory. + +HOME=/u/nr# # Make no longer inherits environment vars +THETANGLE=tangle +THEWEAVE=weave +SPIDER=any.spider +# +DVI=dvi +CFLAGS=-DDEBUG -g -DSTAT + +# CPUTYPE is a grim hack that attempts to solve the problem of multiple +# cpus sharing a file system. In my environment I have to have different +# copies of object and executable for vax, sun3, next, iris, and other +# cpu types. If you will be using Spidery WEB in a homogeneous processor +# environment, you can just set CPUTYPE to a constant, or eliminate it +# entirely. +# +# In my environment, the 'cputype' program returns a string that +# describes the current processor. That means that the easiest thing +# for you to do is to define a 'cputype' program that does something +# sensible. A shell script that says 'echo "vax"' is fine. + +CPUTYPE=`cputype` + +# Change the following three directories to match your installation +# +# the odd placement of # is to prevent any trailing spaces from slipping in + +WEBROOT=$(HOME)/web/src# # root of the WEB source distribution +DEST=$(HOME)/bin/$(CPUTYPE)# # place where the executables go +MACROS=$(HOME)/tex/macros# # place where the macros go + +MASTER=$(WEBROOT)/master# # master source directory +OBDIR=$(MASTER)/$(CPUTYPE)# # common object files + +TANGLESRC=tangle +CTANGLE=ceetangle -I$(MASTER) +CWEAVE=ceeweave -I$(MASTER) +AWKTANGLE=awktangle -I$(MASTER) +COMMONOBJS=$(OBDIR)/common.o $(OBDIR)/pathopen.o +COMMONC=$(MASTER)/common.c $(MASTER)/pathopen.c +COMMONSRC=$(COMMONC) $(MASTER)/spider.awk + + + +# Our purpose is to make tangle and weave + +web: tangle weave + +tangle: $(COMMONOBJS) $(TANGLESRC).o + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + +weave: $(COMMONOBJS) weave.o + cc $(CFLAGS) -o $(DEST)/$(THEWEAVE) $(COMMONOBJS) weave.o + + +source: $(TANGLESRC).c $(COMMONSRC) # make tangle.c and common src, then clean + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.web weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + +# Here is how we make the common stuff + +$(MASTER)/common.c: $(MASTER)/common.web # no change file + $(CTANGLE) $(MASTER)/common + +$(OBDIR)/common.o: $(MASTER)/common.c + cc $(CFLAGS) -c $(MASTER)/common.c + mv common.o $(OBDIR) + + +$(MASTER)/pathopen.c: $(MASTER)/pathopen.web # no change file + $(CTANGLE) $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +$(OBDIR)/pathopen.o: $(MASTER)/pathopen.c + cc $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(OBDIR) + + +## Now we make the tangle and weave source locally + +$(TANGLESRC).c: $(MASTER)/$(TANGLESRC).web $(MASTER)/common.h grammar.web + -/bin/rm -f $(TANGLESRC).web + ln $(MASTER)/$(TANGLESRC).web $(TANGLESRC).web +# chmod -w $(TANGLESRC).web + $(CTANGLE) $(TANGLESRC) + +weave.c: $(MASTER)/weave.web $(MASTER)/common.h grammar.web + -/bin/rm -f weave.web + ln $(MASTER)/weave.web weave.web +# chmod -w weave.web + $(CTANGLE) weave + +## Here's where we run SPIDER to create the source + +grammar.web: $(MASTER)/cycle.awk $(MASTER)/spider.awk $(SPIDER) + echo "date" `date` | cat - $(SPIDER) | awk -f $(MASTER)/spider.awk + cat $(MASTER)/transcheck.list trans_keys.unsorted | awk -f $(MASTER)/transcheck.awk + awk -f $(MASTER)/cycle.awk < cycle.test + sort *.unsorted | awk -f $(MASTER)/nodups.awk + mv *web.tex $(MACROS) + +## We might have to make spider first. + +$(MASTER)/spider.awk: $(MASTER)/spider.web + $(AWKTANGLE) $(MASTER)/spider + mv cycle.awk nodups.awk transcheck.awk $(MASTER) + rm junk.list + + +# $(MASTER)/cycle.awk: $(MASTER)/cycle.web # making spider also makes cycle +# $(AWKTANGLE) $(MASTER)/cycle + + +# This cleanup applies to every language + +clean: + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.* weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + + + +# booting the new distribution +boot: + cd ../master; rm -f *.o; for i in $(COMMONC); do \ + cc $(CFLAGS) -c $$i; \ + mv *.o $(OBDIR) ; \ + done; cd ../c + cc $(CFLAGS) -c $(TANGLESRC).c; \ + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + + +\end{verbatim} +\endgroup + +\section{¼«Ê¬ÍѤΠSpidery {\tt WEB}¤òºî¤ë} +º£¤Î¤È¤³¤í¡¢ Spidery {\tt WEB} ¤ÏUnix ¥Þ¥·¥ó¤Ç¤·¤«¥Æ¥¹¥È¤µ¤ì¤Æ¤¤¤Ê¤¤¡£ +C¥³¥ó¥Ñ¥¤¥é¤È Awk ¥¤¥ó¥¿¡¼¥×¥ê¥¿¡¼¤ÎÆ°¤¯¥Þ¥·¥ó¤Ç¤¢¤ì¤Ð¡¢°Ü¿¢¤Ï´Êñ¤Ê¤Ï¤º¤À¤¬¡¢ +´Ö°ã¤¤¤Ê¤¯¡¢¤¤¤¯¤Ä¤«¤Î½¤Àµ¤¬É¬ÍפǤ¢¤í¤¦¡£ +¤³¤Î¥Þ¥Ë¥å¥¢¥ë¤â´Þ¤ó¤À ´°Á´¤Ê{Spider}¤ÎÇÛÉۤϡ¢anonymous {\tt ftp} +( {\tt princeton.edu:~ftp/pub/spiderweb.tar.Z}) ¤ÇÆþ¼ê¤Ç¤¤ë¡£ +{Spider} ¤ò¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ë¥Ç¥£¥ì¥¯¥È¥ê¡¼¤òÁª¤Ó¡¢ÇÛÉÛ¤µ¤ì¤¿¤â¤Î¤ò untar ¤·¡¢ +%distribution, and follow the directions in the +README ¥Õ¥¡¥¤¥ë¤Î»Ø¼¨¤Ë½¾¤¨¤ÐÎɤ¤¡£ +Áª¤ó¤À¥Ç¥£¥ì¥¯¥È¥ê¡¼¤Ï¡¢{\tt WEBROOT}¤È¤Ê¤ë¡£ + +¤â¤·¡¢ÇÛÉÛ¤ÎÃæ¤Î {\tt Makefile} ¤¬¡¢¾åµ¤Ç¼¨¤·¤¿¤â¤Î¤È°ã¤Ã¤Æ¤¤¤¿¤é¡¢ +ÇÛÉÛ¤ÎÃæ¤Î¤â¤Î¤¬Àµ¤·¤¤¤È¹Í¤¨¤ÆÍߤ·¤¤¡£ + + + + +\pagebreak +\section{¼ÂºÝ¤Î {Spider} ¥Õ¥¡¥¤¥ë} +¤³¤ì¤Þ¤Ç¡¢{Spider}¤Î»È¤¤Êý¤òÀâÌÀ¤¹¤ë¤¿¤á¤Ë¼ÂºÝ¤ÎÎã¤ò»È¤Ã¤Æ¤¤¿¡£ +¤³¤³¤Ç¤Ï¡¢Awk ¸À¸ìÍѤδ°Á´¤Ê {Spider} ¥Õ¥¡¥¤¥ë¤òȯŸ¤·¤¿Îã¤È¤·¤Æ°Ê²¼¤Ë¼¨¤¹¡£ +ÇÛÉÛ¤µ¤ì¤¿¤â¤Î¤ò´Êñ¤Ë¸¦µæ¤Ç¤¤Ê¤¤¿Í¤Ï¡¢¤³¤ì¤¬ÌòΩ¤Ä¤Ç¤¢¤í¤¦¡£ +\begingroup\small +\begin{verbatim} +# Copyright 1989 by Norman Ramsey and Odyssey Research Associates. +# To be used for research purposes only. +# For more information, see file COPYRIGHT in the parent directory. + +language AWK extension awk + +at_sign # + +module definition stmt use stmt +# use as stmt is unavoidable since tangle introduces line breaks + +comment begin <"##"> end newline +macros begin +\def\commentbegin{\#} % we don't want \#\# +macros end + +line begin <"#line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness yes +token number category math mathness yes +token newline category newline translation <> mathness maybe +token pseudo_semi category ignore_scrap mathness no translation <opt-0> + +token \ category backslash translation <> mathness maybe +token + category unorbinop +token - category unorbinop +token * category binop +token / category binop +token < category binop +token > category binop +token >> category binop translation <"\\GG"> +token = category equals translation <"\\K"> +token ~ category binop translation <"\\TI"> +token !~ category binop translation <"\\not\\TI"> +token & category binop translation <"\\amp"> +token % translation <"\\%"> category binop +token ( category open +token [ category lsquare +token ) category close +token ] category close +token { translation <"\\;\\{"-indent> category lbrace +token } translation <"\\}\\"-space> category close +token , category binop translation <",\\,"-opt-3> + +token ; category semi translation <";"-space-opt-2> mathness no +# stuff with semi can be empty in for statements +open semi --> open +semi semi --> semi +semi close --> close +semi --> binop + +# token : category colon +# token | category bar +token != name not_eq translation <"\\I"> category binop +token <= name lt_eq translation <"\\L"> category binop +token >= name gt_eq translation <"\\G"> category binop +token == name eq_eq translation <"\\S"> category binop +token && name and_and translation <"\\W"> category binop +token || name or_or translation <"\\V"> category binop +# token -> name minus_gt translation <"\\MG"> category binop +token ++ name gt_gt category unop translation <"\\uparrow"> +token -- name lt_lt category unop translation <"\\downarrow"> +# preunop is for unary operators that are prefix only +token $ category preunop translation <"\\DO"> mathness yes + +default mathness yes translation <*> + +ilk pattern_like category math +reserved BEGIN ilk pattern_like +reserved END ilk pattern_like + +ilk if_like category if +reserved if +ilk else_like category else +reserved else + +ilk print_like category math +# math forces space between this and other math... +reserved print ilk print_like +reserved printf ilk print_like +reserved sprintf ilk print_like + + +ilk functions category unop mathness yes +reserved length ilk functions +reserved substr ilk functions +reserved index ilk functions +reserved split ilk functions +reserved sqrt ilk functions +reserved log ilk functions +reserved exp ilk functions +reserved int ilk functions + +ilk variables category math mathness yes +reserved NR ilk variables +reserved NF ilk variables +reserved FS ilk variables +reserved RS ilk variables +reserved OFS ilk variables +reserved ORS ilk variables + +ilk for_like category for +reserved for ilk for_like +reserved while ilk for_like + +ilk in_like category binop translation <math_bin-*-"}"> mathness yes +# translation <"\\"-space-*-"\\"-space> +reserved in ilk in_like + +ilk stmt_like category math +reserved break ilk stmt_like +reserved continue ilk stmt_like +reserved next ilk stmt_like +reserved exit ilk stmt_like + + +backslash newline --> math +# The following line must be changed to make a backslash +backslash <"\\backslash"> --> math + +math (binop|unorbinop) math --> math +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +(unop|preunop|unorbinop) math --> math +# unorbinop can only act like unary op as *prefix*, not postfix +math unop --> math +math <"\\"-space> math --> math +# concatenation + +math newline --> stmt +newline --> ignore_scrap + +stmt <force> stmt --> stmt + +(open|lsquare) math close --> math + +math lbrace --> lbrace +lbrace <force> stmt --> lbrace +lbrace <outdent-force> close --> stmt + +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> close else <"\\"-space> if --> if +ifbrace <outdent-force> close else lbrace --> ifbrace +ifbrace <outdent-force> close else newline --> ifline +ifbrace <outdent-force> close --> stmt +(ifline|ifmath) <indent-force> stmt <outdent-force> else <"\\"-space> if --> if +(ifline|ifmath) <indent-force> stmt <outdent-force> else lbrace --> ifbrace +(ifline|ifmath) <indent-force> stmt <outdent-force> else newline --> ifline +(ifline|ifmath) <indent-force> stmt <outdent-force> else --> ifmath +(ifline|ifmath) <indent-force> stmt <outdent> --> stmt + +for <"\\"-space> math --> formath +formath lbrace --> forbrace +formath newline --> forline +forbrace <force> stmt --> forbrace +forbrace <outdent-force> close --> stmt +(forline|formath) <indent-force> stmt <outdent> --> stmt + + +? ignore_scrap --> #1 +\end{verbatim} +\endgroup + + +\newpage +\section{Bibliography} +\begin{thebibliography}{Knuth~999} +\bibitem[Bentley~87]{bentley:pearls} +Jon L. Bentley, ``Programming Pearls,'' {\sl Communications of the +ACM}~{\bf 29:5}(May 1986), 364--?, and {\bf 29:6}(June 1986), +471--483. +ʸ½ñ²½¥×¥í¥°¥é¥ß¥ó¥°¤Ë¤Ä¤¤¤Æ¤Î2¤Ä¤Î¥³¥é¥à¡£ +ºÇ½é¤Î¤â¤Î¤ÏÆþÌçÊÔ¡£ÆóÈÖÌÜ¤Î¤Ï +Donald Knuth ¤Ë¤è¤ë³ÈÄ¥¤µ¤ì¤¿Îã¤Ç +Douglas MacIlroy ¤¬¥³¥á¥ó¥È¤·¤Æ¤¤¤ë¡£ +\bibitem[Knuth~83]{knuth:web} +Donald~E. Knuth, +``The {{\tt WEB}} system of structured documentation'' + Technical Report 980, Stanford Computer Science, Stanford, + California, September 1983. +¥ª¥ê¥¸¥Ê¥ë¤Î {\tt WEB}¤Î¥Þ¥Ë¥å¥¢¥ë¡£ +\bibitem[Knuth~84]{knuth:literate-programming} +Donald E. Knuth, ``Literate Programming,'' {\sl The Computer Journal} +{\bf 27:2}(1984), 97--111. +{\WEB}¤Ë¤è¤ëʸ½ñ²½¥×¥í¥°¥é¥ß¥ó¥°¤Î¥ª¥ê¥¸¥Ê¥ë¤ÎÆþÌç½ñ¡£ +\bibitem[Levy~87]{levy:cweb} +Silvio Levy, ``Web Adapted to C, Another Approach'' {\sl TUGBoat} +{\bf 8:2}(1987), 12--13. +{\WEB}¤ò C ¤Ç¼Â¸½¤¹¤ë¤³¤È¤Ë¤Ä¤¤¤Æ¤Î¾®Êó¹ð½ñ¡£ +¤³¤ì¤«¤é Spidery {\WEB} ¤ÏÇÉÀ¸¤·¤¿¡£ +\bibitem[Sewell~89]{sewell:weaving} +Wayne Sewell, ``Weaving a program: Literate programming in {\tt +WEB},'' +Van Nostrand Reinhold, 1989. +\end{thebibliography} + + +\end{document} diff --git a/web/spiderweb/doc/spe.aux b/web/spiderweb/doc/spe.aux new file mode 100644 index 0000000000..c2471f652f --- /dev/null +++ b/web/spiderweb/doc/spe.aux @@ -0,0 +1,70 @@ +\relax +\citation{knuth:literate} +\citation{bentley:lp1,bentley:lp2,cvw:loom,gries:pearls} +\citation{knuth:tex,knuth:metafont} +\citation{bentley:lp1,bentley:lp2} +\citation{cvw:loom} +\citation{gries:pearls} +\citation{cvw:assessment} +\citation{thimbleby:review} +\citation{knuth:literate,thimbleby:cweb,guntermann:cweb,levy:cweb,sewell:mangle,ramsey:building} +\@writefile{toc}{\string\contentsline\space {section}{Introduction}{2}} +\citation{knuth:literate} +\citation{ramsey:developing,marceau:interactive,guaspari:formal} +\citation{reps:synthesizer:89} +\citation{reps:generating} +\citation{adalrm,polak:predicate} +\citation{marceau:verified,weber:beyond,anderson:asos} +\@writefile{toc}{\string\contentsline\space {section}{Using Literate Programming}{3}} +\citation{polak:predicate,polak:program} +\citation{adalrm} +\citation{ganzinger:operator} +\citation{cvw:assessment} +\citation{thimbleby:review} +\citation{bentley:more-pearls:graphics,bentley:lp2,sedgewick:algorithms} +\@writefile{toc}{\string\contentsline\space {section}{Evaluating {\string\ptt\space WEB}}{5}} +\citation{knuth:tex} +\citation{feldman:make} +\citation{johnson:yacc} +\citation{kernighan:unix} +\citation{ramsey:spiderwebman} +\citation{thimbleby:review} +\citation{parnas:rational} +\@writefile{toc}{\string\contentsline\space {section}{Discussion}{9}} +\citation{reps:synthesizer:89} +\bibstyle{unsrt} +\bibdata{web,ada,cs,ramsey} +\bibcite{knuth:literate}{1} +\bibcite{bentley:lp1}{2} +\bibcite{bentley:lp2}{3} +\bibcite{cvw:loom}{4} +\bibcite{gries:pearls}{5} +\bibcite{knuth:tex}{6} +\bibcite{knuth:metafont}{7} +\bibcite{cvw:assessment}{8} +\@writefile{toc}{\string\contentsline\space {section}{Acknowledgments}{11}} +\bibcite{thimbleby:review}{9} +\bibcite{thimbleby:cweb}{10} +\bibcite{guntermann:cweb}{11} +\bibcite{levy:cweb}{12} +\bibcite{sewell:mangle}{13} +\bibcite{ramsey:building}{14} +\bibcite{ramsey:developing}{15} +\bibcite{marceau:interactive}{16} +\bibcite{guaspari:formal}{17} +\bibcite{reps:synthesizer:89}{18} +\bibcite{reps:generating}{19} +\bibcite{adalrm}{20} +\bibcite{polak:predicate}{21} +\bibcite{marceau:verified}{22} +\bibcite{weber:beyond}{23} +\bibcite{anderson:asos}{24} +\bibcite{polak:program}{25} +\bibcite{ganzinger:operator}{26} +\bibcite{bentley:more-pearls:graphics}{27} +\bibcite{sedgewick:algorithms}{28} +\bibcite{feldman:make}{29} +\bibcite{johnson:yacc}{30} +\bibcite{kernighan:unix}{31} +\bibcite{ramsey:spiderwebman}{32} +\bibcite{parnas:rational}{33} diff --git a/web/spiderweb/doc/spe.bbl b/web/spiderweb/doc/spe.bbl new file mode 100644 index 0000000000..fe18d98426 --- /dev/null +++ b/web/spiderweb/doc/spe.bbl @@ -0,0 +1,186 @@ +\begin{thebibliography}{10} + +\bibitem{knuth:literate} +Donald~E. Knuth. +\newblock Literate programming. +\newblock {\em The Computer Journal}, 27(2):97--111, 1984. + +\bibitem{bentley:lp1} +Donald~E. Knuth and Jon~L. Bentley. +\newblock Programming pearls: Literate programming. +\newblock {\em Communications of the ACM}, 29(5):364--368, May 1986. + +\bibitem{bentley:lp2} +Donald~E. Knuth. +\newblock Programming pearls: A literate program. +\newblock {\em Communications of the ACM}, 29(6):471--483, June 1986. +\newblock Reviewed by M. Douglas McIlroy. + +\bibitem{cvw:loom} +David~R. Hanson. +\newblock Literate programming: Printing common words. +\newblock {\em Communications of the ACM}, 30(7):593--599, July 1987. +\newblock Reviewed by John Gilbert. + +\bibitem{gries:pearls} +David Gries and Jon Bentley. +\newblock Programming pearls: Abstract data types. +\newblock {\em Communications of the ACM}, 30(4):284--290, April 1987. + +\bibitem{knuth:tex} +Donald~E. Knuth. +\newblock {\em {{\TeX}}: The Program}, volume~B of {\em Computers \& + Typesetting}. +\newblock Addison-Wesley, 1986. + +\bibitem{knuth:metafont} +Donald~E. Knuth. +\newblock {\em {{\metafont}}: The Program}, volume~D of {\em Computers \& + Typesetting}. +\newblock Addison-Wesley, 1986. + +\bibitem{cvw:assessment} +Christopher~J. Van~Wyk. +\newblock Literate programming: An assessment. +\newblock {\em Communications of the ACM}, 33(3):361--365, March 1990. + +\bibitem{thimbleby:review} +Harold Thimbleby. +\newblock A review of {Donald} {C}. {L}indsay's text file difference utility, + {{\em diff}}. +\newblock {\em Communications of the ACM}, 32(6):752--755, June 1989. + +\bibitem{thimbleby:cweb} +Harold Thimbleby. +\newblock Experiences of `literate programming' using cweb (a variant of + {K}nuth's {WEB}). +\newblock {\em Computer Journal}, 29(3):201--211, 1986. + +\bibitem{guntermann:cweb} +Klaus Guntermann and Joachim Schrod. +\newblock {{\tt WEB}} adapted to {C}. +\newblock {\em {TUG}boat}, 7(3):134--137, October 1986. + +\bibitem{levy:cweb} +Silvio Levy. +\newblock {\tt WEB} adapted to {C}, another approach. +\newblock {\em TUGBoat}, 8(1):12--13, 1987. + +\bibitem{sewell:mangle} +Wayne Sewell. +\newblock How to {{\tt MANGLE}} your software: the {{\tt WEB}} system for + {M}odula-2. +\newblock {\em {TUG}boat}, 8(2):118--128, July 1987. + +\bibitem{ramsey:building} +Norman Ramsey. +\newblock {L}iterate programming: {\hskip 0pt plus 0.5em}{W}eaving a + language-independent {{\tt WEB}}. +\newblock {\em Communications of the ACM}, 32(9):1051--1055, September 1989. + +\bibitem{ramsey:developing} +Norman Ramsey. +\newblock Developing formally verified {A}da programs. +\newblock In {\em Proceedings of the 5th International Workshop on Software + Specification and Design}, pages 257--265, Pittsburgh, Pennsylvania, May + 1989. + +\bibitem{marceau:interactive} +Carla Marceau and C.~Douglas Harper. +\newblock An interactive approach to {A}da verification. +\newblock In {\em Proceedings of the 12th National Computer Security + Conference}, pages 28--51, Baltimore, Maryland, October 1989. + +\bibitem{guaspari:formal} +David Guaspari, Carla Marceau, and Wolfgang Polak. +\newblock Formal verification of {A}da programs. +\newblock {\em IEEE Transactions on Software Engineering}, 16(9):1058--1075, + September 1990. + +\bibitem{reps:synthesizer:89} +Thomas Reps and Tim Teitelbaum. +\newblock {\em The {S}ynthesizer {G}enerator Reference Manual}. +\newblock Springer-Verlag, 1989. + +\bibitem{reps:generating} +Thomas Reps. +\newblock {\em Generating Language-Based Environments}. +\newblock MIT Press, 1984. + +\bibitem{adalrm} +{US Department of Defense}. +\newblock {\em The {A}da Programming Language Reference Manual}, 1983. +\newblock ANSI/MILSTD~1815A. + +\bibitem{polak:predicate} +Wolfgang Polak. +\newblock Predicate transformer semantics for {A}da. +\newblock Technical Report 89-39, Odyssey Research Associates, September 1989. + +\bibitem{marceau:verified} +Carla Marceau and Geoffrey Hird. +\newblock A verified software implementation of an {RS}-232 repeater using + {P}enelope. +\newblock Technical Report 90-12, Odyssey Research Associates, 1990. + +\bibitem{weber:beyond} +D.~G. Weber and Roger~L. Costello. +\newblock Beyond {A1} using {A}da code verification. +\newblock Technical Report 89-9, Odyssey Research Associates, April 1989. + +\bibitem{anderson:asos} +Eric~R. Anderson, Ben DiVitto, and Ruth~M. Hart. +\newblock {ASOS}: Information security for real-time systems. +\newblock In {\em {AFCEA} West Intelligence Symposium}, 1987. + +\bibitem{polak:program} +Wolfgang Polak. +\newblock Program verification based on denotational semantics. +\newblock In {\em ACM Symposium on Principles of Programming Languages}, pages + 149--158. Association for Computing Machinery, 1981. + +\bibitem{ganzinger:operator} +H.~Ganzinger and K.~Ripken. +\newblock Operator identification in {A}da. +\newblock {\em ACM SIGPLAN Notices}, 15(2):30--42, February 1980. + +\bibitem{bentley:more-pearls:graphics} +Jon Bentley. +\newblock {\em More Programming Pearls: Confessions of a Coder}, chapter 10 and + 11, pages 101--126. +\newblock Addison-Wesley, 1988. + +\bibitem{sedgewick:algorithms} +Robert Sedgewick. +\newblock {\em Algorithms}. +\newblock Addison-Wesley, second edition, 1988. + +\bibitem{feldman:make} +Stuart~I. Feldman. +\newblock Make---a program for maintaining computer programs. +\newblock {\em Software---Practice and Experience}, 9:255--265, 1979. + +\bibitem{johnson:yacc} +Steve~C. Johnson. +\newblock Yacc---yet another compiler compiler. +\newblock Technical Report~32, Computer Science, AT\&T Bell Laboratories, + Murray Hill, New Jersey, 1975. + +\bibitem{kernighan:unix} +Brian~W. Kernighan and Rob Pike. +\newblock {\em The {UNIX} Programming Environment}. +\newblock Prentice-Hall, 1984. + +\bibitem{ramsey:spiderwebman} +Norman Ramsey. +\newblock The {S}pidery {{\tt WEB}} system of structured documentation. +\newblock Technical Report TR-226-89, Department of Computer Science, Princeton + University, August 1989. + +\bibitem{parnas:rational} +David~Lorge Parnas and Paul~C. Clements. +\newblock A rational design process: How and why to fake it. +\newblock {\em IEEE Transactions on Software Engineering}, SE-12(2):251--257, + February 1986. + +\end{thebibliography} diff --git a/web/spiderweb/doc/spe.tex b/web/spiderweb/doc/spe.tex new file mode 100644 index 0000000000..4a4dc42416 --- /dev/null +++ b/web/spiderweb/doc/spe.tex @@ -0,0 +1,545 @@ +\documentstyle[11pt]{article} +\title {Literate Programming on a Team Project\thanks{This research +has been sponsored in part by the USAF, Rome Air Development Center, under +contract number F30602--86--C--0071. +The first author gratefully acknowledges the support of the Fannie and +John Hertz Foundation. +This paper is reprinted from {\em Software---Practice \& Experience}, 21(7):677--683, July 1991.}} +\author{Norman Ramsey\thanks{Current address: Department of Computer +Science, Princeton University, Princeton, New Jersey 08544.} + \hskip3pt and Carla Marceau\\\mbox{}\\Odyssey Research Associates\\ +301A Harris B. Dates Drive\\Ithaca, New York 14850} +\date{February 4, 1991} +\setcounter{secnumdepth}{0} +\setcounter{tocdepth}{6} +\renewcommand{\baselinestretch}{1.33} + +\makeatletter +\def\refno#1{\nocite{#1}\@ifundefined + {b@#1}{{\bf ?}\@warning + {Reference number `#1' on page \thepage \space undefined}}% +{\hbox{\csname b@#1\endcsname}}} +\makeatother + +\def\remark#1{\marginpar{\raggedright\hbadness=10000\footnotesize\it #1}} +% \def\remark#1{\relax} +\let\logo=\sc +\font\logo=logo10 +\def\metafont{{\logo METAFONT}} + + +\begin{document} % 1 +\clubpenalty=10000 +\widowpenalty=10000 +\maketitle + +\begin{abstract} % 2 +% % We used {\tt WEB} on a group project to write a large program, over +% % 33,000~lines. +% % The program was not intended to be published. +% % We encountered many problems using {\tt WEB}, but we believe we are +% % better off for having used it. +% % We describe both the problems and why we believe {\tt WEB} was +% % beneficial despite them. +% We used literate programming, with {\tt WEB}, on a group project to +% write a program of +% over 33,000~lines. +% The program, Penelope, was not intended to be published, but the +% literate source has served as good internal documentation through +% development and maintenance. +% Using {\tt WEB} without help from its developer uncovered a number of +% problems, which are described below. +% Despite the problems, {\tt WEB} has been effective in helping us +% document the design and implementation of Penelope. +We used literate programming on a team project to write a 33,000-line +program for the Synthesizer Generator. The program, Penelope, was +written using {\tt WEB}, a tool designed for writing literate +programs. Unlike other {\tt WEB} programs, many of which have been +written by {\tt WEB}'s developer or by individuals, Penelope was not +intended to be published. We used {\tt WEB} in the hope that +both our team and its final product would benefit from the advantages +often attributed to literate programming. The {\tt +WEB} source served as good internal documentation throughout +development and maintenance, and it continues to document Penelope's +design and implementation. +Our experience also uncovered a number of +problems with {\tt WEB}. +\end{abstract} % 2 + + +\section{Introduction} + +Donald Knuth coined the term ``literate programming'' when describing +{\tt WEB}, the tool he used to build \TeX~\cite{knuth:literate}. +He believes that ``the time is ripe for significantly better +documentation of programs, and that we can best achieve this by +considering programs to be {\em works of literature}.'' +Knuth and others have presented examples of such +programs~\cite{bentley:lp1,bentley:lp2,cvw:loom,gries:pearls}. + + +Literate programming is usually discussed in the context of +publishing programs or of publishing books or articles about programs. +\TeX\ and {\metafont}, the original applications of {\tt WEB}, +have been published as books~\cite{knuth:tex,knuth:metafont}. +Other published literate programs seem to be primarily for teaching. +Programs to find random sequences and count common words +were written to illustrate the power of literate +programming~\cite{bentley:lp1,bentley:lp2}. +Another program to count common words +is a tutorial on how to +develop and tune a small program~\cite{cvw:loom}. +Another illustrates formal methods of program +development and the use of abstract data types~\cite{gries:pearls}. + + +A valedictory assessment points out three common aspects of the published +literate programs: cosmetics, polish, and verisimilitude, of which +verisimilitude---the property of using one input to produce both +compilable program and published document--is deemed +essential~\cite{cvw:assessment}. +Additional expectations of a literate +programming tool include flexible order of elaboration, +ability to develop program and documentation concurrently in one +place, cross-references, and indexing~\cite{thimbleby:review}. + +{\tt WEB} is the principal tool used for literate programming; a +number of implementations are +available~\cite{knuth:literate,thimbleby:cweb,guntermann:cweb,levy:cweb,sewell:mangle,ramsey:building}. +{\tt WEB} programmers + interleave source code and descriptive text in a single document. +When using {\tt WEB}, a programmer divides the source code into +small textual units called {\em modules}, and each module carries +associated documentation. +In the {\tt WEB} source, different modules may +be written in any order. + The programmer is encouraged to choose an +order that helps explain the program. +The modules are like macro definitions; they have +the form +\begin{quote} % 2 +\tt@<{\em module name\/}@>={\em body} +\end{quote} % 2 +where the body contains both code and references to other modules. +{\tt WEB} programmers can also define and use macros similar to +C~preprocessor macros. + One module is unnamed; its body represents the underlying program. + +Two filters process {\tt WEB} source. + {\tt TANGLE} reads the {\tt WEB} source and expands the +unnamed module according to its definition. +References to named modules are expanded where they occur, and the end +result is that {\tt TANGLE} extracts the underlying program from the +{\tt WEB} source. +This program is formed from the code fragments that the programmer put +into the module definitions, assembled in the order required by the compiler. +A second filter, {\tt WEAVE}, reads the {\tt WEB} source and converts +it to \TeX\ input, with which {\TeX} can produce +high-quality typeset documentation of the program. +Examples of {\tt WEB} source and typeset documentation can be found in +Reference~\refno{knuth:literate}. + + +\section{Using Literate Programming} + + Penelope is a language-based editor intended to help +programmers develop formally verified Ada +programs~\cite{ramsey:developing,marceau:interactive,guaspari:formal}. +It parses annotated Ada programs, +performs static semantic checking and overload resolution, +computes weakest preconditions by predicate transformation, +simplifies the resulting preconditions, +and +helps users construct proofs of those preconditions. +Its source code is +an editor specification for +the Synthesizer Generator~\cite{reps:synthesizer:89}. +The Synthesizer Generator builds an editor of attributed syntax +trees. +When a user defines a tree, the editor attributes it. +When the user changes the tree, +the editor recomputes only those attribute values that have +changed~\cite{reps:generating}. + +Penelope has two written specifications: the Ada language +reference manual and a denotational-style definition of Ada predicate +transformers~\cite{adalrm,polak:predicate}. +After three years of work, the {\tt WEB} source for the editor +is over 33,000 lines. +Over 13,000 of those lines are interleaved documentation. +The editor has been used to verify a software repeater for an +asynchronous +communication line +and security properties of a part of the +ASOS operating system +kernel~\cite{marceau:verified,weber:beyond,anderson:asos}. +Seven programmers have written {\tt WEB} source, +but no more than four have worked +on it at any one time. +At this writing, the editor is being extended +to support Ada libraries. % programs that use data abstraction. + +We decided to write the editor as a literate program because +we expected implementing predicate +transformation to be error-prone. +To avoid errors, we used {\tt WEB} to juxtapose +the specification and implementation of +each predicate transformer. +We used {\TeX}'s math mode to write the specifications in the notation +of denotational semantics.~\cite{polak:predicate,polak:program}. + +The right model for a literate program that is being maintained and +extended is not the novel but the car repair manual. +We began writing new code as an +explanation or tutorial for our colleagues, but +as the text grew we treated it more like a reference work. +As with any document, we revised repeatedly to clarify meaning. +We often used +{\tt TANGLE}'s reordering mechanism to make major revisions in the +{\tt WEB} source without changing the underlying program. +% Parnas and Clements say this; see {parnas:rational} + + +We divided Penelope into parts according to functionality: +we wrote chapters on +abstract syntax, +concrete syntax, +predicate transformation, +static semantic checking, +proof construction, +and simplification of terms. +Each of the first four chapters follows the structure of the Ada +Language Reference Manual, since each is closely related to +Ada. +Only knowledge of the Ada manual is required to navigate this code; +a reader who knows where to find the +{\tt exit} statement in the Ada manual can find the predicate +transformation of the {\tt exit} statement in the corresponding +section of the predicate transformation chapter. +We gave the final chapters structures related to the problems of +simplification and proof construction. + + +Penelope has grown so large that each chapter +is itself structured like a reference work. + Sections within chapters have a different structure. +They are tutorials that use the traditional approach +to documentation: begin with a problem statement or specification, +discuss possible solutions, explain the design of the preferred +solution, then develop the implementation and its description. +A short introductory chapter describes the major parts of the program +the organization used to form the text. +A ``how to find it'' section helps readers find source code. + +We have used the Penelope source +not only for reference but also to introduce new programmers to the +project. % ??? +% For example, as a prelude to extending the +% Ada subset handled by Penelope, a new project member might read Chapter +% 6 of the Red Dragon Book and also the chapter of Penelope on static +% semantic checking. + + + + +We used some of the cosmetic features of {\tt WEB}; +we found +tables of variables, functions, and files all useful to describe the +organization of the code. +When working on Ada static semantic checking, we found it useful to +include in the {\tt WEB} source some fragments of relevant documents. +The fragments included visibility and overloading rules from the Ada reference +manual~\cite{adalrm} and a presentation of the Ada type system derived +from Reference~\refno{ganzinger:operator}. + + +\section{Evaluating {\tt WEB}} + + Using {\tt WEB} without help from its developer uncovered a number of +problems. +Some problems relate to the criteria in References +\refno{cvw:assessment}~and~\refno{thimbleby:review}, but others do not. + +We had no trouble with +{\tt WEB}'s fundamental mechanisms, the section and +the named module. +They provide verisimilitude and flexible order of elaboration. +The small size of modules makes it feasible to develop code and +documentation in one place using an ordinary text editor. +The order of fragments is the same in the {\tt WEB} source and in the +published document, which simplifies polishing. + +\medskip +We found some of {\tt WEB}'s cosmetic features inadequate, others +superfluous. +Cosmetics should include appropriate media for presenting programs: +not just math and tables but also diagrams and +figures~\cite{bentley:more-pearls:graphics,bentley:lp2,sedgewick:algorithms}. + Describing data structures was hampered by {\TeX}'s lack of support for +diagrams and pictures. +{\TeX} does make it easy to use mathematical notation, which + helped considerably in describing + predicate transformation, + the simplifier, and + the proof system used in the proof constructor. + +Programmers complained more about prettyprinting than about all other {\tt WEB} +problems combined. +{\tt WEAVE} ignores the programmer's choice of indentation +and line breaks; it breaks and indents lines on the basis of +the syntactic categories of tokens. +(Programmers can force line breaks by inserting special control sequences +like {\tt@/} into their program text, but that's about all.) +We spent too much time tinkering +with prettyprinting, trying to make {\tt WEAVE}'s output +acceptable to everyone. +We would have been better off with no prettyprinter, or with a +prettyprinter that changed +only the typographic treatment of program fragments without changing +the placement of tokens on the page. + +We used the index of identifiers + during reviews only, usually to find function definitions +and to locate code that had been misplaced. + +\medskip +{\tt WEB} formats interleaved documentation using {\TeX}, which some +programmers already use for writing documents. +{\tt WEB} and {\TeX} are integrated poorly. +One cannot lift pieces of {\tt WEAVE}'s output and put them in other +documents without adjusting the \TeX\ code. +{\tt WEB} works even less well with \LaTeX; \LaTeX\ constructs cannot +be used in {\tt WEB} source, and getting {\tt WEAVE} output +to work in \LaTeX\ documents requires tedious adjustments by hand. +The other direction is easier; +we wrote project documents using \LaTeX, and, with some adjustments, +we could include excerpts from these documents in our code. +%%%%%%%% Carla wants no more details +% \remark{I can give more details. For example, the {\tt webmac} macros +% should make it easy to pull out the {\tt WEAVE} output routine and use +% a plain \TeX\ or \LaTeX output routine---but they don't. +% This is a sore point with me.} +%%%%%%%%% + We were accustomed to writing \LaTeX\ documents, +so it was annoying to be forced to switch to plain +\TeX\ to write programs. + +% \paragraph{Editing {\tt WEB} source} +\medskip + +\TeX's input often looks very different from \TeX's output, especially +when mathematics is used. +Similarly, {\tt WEB} source looks very different from the typeset +document produced by {\tt WEAVE} and {\TeX}. +When people use \TeX\ to write papers, +it may be acceptable for the \TeX\ input to be full of +confusing hieroglyphics, because the {\TeX} input is almost never +read---only the printed version is read. +{\tt WEB} source is read frequently because programmers must edit it. +Both the difficulty of reading the source and the marked difference between +source and listing complicate editing. + +\medskip % \paragraph{Structuring the document} + +{\tt WEAVE}'s standard table of contents mechanism is a list of +section names. + (A section is a named group of modules together with their +interleaved documentation.) +This flat structure is inadequate for +describing even a moderate-sized program. +Extra structure in the form of ``parts'' has been added to +the book version of {\TeX}; a part contains several +sections~\cite{knuth:tex}. + + +We changed {\tt WEAVE}'s table of contents mechanism to make +hierarchical organization possible. + The new mechanism supports +chapters, sections, and two levels of subsections. +We did so without changing {\tt WEAVE} itself; instead we changed the +\TeX\ macros that support {\tt WEAVE}. +The new macros recognize special symbols at the beginnings of section +names; these symbols indicate which sections are really chapters, +subsections, and so on. +Using this hierarchy made the table of contents +an important guide to the code; +the only practical way to find a particular part of the editor code +was to begin with the table of contents. + + + + +The {\tt WEAVE} listing of Penelope is over 800~pages; +its table of contents is about 8~pages. +We needed to extract and print parts of this document, +but {\tt WEAVE} processes only complete documents. +We extracted parts in two ways. +When we wanted just a few, small, closely related parts, we created a +special {\tt WEB} file that held just those parts, and printed it. +For something more general, we used a shell script that +removed parts of {\tt WEAVE}'s output before passing the rest to {\TeX}. +This script recognized the special symbols in the section names so that, for +example, we could include or exclude whole chapters by name, +without having to +enumerate their contents. +It would have been more expensive, and no less awkward, to use +standard mechanisms for extracting pages from {\TeX}'s output. + +Special symbols in section names are an awkward way of indicating +structure. + A more natural way of indicating structure, like the +{\LaTeX} mechanism, would have been welcome. +Tools should make it easy to use the + structure to help readers extract excerpts from literate +programs. + +\medskip % \paragraph{Fit with configuration management tools} + + {\tt WEB} works poorly with {\tt make}~\cite{feldman:make}. + {\tt TANGLE} is designed to read and write a complete program. +Some {\tt TANGLE}s can write multiple files, +which can then be compiled separately, but +those files all get rewritten + every time the {\tt WEB} source changes, +and {\tt make} therefore recompiles them all. +This problem is familiar; +other preprocessors, like {\tt yacc}~\cite{johnson:yacc}, can also +cause excessive recompilation. +The workaround described on page 265 of +Reference~\refno{kernighan:unix} works for {\tt TANGLE}. +%%%%%%%% Carla wants no more details +% \remark{Workaround doesn't help too much when the output +% from {\tt TANGLE} includes information about source line numbers?} +%%%%%%%%% + +{\tt WEB} users may be tempted +to break their {\tt WEB} source into many files and run them through +{\tt TANGLE} separately. +Doing so defeats the purpose of writing a literate +program; separate compilation does not necessarily imply separate +explanation. +For example, one would prefer to place a +unit's specification and implementation in the same {\tt WEB} +source, even when +they should be compiled separately. + +\medskip % \paragraph{Fit with compilers and debuggers} + +Our {\tt TANGLE}~\cite{ramsey:spiderwebman} emits +the {\tt\#line} directive of the C preprocessor, making +messages from compilers and debuggers refer to line numbers in +the {\tt WEB} source instead of to those in {\tt TANGLE}'s output. +Not all compilers or all {\tt TANGLE}s support such mechanisms. +Renumbering is essential for large programs. + + + + + +\section{Discussion} + +Most literate programming papers refer to programs that are +polished, publishable ``works of art.'' +Our primary goal in writing Penelope +was not to write a publishable program, nor to +evaluate literate programming as a software engineering technique, +but to build a prototype editor embodying the results +of research in formal verification. +Our experience has given us some subjective +impressions of the benefits of applying literate programming +to team development, as well as more specific conclusions about +the difficulties of applying literate programming. + +There are few published techniques for writing literate +programs, especially for writing large ones. +Most of our programmers complained about the awkward tools and about +the lack of guidance in their use. +We were unable to develop precise methods for writing literate +programs or even clear criteria about what constituted a +literate program. +Instead, we relied on peer review of programs, rewriting them +until the project members understood them. +These programs were rarely polished to the point necessary for +publication; less polished presentations were adequate. + +One review of a literate program emphasizes the role of +juxtaposed code and documentation~\cite{thimbleby:review}. +It cites several benefits of this juxtaposition, including an +incentive to explain and hence to understand what one is doing. +During peer reviews of Penelope, +we insisted that explanations of programs include explanations of design. +% this insistence mitigated against the +% tendency of programmers to begin implementing without thinking about +% design. +% We found that +% the juxtaposition reduced the overhead +% involved in maintenance; +Juxtaposing design documentation and code reduced the overhead of +maintenance because maintainers reading the code did not have to look +elsewhere for design documents. + +We cannot say to what extent literate programming can replace +standard software development methodology. However, putting a +clear description of design in our source code helped make it possible +for a changing team of programmers to develop it over a span of three +years. We were able to apply standard guidelines, like those in +Reference~\refno{parnas:rational}, to describing Penelope's design. + +We believe +literate programming helped us substantially. +This belief is based not on measurements but on our subjective +comparisons of experience on this project to other projects. +A programmer who has used standard software development systems at an +international computer manufacturing company reports that a key +difference in Penelope was that the documentation was {\em used}, precisely +because of its proximity to the source code. +The project manager, when at a large software house, +learned to expect technical staff first to criticize +implementations +for drifting away from the original intent, then to +call for complete rewrites. +There have been no complaints about the quality of Penelope's +implementation. +The programmers have been surprised at how easily they have extended +and modified one another's work. +For example, an editor for constructing proofs was implemented by a +programmer who then left the project. +The programmer who took over the job of maintaining the proof +constructor read the program in two hours and found herself well +prepared to change the code. + +We do not ascribe Penelope's success purely to literate programming; +other factors contributed. +We began implementation with a clearly defined +goal and worked from detailed, sometimes formal, specifications. +We had time to design the system carefully and used a declarative +programming language. +We did not have to develop a user interface but used the one provided +by the Synthesizer Generator~\cite{reps:synthesizer:89}. + + +We will continue to use literate programming +for Penelope and for future projects. +{\tt WEB}'s problems are such that we believe it will be +cost-effective for future projects to develop literate programming +tools that address some of the criticisms presented here. + + +\section{Acknowledgments} +Silvio Levy provided his {\tt CWEB} implementation as a base for the +{\tt WEB} used to implement the Penelope editor. +The staff of the Ada Verification project at Odyssey Research made +possible the experience with Penelope on which this paper is based. +This paper has been much improved by comments from David Hanson and +from the anonymous referees. +Stuart Feldman commented on this paper and discussed ideas for better +tools. + +\bibliographystyle{unsrt} +\bibliography{web,ada,cs,ramsey} + +%\newpage +%\tableofcontents + +\end{document} % 1 + diff --git a/web/spiderweb/doc/spiderman.aux b/web/spiderweb/doc/spiderman.aux new file mode 100644 index 0000000000..a5db7cabc5 --- /dev/null +++ b/web/spiderweb/doc/spiderman.aux @@ -0,0 +1,56 @@ +\relax +\citation{knuth:literate-programming} +\citation{levy:cweb} +\citation{knuth:literate-programming} +\citation{sewell:weaving} +\@writefile{toc}{\string\contentsline\space {section}{Introduction}{1}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Prerequisites}{2}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Plan of this guide}{2}} +\@writefile{toc}{\string\contentsline\space {section}{How {\string\ptt\space WEAVE} and {\string\ptt\space TANGLE} see the world}{2}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Lexical analysis in {{\string\ptt\space WEB}}}{2}} +\@writefile{toc}{\string\contentsline\space {section}{Using {Spider} to tell {{\string\ptt\space WEB}} how to tokenize}{4}} +\@writefile{toc}{\string\contentsline\space {section}{Using {Spider} to tell {\string\ptt\space WEAVE} how to reduce scraps}{5}} +\@writefile{toc}{\string\contentsline\space {section}{Syntax of {\string\ptt\space spider} files}{6}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Comments and blank lines}{6}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Fields}{6}} +\@writefile{toc}{\string\contentsline\space {subsection}{Translations}{7}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Restricted translations}{8}} +\@writefile{toc}{\string\contentsline\space {subsection}{{\string\ptt\space token} commands}{8}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Token descriptions}{8}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Token designators}{9}} +\@writefile{toc}{\string\contentsline\space {subsection}{Reserved word tokens}{11}} +\@writefile{toc}{\string\contentsline\space {section}{Syntax of the prettyprinting grammar}{11}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Matching the left hand side of a production}{12}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Firing a production}{13}} +\@writefile{toc}{\string\contentsline\space {subparagraph}{Side effects of firing a production}{13}} +\@writefile{toc}{\string\contentsline\space {paragraph}{If no initial subsequence matches any production}{13}} +\@writefile{toc}{\string\contentsline\space {section}{Examples of {\string\ptt\space WEAVE} grammars}{13}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Short examples}{14}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Expressions}{14}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Conditional statements}{16}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Handling preprocessor directives in C}{16}} +\@writefile{toc}{\string\contentsline\space {subsection}{Using context-dependent productions}{17}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Underlining the index entry for the name of a declared function}{17}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Conditional expressions}{17}} +\@writefile{toc}{\string\contentsline\space {subsection}{Debugging a prettyprinting grammar}{18}} +\@writefile{toc}{\string\contentsline\space {section}{The rest of the {Spider} language}{18}} +\@writefile{toc}{\string\contentsline\space {subsection}{Naming the target language}{19}} +\@writefile{toc}{\string\contentsline\space {subsection}{Defining {T\kern -.1667em\lower .5ex\hbox {E}\kern -.125emX} macros}{19}} +\@writefile{toc}{\string\contentsline\space {subsection}{Setting default token information}{20}} +\@writefile{toc}{\string\contentsline\space {subsection}{Specifying the treatment of modules}{20}} +\@writefile{toc}{\string\contentsline\space {subsection}{Determining the at sign}{20}} +\@writefile{toc}{\string\contentsline\space {paragraph}{Changing control sequences}{21}} +\@writefile{toc}{\string\contentsline\space {subsection}{Comments in the programming language}{21}} +\@writefile{toc}{\string\contentsline\space {subsection}{Controlling line numbering}{22}} +\@writefile{toc}{\string\contentsline\space {subsection}{Showing the date of generation}{22}} +\@writefile{toc}{\string\contentsline\space {section}{Spider's error messages}{23}} +\@writefile{toc}{\string\contentsline\space {section}{{Spider}'s output files}{24}} +\@writefile{toc}{\string\contentsline\space {section}{Using {Spider} to make {{\string\ptt\space WEB}} (the {Spider} tools)}{24}} +\@writefile{toc}{\string\contentsline\space {section}{Getting your own Spidery {\string\ptt\space WEB}}{29}} +\@writefile{toc}{\string\contentsline\space {section}{A real {Spider} file}{29}} +\bibcite{bentley:pearls}{Bentley\penalty \@M \ 87} +\bibcite{knuth:web}{Knuth\penalty \@M \ 83} +\bibcite{knuth:literate-programming}{Knuth\penalty \@M \ 84} +\@writefile{toc}{\string\contentsline\space {section}{Bibliography}{33}} +\bibcite{levy:cweb}{Levy\penalty \@M \ 87} +\bibcite{sewell:weaving}{Sewell\penalty \@M \ 89} diff --git a/web/spiderweb/doc/spiderman.tex b/web/spiderweb/doc/spiderman.tex new file mode 100644 index 0000000000..e59087373d --- /dev/null +++ b/web/spiderweb/doc/spiderman.tex @@ -0,0 +1,1693 @@ +% Copyright 1989 by Norman Ramsey and Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +% spiderman.tex, with apologies to Stan Lee + +\documentstyle[11pt]{article} +\setcounter{secnumdepth}{0} +\newcommand{\syntax}[1]{\mbox{$\langle\hbox{\sl #1\/}\rangle$}} +\newcommand{\produces}{\mbox{${}::={}$}} +\newcommand{\opt}[1]{$[$#1$]$} +\newcommand{\BS}{\relax} +\chardef\BS=`\\ % backslash in a string + +\title{A {Spider} User's Guide} +\author{Norman Ramsey\\Department of Computer Science\\Princeton University} +\date{July 1989} +\newcommand {\WEB}{{\tt WEB}} + +\begin{document} +\maketitle + +\section{Introduction} +Donald Knuth developed the {\tt WEB} system of structured documentation +as part of the {\TeX} project~\cite{knuth:literate-programming}. +{\WEB} enables a programmer to divide his or her program into chunks (called +{\em modules}), to associate text with each chunk, and to present the +chunks in in any order. +In Knuth's implementation, the chunks are pieces of PASCAL programs, +and the chunks are formatted using {\TeX}. + + The {\tt WEB} idea suggests a way of combining {\em any} +programming language with {\em any} document formatting language, +but until recently there was no software support for writing anything +but PASCAL programs using {\tt WEB}. +In~1987, Silvio Levy rewrote the {\tt WEB} system in C for C, +while retaining {\TeX} as the formatting language~\cite{levy:cweb}. +I have has modified Levy's implementation by removing the parts +that make C the target programming language, and I have + added a third tool, {Spider}, which complements {\tt WEAVE} +and {\tt TANGLE}. +{Spider} reads a description of a programming language, and writes +source code for a {\tt WEAVE} and {\tt TANGLE} which support that +language. +Using {Spider}, a C~compiler, and an Awk~interpreter, an experienced +systems programmer can generate a {\tt WEB} system for +an Algol-like language in a few hours. + +This document explains how to use {Spider} to generate a {\WEB} +system for any programming language. +(The choice of programming language is limited only by the lexical +structure built into Spidery {\tt WEB}, as we shall see.) +You should consult the companion document, ``The Spidery {\WEB} system of +structured documentation,'' to learn how to use the generated {\WEB} system. + +\paragraph{Prerequisites} +If you are going to use {Spider} to build a {\WEB} system, +you should be comfortable using {\tt WEB}. +To get an idea how {\tt WEB} works, you should have read Knuth's +introductory article +on {\WEB}~\cite{knuth:literate-programming}, as well as the {\WEB} +users' manual. +(The {\WEB} user's manual is pretty heavy going, so you may want to +consult the Bibliography for more introductory material on {\WEB}. +Wayne Sewell's {\it Weaving a Program: Literate Programming in {\tt +WEB}} +may be helpful~\cite{sewell:weaving}.) + +In what follows we will assume that you know what {\tt WEAVE} and {\tt +TANGLE} are, what input they expect, and what output they produce. + +\paragraph{Plan of this guide} +We'll begin with a review of weaving and tangling, so that we can get +an idea what is necessary to build a language-independent {\WEB}. +Then we'll present a discussion of the features of {Spider} that +tell {\WEB} about the programming language. +We'll define these in detail and give some examples, and then +we'll close with a complete description of the {Spider} language +and tools. + +\section{How {\tt WEAVE} and {\tt TANGLE} see the world} +Both {\tt WEAVE} and {\tt TANGLE} operate on the same input, a {\WEB} +file. +{\tt WEAVE} must examine this input and produce a {\TeX} text, while +{\tt TANGLE} must produce a program text from the same input. +The input consists of {\TeX} parts, definition parts, and code parts. +The {\TeX} parts are the easiest to consider: {\tt WEAVE} just copies +them and {\tt TANGLE} throws them away. +The definition parts are a bit more complicated: {\tt WEAVE}'s job is +to typeset them, while {\tt TANGLE} must remember the definitions and +expand them at the proper time. +The code parts are the most complex of all: {\tt WEAVE} must +prettyprint them, and {\tt TANGLE} must rearrange them into a coherent +program text. + +\paragraph{Lexical analysis in {\WEB}} +Both {\tt WEAVE} and {\tt TANGLE} interpret the code parts as a stream +of {\em tokens}. +Since not all programming languages have the same tokens, it is +{Spider}'s job to tell {\tt WEAVE} and {\tt TANGLE} how to tokenize the +input.% +\footnote{% +The current implementation of {\tt WEB}'s lexical analysis is limited. +It should be replaced with something using regular +expressions.% +} +A Spidery {\WEB} system can recognize the following kinds of +tokens: +\begin{itemize} +\item identifiers +\item numeric and string constants +\item newlines +\item ``pseudo-semicolons'' (the token {\tt @;}) +\item reserved words +\item non-alphanumeric tokens +\end{itemize} + +{\tt TANGLE} rearranges these tokens into one long program +text, then writes out the program text token by token. +Normally, {\tt TANGLE} puts no white space between tokens, but it +will put blanks between adjacent identifier, reserved word, and +numeric constant tokens. +Thus the input +\begin{quote} +\tt if 0 > x-y then z := -1; +\end{quote} +will be written out as +\begin{quote} +\tt if 0>x-y then z:=-1; +\end{quote} +and not +\begin{quote} +\tt if0>x-ythenz:=-1; +\end{quote} +which wouldn't parse. +When it is desirable to have {\tt TANGLE} translate +the tokens differently, each token can be given a {\tt tangleto} +attribute, which specifies what program text is printed out for that +token. +For example, +the {\tt spider} file used to generate C~{\WEB} forces the {\tt =} +tokento be printed out as the string {\tt "=\ "}, because in C the string +{\tt "=-"} can be ambiguous. + +{\tt WEAVE} must turn the token stream into a {\TeX} text that will +cause the code to be prettyprinted. +It does so in three steps: +\begin{enumerate} +\item +{\tt WEAVE} turns each token into a {\em scrap}. +A scrap has two important properties: its syntactic +{\em category} and its {\em translation}. +The categories are symbols in a prettyprinting grammar; that grammar +tells {\tt WEAVE} how to combine the scraps +with prettyprinting instructions. +The translations are the {\TeX} texts that will tell {\TeX} exactly +how to print the scraps. +\item +{\tt WEAVE} reduces the scrap stream by combining scraps according to +the productions of its prettyprinting grammar. +({\tt WEAVE} does a kind of shift-reduce parsing of program fragments.) +While combining the translations, {\tt WEAVE} adds {\TeX} text that +will cause indenting, outdenting, line breaking, and so on. +\item +Ideally, {\tt WEAVE} keeps reducing scraps until it has a single scrap with +a very long translation, but perhaps it will end up +with an irreducible sequence of scraps. +In any case, after no more reductions can be done, the translations of the +remaining scraps are output one at a time. +\end{enumerate} + +\section{Using {Spider} to tell {\WEB} how to tokenize} +{Spider} divides tokens into two classes; reserved words and +other. +The reserved words as specified using the {\tt reserved} and {\tt ilk} +commands; the other tokens are specified using the {\tt token} +command. +(This somewhat unusual setup is dictated by the way {\tt +WEAVE} works; its advantage is that is is easy to define a whole group +of reserved words that will be treated identically.) +Here's how it works: the {\tt reserved} command designates + a particular identifier as a reserved word, and says +what {\em ilk} it belongs to. +The {\tt token} and {\tt ilk} commands tell {\tt WEAVE} and {\tt +TANGLE} what to do with a particular token, or with all the reserved +words of a particular ilk. +For each token or ilk one can specify the {\em tangleto} field, the +token's {\em mathness} (whether it has to be typeset in math mode), and +its {\em category} and {\em translation} (for conversion to scraps). +All but the category can have defaults, set with the {\tt defaults} +command. +Choice of category names is up to the user. + +We will discuss the tokenization commands more later when we present +the syntax of {Spider} in detail. +Meanwhile, +here are some example tokenization commands from the {\tt spider} file +for~C: +\begin{verbatim} +token + category unorbinop +token - category unorbinop +token * category unorbinop +token = category equals translation <"\\leftarrow"> tangleto <"="-space> +token ~ category unop translation <"\\TI"> +token & category unorbinop translation <"\\amp"> +token ^ translation <"\\^"> category binop +token ? translation <"\\?"> category question +token % translation <"\\%"> category binop +token # translation <"\\#"> category sharp +token ! category unop translation <"\\neg"> +token ( category lpar +token ) category rpar +token [ category lpar +token ] category rpar +token { translation <"\\{"> category lbrace +token } translation <"\\}"> category rbrace +token ++ category unop translation <"\\PP"> +token -- category unop translation <"\\MM"> +token != translation <"\\I"> category binop +token == translation <"\\S"> category binop +token && translation <"\\W"> category binop + +ilk case_like category case +ilk int_like category int + +reserved auto ilk int_like +reserved break ilk case_like +reserved case ilk case_like +reserved char ilk int_like +\end{verbatim} +These show the definitions of some of the tokens used in C. +Notice the {\tt tangleto} option is almost always left to default, and +the {\tt translation} option is often left to default. + +Once the tokens are specified, and each has a {\tt tangleto} string, +we can almost construct a {\tt TANGLE} for the language. + Before we can construct a {\tt WEAVE}, we have to tell it how to +combine and reduce scraps. + +\section{Using {Spider} to tell {\tt WEAVE} how to reduce scraps} +The most intricate part of {\tt WEAVE} is its mechanism for converting +programming language code into \TeX\ code. +{\tt WEAVE} uses a simple bottom-up parsing algorithm, since it + must deal with fragmentary +constructions whose overall ``part of speech'' is not known. + +The input is represented as a sequence of {\em scraps}, +where each scrap of information consists +of two parts, its {\em category} and its {\em translation}. +The category +is essentially a syntactic class, and the translation 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 +program 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 find 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\,$, et cetera. + +A production applies if the category codes have a given pattern. For +example, if one of the productions is +$$\hbox{\tt open [ math semi <"\BS\BS,"-opt-5> ] --> +open math}$$ +then it means that three consecutive scraps whose respective categories are +{\tt open}, {\tt math}, and {\tt semi} are con\-verted to two scraps whose categories +are {\tt open} and {\tt math}. + The {\tt open} scrap has not changed, while the string +{\tt <"\BS\BS,"-opt-5>} +indicates that the new {\tt math} scrap +has a translation composed of the translation of the original +{\tt math} scrap followed by the translation of the {\tt semi} scrap followed +by `{\tt \BS,}' followed by `{\tt opt}' followed by `{\tt5}'. (In the \TeX\ file, +this will specify an additional thin space after the semicolon, followed +by an optional line break with penalty 50.) +Translations are enclosed in angle brackets, and may contain quoted +strings (using the C conventions to escape backslashes and so on), or +may contain special keywords. + +Before giving examples of useful productions, we'll break to give the +detailed syntax of the {Spider} subset covered so far. + + + +\section{Syntax of {\tt spider} files} + +{Spider} is an Awk program which converts a description of a +language into C~code for {\tt WEAVE} and {\tt TANGLE}. +Since {Spider} is an Awk program, its input is a sequence of +lines, and all {Spider} commands must fit on one line. + +\paragraph{Comments and blank lines} +Because {\em any} character sequence can be a token of a programming +language, we can't just designate a particular sequence as a ``begin +comment'' marker. +So in {Spider} there are no comments, only {\em comment lines}. +A comment line is one whose first character is ``{\tt \#}''. +The {Spider} processor ignores comment lines and blank lines. + +\paragraph{Fields} +Each command in the {\tt spider} file consists of a sequence of {\em +fields}. +These are just the Awk fields, and they are separated by white space. +This feature of {Spider} (inherited from Awk) forbids the use of +white space within a field. + +\subsection{Translations} +Most fields in a {Spider} file are simple identifiers, or perhaps +strings of non-alphanumeric characters. +The major exception is {\em translations}. +Translations are always surrounded by angle brackets ({\tt <>}), +and consist of a (possibly empty) list of translation pieces. +The pieces on a list are separated by dashes ({\tt -}). +A piece is one of: +\begin{itemize} +\item A quoted string. +This string may contain embedded quotes escaped by ``\verb+\+'', but +it {\em must not} contain embedded white space or an embedded dash. +\item The ``self'' marker, ``{\tt *}'', + refers to the sequence of characters making up the token being +translated. +The self marker is permitted only in certain contexts, and its precise +meaning depends on the context. +\item A digit. +\item A key word. +The key words known to {Spider} are +\begin{description} +\item [\tt space] Stands for one space ({\tt "\ "}). +\item[\tt dash] Stands for a dash ({\tt "-"}). +\end{description} +The other key words are passed on to {\tt WEAVE}. + +{\tt WEAVE} recognizes the following key words: +\begin{description} +\item[\tt break\_space] denotes an optional line break or an en space; +\item[\tt force] denotes a line break; +\item[\tt big\_force] denotes a line break with additional vertical space; +\item[\tt 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$; +\item[\tt backup] denotes a backspace of one em; +\item[\tt cancel] obliterates any {\tt break\_space} or {\tt force} or +{\tt big\_force} +tokens that immediately precede or follow it and also cancels any +{\tt backup} tokens that follow it; +\item[\tt indent] causes future lines to be indented one more em; +\item[\tt outdent] causes future lines to be indented one less em. +\item[\tt math\_rel] translates to \verb+\mathrel{+ +\item[\tt math\_bin]translates to \verb+\mathbin{+ +\item[\tt math\_op] translates to \verb+\mathop{+ +\end{description} +The {\em only} key words that will work properly in math mode are {\tt +indent} and {\tt outdent}, so when you're defining the translations of +tokens you must use {\tt mathness~no} if your translations contain +other key words. +You may use any recognized key words in the translations of a +production; there the mathness is automatically taken care of for you. +\end{itemize} + +Here are some example translations: +\begin{verbatim} +<"\\"-space> +<indent-force> +<"{\\let\\\\=\\bf"-space> +<"}"-indent-"{}"-space> +\end{verbatim} + +\paragraph{Restricted translations} +In some cases, notably for a {\tt tangleto} description, translations +are {\em restricted}. +A restricted translation is never converted to typesetting code, +but is always converted to an ASCII string, usually for output by {\tt +TANGLE}, but sometimes for other things. +A restricted translation may contain only {\em quoted strings} and the +keywords {\tt space} and {\tt dash}. + + +\subsection{{\tt token} commands} +The syntax of the {\tt token} command is: +\begin{quote} +\tt +\syntax{command} \produces~token \syntax{token-designator} +\syntax{token-descriptions} +\end{quote} +Where \syntax{token-descriptions} is a (possibly empty) list of token +descriptions. + +\paragraph{Token descriptions} +The token descriptions are +\begin{itemize}\parindent=0pt +\item +{\tt tangleto \syntax{restricted translation}} + +The \syntax{restricted translation} tells {\tt TANGLE} what program +text to write out for this token. +The only kinds of translation pieces valid in a restricted translation +are quoted strings and the special words {\tt space} and {\tt dash}. +If no {\tt tangleto} description is present, {\tt TANGLE} just writes +out the sequence of characters that constitute the token. + +\item +{\tt translation \syntax{translation}} + +Tells {\tt WEAVE} what translation to assign when making this token into +a scrap. +The self +marker~({\tt*}) stands for the sequence of characters that were read in to +make up the token. +The translation often defaults to \verb+translation <*>+; {Spider} +is set up to have this default initially. + +\item +{\tt category \syntax{category-name}} + +Tells {\tt WEAVE} what category to assign when making this token into +a scrap. +If you're writing a {Spider} file, you may choose any category +names you like, subject only to the restriction that they not conflict +with other names known to {Spider} (e.g.~predefined key words, +names of ilks, and so on). +Using category names that are identical to reserved words of the +target programming language (or reserved words of~C) is not only +supported, it is strongly encouraged, for clarity. +Also, when we get to the sample grammars later on, you will see some +other conventions we use for category names. + +\item +{\tt mathness \syntax{mathness-indicator}} + +where \syntax{mathness-indicator} is {\tt yes}, {\tt no}, or {\tt +maybe}. +This indicates to {\tt WEAVE} whether the translation for this token +needs to be typeset in {\TeX}'s math mode or not, or whether it +doesn't matter. +When firing productions, +{\tt WEAVE} will place math shift characters~(\verb+$+) in the {\TeX} +text that guarantee the placement of tokens in the correct modes. +Tokens with the {\em empty translation} (\verb+<>+) should always have +{\tt mathness maybe}, lest they cause {\tt WEAVE} to place two +consecutive math shift characters. + +\item +{\tt name \syntax{token-name}} + +This should only be necessary in debugging {Spider} or {\WEB}. +It causes the specified name to be attached to the token, so that a +programmer can search for that name in the C~code generated by +{Spider}. + +\end{itemize} + +\paragraph{Token designators} +{Spider} recognizes the following token designators: +\begin{description} +\item[{\tt identifier}] +A {\tt token} command using this designator tells {\tt WEAVE} and {\tt +TANGLE} what to do with identifier tokens. +Unfortunately it is not possible to specify with {Spider} just +what an identifier is; that definition is hard-wired into {\tt WEAVE} +and {\tt TANGLE}. +An identifier is the longest string matching this regular expression% +\footnote{The reader unfamiliar with the Unix notation for regular +expressions should consult the {\it ed(1)} man page.}: +\begin{verbatim} +[a-zA-Z_][a-zA-Z0-9_]* +\end{verbatim} + +\item[{\tt number}] +In the current implementation of {Spider} and {\tt WEAVE}, a {\tt token} +command using this designator covers the treatment of both numeric +constants and string constants. +Like the identifiers, the definitions of what constitutes a numeric or +string constant cannot be changed. +{\samepage +A numeric constant is the longest string matching% +\footnote{There ought to be some kind of {\WEB} control sequence to +support floating point notation for those languages that have it.}: +\begin{verbatim} +[0-9]+(\.[0-9]*)? +\end{verbatim} +} +A string constant is the longest string matching +\begin{verbatim} +\"([^"]*\\\")*[^"]*\"|'[^@\]'|'\\.'|'@@' +\end{verbatim} +Carriage returns may appear in string constants if escaped by a +backslash~(\verb+\+). + +\item[{\tt newline}] +A {\tt token} command using this descriptor tells {\tt WEAVE} and {\tt +TANGLE} how to treat a newline. +We'll see later how to make {\tt WEAVE} ignore newlines. + +\item[{\tt pseudo\_semi}] +A {\tt token} command using this descriptor tells {\tt WEAVE} what to +do with the {\WEB} control sequence {\tt @;}. +This control sequence is always ignored by {\tt TANGLE}. + +\item[\syntax{characters}] +where none of the characters is alphanumeric. +A {\tt token} command using this descriptor defines the sequence of +characters as a token, and tells {\tt WEAVE} and {\tt TANGLE} what to +do with that token. +A token may be a prefix of another token; {\tt WEAVE} and {\tt TANGLE} +will prefer the longer token to the shorter. +Thus, in a C~{\WEB}, \verb+==+ will be read as a single \verb+==+ +token, not as two \verb+=+ tokens. +\end{description} + + + + +\subsection{Reserved word tokens} +Reserved words are attached to a particular {\em ilk} using the {\tt +reserved} command. +\begin{quote} +\tt reserved \syntax{reserved-word} $[$ilk \syntax{ilk-name}$]$ +\end{quote} +If you're writing a {Spider} file, you may choose any ilk +names you like, subject only to the restriction that they not conflict +with other names known to {Spider} (e.g.~predefined key words, +names of categories, and so on). +The convention, however, is to use ilk {\tt with\_like} for a reserved +word {\tt with}, and so on.% +\footnote{% +The existence of this convention seduced me into adding a pernicious +feature to {Spider}---if you omit the ilk from a {\tt reserved} +command, {Spider} will make an ilk name by appending {\tt \_like} +to the name of the reserved word. +Furthermore, if that ilk doesn't already exist, {Spider} will +construct one. +Don't use this feature. +} + +The {\tt ilk} and {\tt token} commands have nearly identical syntax. +The syntax of the {\tt ilk} command is: +\begin{quote}\tt +\syntax{command} \produces~ilk \syntax{ilk-name} +\syntax{token-descriptions} +\end{quote} +In translations that appear in {\tt ilk} commands, the self +marker~({\tt *}) designates the string of characters making up the +reserved word, surrounded by \verb+\&{...}+, which makes the reserved +words appear in bold face. + +\section{Syntax of the prettyprinting grammar} +Defining the tokens of a language is somewhat tedious, but it is +essentially straightforward, and the definition usually does not need +fine tuning. +When developing a new {\WEB} with {Spider}, you will spend most of +your time writing the grammar that tells {\tt WEAVE} how to reduce +scraps. +The grammar is defined as a sequence of context-sensitive productions. +Each production has the form: +\begin{quote} +\tt +\syntax{left context} [ \syntax{firing instructions} ] \syntax{right context} +\\\null\qquad +--> \syntax{left context} \syntax{target category} \syntax{right context} +\end{quote} +where the left and right contexts are (possibly empty) sequences of +scrap designators, the firing instructions are a sequence of scrap +designators and translations (containing at least one scrap +designator), and the target category is a category designator. +If the left and right contexts are both empty, the square brackets +({\tt []}) can be omitted, and the production is context free. +The left and right contexts must be the same on both sides of the {\tt +-->}. + +What does the production mean? +Well, {\tt WEAVE} is trying to reduce a sequence of scraps. +So what {\tt WEAVE} does is look at the sequence, to find out whether +the left hand side of some production matches an initial subsequence +of the scraps. +{\tt WEAVE} picks the first matching production, and {\em fires} it, +reducing the scraps described in the firing instructions to a single +scrap, and it gives the new scrap the {\em target category}. +The translation of the new scrap is formed by concatenating the +translations in the {\em firing instructions}, where a scrap +designator stands for the translation of the designated scrap. + +Here is the syntax that describes contexts, firing instructions, scrap +designators, and so on. +\begin{quote} +\tt +\syntax{left context} \produces~\syntax{scrap designators}\\ +\syntax{right context} \produces~\syntax{scrap designators}\\ +\syntax{firing instruction} \produces \syntax{scrap designator}\\ +\syntax{firing instruction} \produces \syntax{translation}\\ +\syntax{scrap designator} \produces~?\\ +\syntax{scrap designator} \produces~\opt{!}\syntax{category name}\opt{*}\\ +\syntax{scrap designator} + \produces~\opt{!}\syntax{category alternatives}\opt{*}\\ +\syntax{category alternatives} + \produces~\rlap{(\syntax{optional alternatives}\syntax{category name})}\\ +\syntax{optional alternative} \produces~\syntax{category name}|\\ +\syntax{target category} \produces~\#\syntax{integer}\\ +\syntax{target category} \produces~\syntax{category name}\\ +\end{quote} + +\paragraph{Matching the left hand side of a production} +When does a sequence of scraps match the left hand side of a +production? +For matching purposes, we can ignore the translations and the square +brackets~({\tt []}), and look at the left hand side just as a sequence +of scrap designators. +A sequence of scraps matches a sequence of scrap designators if and +only if each scrap on the sequence matches the corresponding scrap +designator. +Here are the rules for matching scrap designators (we can +ignore starring% +\footnote{A category name is said to be {\em starred} if it has the +optional {\tt *}.}% +): +\begin{itemize} +\item +Every scrap matches the designator {\tt ?}. +\item +A scrap matches \syntax{marked category} if and only if its category +is the same as the category of the designator. +\item +A scrap matches {\tt!}\syntax{marked category} if and only if its category +is {\em not} the same as the category of the designator. +(The {\tt !} indicates negation.) +\item +A scrap matches a list of category alternatives if and only if its +category is on the list of alternatives. +\item +A scrap matches a {\em negated} list of category alternatives if and +only if its category is {\em not} on the list of alternatives. +\end{itemize} + +\paragraph{Firing a production} +Once a match is found, {\tt WEAVE} fires the production by replacing +the subsequence of scraps matching the firing instructions. +{\tt WEAVE} replaces this subsequence with a new scrap whose category +is the target category, and whose translation is the concatenation of +all the translations in the firing instructions. +(When the new translation is constructed, the +translations of the old scraps are included at the positions of the +corresponding scrap designators.) +If the target category is not given by name, but rather by +number~({\tt \#$n$}), {\tt WEAVE} will take the category of the $n$th +scrap in the subsequence that matches the left hand side of the +production, and make that the target category. + +\subparagraph{Side effects of firing a production} +When a production fires, {\tt WEAVE} will {\em underline the +index entry} for the first identifier in any {\em starred} scrap. + +\paragraph{If no initial subsequence matches any production} +If the initial subsequence of scraps does not match the left hand side +of any production, {\tt WEAVE} will try to match the subsequence +beginning with the second scrap, and so on, until a match is found. +Once a match is found, {\tt WEAVE} fires the production, changing its +sequence of scraps. +It then starts all over again at the beginning of the new sequence, +looking for a match.% +\footnote{ +The implementation is better than that; {Spider} figures out just +how much {\tt WEAVE} must backtrack to get the same effect as +returning to the beginning.} +If {\em no} subsequence of the scraps matches any production, then the +sequence of scraps is irreducible, and {\tt WEAVE} writes out the +translations of the scraps, one at a time. + +\section{Examples of {\tt WEAVE} grammars} +This all must seem very intimidating, but it's not really. +In this section we present some grammar fragments and explain what's +going on. + +\paragraph{Short examples} +\begin{verbatim} +? ignore_scrap --> #1 +\end{verbatim} +This production should appear in every grammar, because Spidery {\tt +WEAVE} expects category \verb+ignore_scrap+ to exist with roughly this +semantics. +(For example, all comments generate scraps of category {\tt +ignore\_scrap}.) +Any scrap of category \verb+ignore_scrap+ essentially doesn't affect +the reduction of scraps: it is absorbed into the scrap to its left. + +\begin{verbatim} +token newline category newline translation <> +newline --> ignore_scrap +\end{verbatim} +This token definition and production, combined with the previous +production, causes {\tt WEAVE} to ignore all newlines. + +For this next example, from the C~grammar, you will need to know that +{\tt math} represents a mathematical expression, {\tt semi} a +semicolon, and {\tt stmt} a statement or sequence of statements. +\begin{verbatim} +math semi --> stmt +stmt <force> stmt --> stmt +\end{verbatim} +The first production says that a mathematical expression, followed by +a semicolon, should be treated as a statement. +The second says that two statements can be combined to make a single +statement by putting a line break between them. + +\paragraph{Expressions} +This more extended example shows the treatment of expressions in Awk. +This is identical to the treatment of expressions in C and in several +other languages. +We will use the following categories: +\begin{description} +\item[math] A mathematical expression +\item[binop] A binary infix operator +\item[unop] A unary prefix or postfix operator +\item[unorbinop] An operator that could be binary infix or unary +prefix +\end{description} +To show you how these might be used, here are some sample token +definitions using these categories: +\begin{verbatim} +token + category unorbinop +token - category unorbinop +token * category binop +token / category binop +token < category binop +token > category binop +token , category binop translation <",\\,"-opt-3> +token = category binop translation <"\\K"> +token != translation <"\\I"> category binop +token == name eq_eq translation <"\\S"> category binop +token ++ name gt_gt category unop translation <"\\uparrow"> +token -- name lt_lt category unop translation <"\\downarrow"> +\end{verbatim} +Notice that the translation for the comma specifies a thin space and +an optional line break after the comma. +The translations of {\tt =}, {\tt !=}, and {\tt ==} +produce~$\leftarrow$, $\ne$, and~$\equiv$. + +Here is the grammar for expressions. +\begin{verbatim} +math (binop|unorbinop) math --> math +(unop|unorbinop) math --> math +math unop --> math +math <"\\"-space> math --> math +\end{verbatim} +In Awk there is no concatenation operator; concatenation is by +juxtaposition. +The last production tells {\tt WEAVE} to insert a space between two +juxtaposed expressions. + +So far we haven't dealt with parentheses, but that's easily done: +\begin{verbatim} +token ( category open +token ) category close +token [ category open +token ] category close +open math close --> math +\end{verbatim} + + +Now this grammar just given doesn't handle the Awk or C {\tt +=} +feature very well; {\tt x+=1} comes out as~$x+\leftarrow 1$, and {\tt +x/=2} is irreducible! +Here's the cure; first, we make a new category for assignment: +\begin{verbatim} +token = category equals translation <"\\K"> +\end{verbatim} +And then we write productions that reduces assignment (possibly +preceded by another operator) to a binary operator: +\begin{verbatim} +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +\end{verbatim} +Notice that, given the rules stated above, the second production can +fire only if {\tt equals} is {\em not} preceded by an operator. +On input~{\tt x+=1}, the first production fires, and we have the +translation~$x\buildrel+\over{\leftarrow} 1$. + +\paragraph{Conditional statements} +Here is the grammar for (possibly nested) conditional statements in +Awk. +\begin{verbatim} +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> close else <"\\"-space> if --> if +ifbrace <outdent-force> close else lbrace --> ifbrace +ifbrace <outdent-force> close else newline --> ifline +ifbrace <outdent-force> close --> stmt +(ifline|ifmath) <indent-force> stmt <outdent> --> stmt +\end{verbatim} +It relies on the following token definitions: +\begin{verbatim} +ilk if_like category if +reserved if +ilk else_like category else +reserved else +token { translation <"\\;\\{"-indent> category lbrace +token } translation <"\\}\\"-space> category close +token newline category newline translation <> +\end{verbatim} + +\paragraph{Handling preprocessor directives in C} +Here is a simplified version of +the grammar that handles C preprocessor directives. +It puts the directives on the left hand margin, and correctly handles +newlines escaped with backslashes. +(The full version is also able to distinguish {\tt <...>} +bracketing a file name from the use of the same symbols to mean ``less +than'' and ``greater than.'') +{\small\advance\hsize 1in +\begin{verbatim} +# control sequence \8 puts things on the left margin +<"\\8"> sharp <"{\\let\\\\=\\bf"-space> math <"}"-indent-"{}"-space> --> preproc +preproc backslash <force-"\\8\\hskip1em"-space> newline --> preproc +<force> preproc <force-outdent> newline --> ignore_scrap +preproc math --> preproc +newline --> ignore_scrap +\end{verbatim} +} +The \verb+\let+ in the first production makes the identifier following +the {\tt \#} come out in bold face. + + +\subsection{Using context-dependent productions} +So far we've been able to do a lot without using the +context-dependent features of {Spider} productions. +(For example, the entire {\tt spider} file for Awk is written using +only context-free productions.) +Now we'll show some examples that use the context-dependence. + +In the grammar for Ada, a semicolon is used as a terminator for +statements. +But semicolons are also used as {\em separators} in parameter +declarations. +The first two productions here find the statements, but the third +production supersedes them when a semicolon is seen in a parenthesized +list. +\begin{verbatim} +semi --> terminator +math terminator --> stmt +open [ math semi ] --> open math +\end{verbatim} + + +\paragraph{Underlining the index entry for the name of a declared +function} +In SSL, function declarations begin with the type of the function +being declared, followed by the name of that function. +The following production causes the index entry for that function to +be underlined, so that we can look up the function name in the index +and easily find the section in which the function is declared: +\begin{verbatim} +decl simp [ simp* ] --> decl simp math +\end{verbatim} +Where we've relied on +\begin{verbatim} +token identifier category simp mathness yes +\end{verbatim} + + +\paragraph{Conditional expressions} +Suppose we want to format conditional expressions (for example in C) +like this: +\begin{quote} +\syntax{condition}\\ +\mbox{\qquad}$?$ \syntax{expression}\\ +\mbox{\qquad}$:$ \syntax{expression} +\end{quote} +The problem is that it's hard to know when the conditional expression +ends. +It's essentially a question of precedence, and what we're going to do +is look ahead until we see an operator with sufficiently low +precedence that it terminates a conditional expression. +In SSL a conditional expression can be terminated by a semicolon, a +right parenthesis, a comma, or a colon. +We'll use the {\em right context} to do the lookahead. +{\small +\begin{verbatim} +token ? translation <"\\?"> category question +token : category colon + +<indent-force> question math <force> colon --> condbegin +[ condbegin math <outdent> ] (semi|close|comma|colon) --> math (semi|close|comma|colon) +\end{verbatim} +} + +\subsection{Debugging a prettyprinting grammar} +{\tt WEAVE} has two tracing modes that can help you debug a +prettyprinting grammar. +The control sequence {\tt @1} turns on partial tracing, and {\tt @2} +turns on a full trace. +{\tt @0} turns tracing back off again. +In the partial tracing mode, {\tt WEAVE} applies all the productions +as many times as possible, and then it prints out the irreducible +scraps that remain. +If the scraps reduce to a single scrap, no diagnostics are printed. + + +When a scrap is printed, {\tt WEAVE} prints a leading +{\tt+}~or~{\tt-}, the name of the category of that scrap, and a +trailing {\tt+}~or~{\tt-}. +The {\tt+} indicates that {\TeX} should be in math mode, and the +{\tt-} that {\TeX} should not be in math mode, at the beginning and +end of the scrap's translation, respectively. +(You can see the translations by looking at the {\tt.tex} file, since +that's where they're written out.) + +For beginners, the full trace is more helpful. +It prints out the following information every time a production is +fired: +\begin{itemize} +\item +The number of the production just fired (from {\tt productions.list}); +\item +The sequence of scraps {\tt WEAVE} is now trying to reduce; +\item +A {\tt*} indicating what subsequence {\tt WEAVE} will try to reduce +next. +\end{itemize} +A good way to understand how prettyprinting grammars work is to take +a {\tt productions.list} file, and look at a full trace of the +corresponding {\tt WEAVE}. +Or, if you prefer, you can simulate by hand the action of {\tt WEAVE} +on a sequence of scraps. + +\section{The rest of the {Spider} language} +The tokens and the grammar are not quite the whole story. +Here's the rest of the truth about what you can do with {Spider}. + +\subsection{Naming the target language} +When a Spidery {\tt WEAVE} or {\tt TANGLE} starts up, it prints the +target language for which it was generated, and the date and time of +the generation. +The {\tt language} command is used to identify the language being +targeted. +Its syntax is +\begin{quote} +\tt language \syntax{language-name} +\opt{extension \syntax{extension-name}}\\ +\mbox{\qquad\qquad}\opt{version \syntax{version-name}} +\end{quote} +The extension name is the extension used (in place of {\tt .web}) by +{\tt TANGLE} to write out the program text for the unnamed module. +The extension is also used to construct a language-specific file of +{\TeX} macros to be used by {\tt WEAVE}, so different languages should +always have different extensions. +If the extension is not given it defaults to the language name. +If the version information is given, it too will be printed out at +startup. + +The {\tt c.spider} file I use for Unix has +\begin{verbatim} +language C extension c +\end{verbatim} + + +\subsection{Defining {\TeX} macros} +In addition to the ``kernel'' {\WEB} macros stored in {\tt +webkernel.tex}, you may want to create some {\TeX} macros of your +own for use in translations. +Any macro definitions you put between lines saying {\tt macros begin} +and {\tt macros end} will be included verbatim in the {\TeX} macro +file for this language. +That macro file will automatically be \verb+\input+ by every {\TeX} +file generated by this {\tt WEAVE}. + +For example, the C grammar includes productions to handle preprocessor +directives. +These directives may include file names that are delimited by angle +brackets. +I wanted to use the abbreviations \verb+\LN+ and \verb+\RN+ for left +and right angle brackets, so I included +\begin{verbatim} +macros begin +\let\LN\langle +\let\RN\rangle +macros end +\end{verbatim} +in the {\tt c.spider} file. + +\subsection{Setting default token information} +It's possible to set default values for the {\tt translation} and {\tt +mathness} properties of tokens, so that they don't have to be +repeated. +This is done with the {\tt default} command, whose syntax is: +\begin{quote} +\tt +default \syntax{token descriptions} +\end{quote} +The initial defaults (when {Spider} begins execution) are {\tt +translation~<*>} and {\tt mathness~maybe}. + +\subsection{Specifying the treatment of modules} +{\WEB} introduces a new kind of token that isn't in any programming +language, and that's the module name ({\tt @<...@>} or {\tt @(...@>}). +{\tt TANGLE}'s job is to convert the module names to program text, and +when {\tt TANGLE} is finished no module names remain. +But {\tt WEAVE} has to typeset the module names, and we need to tell +{\tt WEAVE} what category to give a scrap created from a module name. +We allow two different categories, one for the definition of the +module name (at the beginning of a module), and one for a use of a +module name. +{\samepage +The syntax of the {\tt module} command is: +\begin{quote} +\tt +module \opt{definition \syntax{category name}} +\opt{use \syntax{category name}} +\end{quote} +} + +The {\tt c.spider} file contains the line +\begin{verbatim} +module definition decl use math +\end{verbatim} + +\subsection{Determining the at sign} +When generating a {\WEB} system with {Spider}, you're not required +to use ``{\tt @}'' as the ``magic at sign'' that introduces {\WEB} +control sequences. +By convention, however, we use ``{\tt @}'' unless that is deemed +unsuitable. +If ``{\tt @}'' is unsuitable, we use ``{\tt \#}.'' +Since {Spider} writes C~{\WEB} code for {\tt WEAVE} and {\tt +TANGLE}, it writes a lot of {\tt @} signs. +I didn't when to have to escape each one, so I chose +``{\tt \#}'' for Awk~{\WEB}'s at sign: +\begin{verbatim} +at_sign # +\end{verbatim} +The at sign defaults to ``{\tt @}'' if left unspecified. + +\paragraph{Changing control sequences} +Changing the at sign changes the meaning of one or two control +sequences. +This is more easily illustrated by example than explained. +Suppose we change the at sign to {\tt\#}. +Then in the resulting {\WEB} two control sequences have new meanings: +\begin{description} +\item[{\tt \#\#}] +Stands for a {\tt \#} in the input, by analogy with {\tt @@} in normal +{\WEB}. +You will need this when defining {\TeX} macros that take parameters. +\item[{\tt \#@}] +This is the new name of the control sequence normally represented by +{\tt@\#}. + You would use {\tt\#@} to get a line break followed by vertical +white space. +\end{description} +If you change the at sign to something other than {\tt@}~or~{\tt\#}, +the above will still hold provided you substitute your at sign for +{\tt\#}. + + +\subsection{Comments in the programming language} +We have to tell {\tt WEAVE} and {\tt TANGLE} how to recognize +comments in our target programming language, since comment text is +treated as {\TeX} text by {\tt WEAVE} and is ignored by {\tt TANGLE}. +The syntax of the {\tt comment} command is +\begin{quote} +\tt +comment begin \syntax{restricted translation} \\ +\null\qquad end $(\syntax{restricted translation}|{\tt newline})$ +\end{quote} +The restricted translations can include only quoted +strings, {\tt space}, and +{\tt dash}. +They give the character sequences that begin and end comments. +If comments end with newlines the correct incantation is {\tt end +newline}. + +If the comment character is the same as the at sign, it has to be +doubled in the {\WEB} file to have any effect. +For reasons that I've forgotten, {Spider} is too dumb +to figure this out and {\em you must double the comment character in +the {Spider} file}. +This is not totally unreasonable since any at sign that actually appears in a +{\WEB} file will have to be double to be interpreted correctly. + +{\tt WEAVE} uses the macros \verb+\commentbegin+ and +\verb+\commentend+ at the beginning and end of comments, so you can +define these to be whatever you like (using the {\tt macros} command) +if you don't like {Spider}'s defaults. +{Spider} is smart enough to escape {\TeX}'s special characters in +coming up with these defaults. + +Here's a real-world ugly example of how things really are, from the +{\tt spider} file for Awk: +\begin{verbatim} +comment begin <"##"> end newline +macros begin +\def\commentbegin{\#} % we don't want \#\# +macros end +\end{verbatim} + +\subsection{Controlling line numbering} + A compiler doesn't get to see {\WEB} files directly; it has to +read the output of {\tt TANGLE}. +Error messages labelled with line numbers from a tangled file aren't +very helpful, so Spidery {\tt TANGLE} does something to improve the +situation: it writes {\tt \#line} directives into its output, in the +manner of the C~preprocessor. +({\tt TANGLE} also preserves the line breaking of the {\WEB} source, +so that the {\tt \#line} information will be useful.) +For systems like Unix with {\tt cc} and {\tt dbx}, both compile-time +and run-time debugging can be done in terms of the {\WEB} source, and +the intermediate programming language source need never be consulted. + +Not all compilers support line numbering with {\tt \#line} directives, +so {Spider} provides a {\tt line} command to change the format of +the {\tt \#line} directives. +If your compiler doesn't support {\tt \#line}, you can use the {\tt +line} command to turn the line number information into a comment.% +\footnote{% +There should be a command that turns off line numbering.% +} +The syntax is: +\begin{quote} +\tt +line begin \syntax{restricted translation} end \syntax{restricted translation} +\end{quote} +The {\tt begin} translation tells what string to put in front of the file +name and line number information; the {\tt end} translation tells what to +put afterward. +The defaults (which are set for C) are +\begin{verbatim} +line begin <"#line"> end <""> +\end{verbatim} +Here's an example from the Ada~{Spider} file, which makes the line +number information into an Ada comment: +\begin{verbatim} +line begin <"--"-space-"line"> end <""> +\end{verbatim} + + + + +\subsection{Showing the date of generation} +When Spidery {\tt WEAVE} and {\tt TANGLE} start up, they print the +date and time at which their {Spider} file was processed. +This is done through the good offices of {Spider}'s {\tt date} +command, which is +\begin{quote} +\tt +date \syntax{date} +\end{quote} +where \syntax{date} looks like {\tt "Fri Dec 11 11:31:18 EST 1987"} or +some such. +Normally you never need to use the {\tt date} command, because one is +inserted automatically by the {Spider} tools, but if you're +porting {Spider} to a non-Unix machine you need to know about it. + + + + +\section{Spider's error messages} +{Spider} makes a lot of attempts to detect errors in a +{Spider} specification. +{Spider}'s error messages are intended to be self-explanatory, but +I don't know how well they succeed. +In case you run into trouble, here are the error +conditions {Spider} tries to detect: +\begin{itemize} +\item + Garbled commands, lines with bad fields in them, or commands with +unused fields. +Any command with a field {Spider} can't follow or with an extra +field is ignored from the bad field onward, but the earlier fields may +have an effect. +Any production with a bad field or other error is dropped completely. +\item +Missing {\tt language} command. +\item +{\tt macros} or {\tt comment} command before {\tt language} command. +{Spider} uses the {\tt extension} information +from the {\tt language} command to determine the name of the file to +which the macros will be written, and the {\tt comment} command +causes {Spider} to write macros telling {\TeX} what to do at the +beginning and end of comments. +\item +Contexts don't match on the left and right sides of a production. +\item +A numbered target token doesn't fall in the range defined by the +left hand side of its production. +\item +Some category is never {\em appended}. +This means there is no way to create a scrap with this category. +{Spider} only looks to see that each +category appears at least once as the category of some token or as the +category of the target token in some production, so {Spider} might +fail to detect this condition (if there is some production that can +never fire). +\item +Some category is never {\em reduced}. +This means that the category never appears in a scrap +designator from the firing instructions of a production. +If a category is never reduced, {Spider} only issues a warning, +and does not halt the compilation process with an error. + +The append +and reduce checks will usually catch you if you misspell a category +name. +\item +You defined more tokens than {\tt WEAVE} and {\tt TANGLE} can handle. +\item +You forgot token information for identifiers, numeric +constants, newlines, pseudo-semicolons~({\tt @;}), module definitions, +or module uses. +\item +Some ilk has no translation, or there is some ilk of which there are +no reserved words. +\end{itemize} + + + + +\section{{Spider}'s output files} +{Spider} writes many output files, and you may want to look at +them to figure out what's going on. +Here is a partial list (you can find a complete list by consulting +{\tt spider.web}): +\begin{description} +\item[\tt cycle.test] +Used to try to detect potential loops in the grammar. +Such loops can cause {\tt WEAVE} to run indefinitely (until it runs +out of memory) on certain inputs. +Discussed below with the {Spider} tools. +\item[\tt spider.slog] +A verbose discussion of everything {Spider} did while it was +processing your file. +To be consulted when things go very wrong. +\item[\tt *web.tex] +The macros specific to the generated {\WEB}. +\item[\tt productions.list] +A numbered list of all the productions. +This list is invaluable when you are trying to debug a grammar using +Spidery {\tt WEAVE}'s tracing facilities ({\tt @2}). +\end{description} + + + + +\section{Using {Spider} to make {\WEB} (the {Spider} tools)} +Many of the {Spider} tools do error checking, like: +\begin{itemize} +\item +Check to see there are no duplicate names among the categories, ilks, +and translation keywords. +\item +Check the translation keywords against a list of those recognized by +{\tt WEAVE}, and yelps if trouble happens. +\item +Try to determine whether there is a ``production cycle'' that could +cause {\tt WEAVE} to loop infinitely by firing the productions in the +cycle one after another. +\end{itemize} + +I'm not going to say much about how to do all this, or how to make +{\tt WEAVE} and {\tt TANGLE}; instead I'm going to show you a {\tt +Makefile} and comment on it a little bit. +Since right now Spidery {\tt WEB} is available only on Unix systems, +chances are you have the {\tt Makefile} and can just type ``{\tt +make~tangle}'' or ``{\tt make~weave}.'' +If not, reading the Makefile is still your best bet to figure out what +the tools do. + +We assume that you are making {\tt WEAVE} and {\tt TANGLE} in some +directory, and that the ``master sources'' for Spidery {\WEB} are kept +in some other directory. +Some of the {\tt Makefile} macros deserve special mention: +\begin{description} +\renewcommand{\makelabel}[1]{{\tt#1}\hfil} +\item[THETANGLE] +Name of the {\tt TANGLE} we will generate. +\item[THEWEAVE] +Name of the {\tt WEAVE} we will generate. +\item[SPIDER] +Name of the {Spider} input file. +\item[DEST] +The directory in which the executables defined by \verb+$(TANGLE)+ and +\verb+$(WEAVE)+ will be placed. +\item[WEBROOT] +The directory that is the root of the Spidery {\WEB} distribution. +\item[MASTER] +The location of the ``master sources.'' +This should always be different from the directory in which {\tt make} +is called, or havoc will result. +\item[CTANGLE] +The name of the program used to tangle C code. +\item[AWKTANGLE] +The name of the program used to tangle Awk code. +\item[MACROS] +The name of a directory in which to put {\TeX} macro definitions (a +{\tt *web.tex} file. +\end{description} + +Usually we will only be interested in two commands: ``\/{\tt +make~weave}'' and ``\/{\tt make~tangle}.'' +It's safe to use ``\/{\tt make~clean}'' only if you use the current +directory for nothing exception spidering; ``\/{\tt make~clean}'' is +really vicious. + +The line that's really of interest is the line showing the dependency +for {\tt grammar.web}. +First we run {Spider}. +Then we check for bad translation keywords and for potential cycles in +the prettyprinting grammar. +We check for duplicate names, and then finally (if everything else +works), we put the {\tt *web.tex} file in the right place. + +Here's \verb+$(MASTER)/WebMakefile+: +\begingroup\small +\begin{verbatim} +# Copyright 1989 by Norman Ramsey and Odyssey Research Associates. +# Not to be sold, but may be used freely for any purpose. +# For more information, see file COPYRIGHT in the parent directory. + +HOME=/u/nr# # Make no longer inherits environment vars +THETANGLE=tangle +THEWEAVE=weave +SPIDER=any.spider +# +DVI=dvi +CFLAGS=-DDEBUG -g -DSTAT + +# CPUTYPE is a grim hack that attempts to solve the problem of multiple +# cpus sharing a file system. In my environment I have to have different +# copies of object and executable for vax, sun3, next, iris, and other +# cpu types. If you will be using Spidery WEB in a homogeneous processor +# environment, you can just set CPUTYPE to a constant, or eliminate it +# entirely. +# +# In my environment, the 'cputype' program returns a string that +# describes the current processor. That means that the easiest thing +# for you to do is to define a 'cputype' program that does something +# sensible. A shell script that says 'echo "vax"' is fine. + +CPUTYPE=`cputype` + +# Change the following three directories to match your installation +# +# the odd placement of # is to prevent any trailing spaces from slipping in + +WEBROOT=$(HOME)/web/src# # root of the WEB source distribution +DEST=$(HOME)/bin/$(CPUTYPE)# # place where the executables go +MACROS=$(HOME)/tex/macros# # place where the macros go + +MASTER=$(WEBROOT)/master# # master source directory +OBDIR=$(MASTER)/$(CPUTYPE)# # common object files + +TANGLESRC=tangle +CTANGLE=ceetangle -I$(MASTER) +CWEAVE=ceeweave -I$(MASTER) +AWKTANGLE=awktangle -I$(MASTER) +COMMONOBJS=$(OBDIR)/common.o $(OBDIR)/pathopen.o +COMMONC=$(MASTER)/common.c $(MASTER)/pathopen.c +COMMONSRC=$(COMMONC) $(MASTER)/spider.awk + + + +# Our purpose is to make tangle and weave + +web: tangle weave + +tangle: $(COMMONOBJS) $(TANGLESRC).o + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + +weave: $(COMMONOBJS) weave.o + cc $(CFLAGS) -o $(DEST)/$(THEWEAVE) $(COMMONOBJS) weave.o + + +source: $(TANGLESRC).c $(COMMONSRC) # make tangle.c and common src, then clean + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.web weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + +# Here is how we make the common stuff + +$(MASTER)/common.c: $(MASTER)/common.web # no change file + $(CTANGLE) $(MASTER)/common + +$(OBDIR)/common.o: $(MASTER)/common.c + cc $(CFLAGS) -c $(MASTER)/common.c + mv common.o $(OBDIR) + + +$(MASTER)/pathopen.c: $(MASTER)/pathopen.web # no change file + $(CTANGLE) $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +$(OBDIR)/pathopen.o: $(MASTER)/pathopen.c + cc $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(OBDIR) + + +## Now we make the tangle and weave source locally + +$(TANGLESRC).c: $(MASTER)/$(TANGLESRC).web $(MASTER)/common.h grammar.web + -/bin/rm -f $(TANGLESRC).web + ln $(MASTER)/$(TANGLESRC).web $(TANGLESRC).web +# chmod -w $(TANGLESRC).web + $(CTANGLE) $(TANGLESRC) + +weave.c: $(MASTER)/weave.web $(MASTER)/common.h grammar.web + -/bin/rm -f weave.web + ln $(MASTER)/weave.web weave.web +# chmod -w weave.web + $(CTANGLE) weave + +## Here's where we run SPIDER to create the source + +grammar.web: $(MASTER)/cycle.awk $(MASTER)/spider.awk $(SPIDER) + echo "date" `date` | cat - $(SPIDER) | awk -f $(MASTER)/spider.awk + cat $(MASTER)/transcheck.list trans_keys.unsorted | awk -f $(MASTER)/transcheck.awk + awk -f $(MASTER)/cycle.awk < cycle.test + sort *.unsorted | awk -f $(MASTER)/nodups.awk + mv *web.tex $(MACROS) + +## We might have to make spider first. + +$(MASTER)/spider.awk: $(MASTER)/spider.web + $(AWKTANGLE) $(MASTER)/spider + mv cycle.awk nodups.awk transcheck.awk $(MASTER) + rm junk.list + + +# $(MASTER)/cycle.awk: $(MASTER)/cycle.web # making spider also makes cycle +# $(AWKTANGLE) $(MASTER)/cycle + + +# This cleanup applies to every language + +clean: + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.* weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + + + +# booting the new distribution +boot: + cd ../master; rm -f *.o; for i in $(COMMONC); do \ + cc $(CFLAGS) -c $$i; \ + mv *.o $(OBDIR) ; \ + done; cd ../c + cc $(CFLAGS) -c $(TANGLESRC).c; \ + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + + +\end{verbatim} +\endgroup + +\section{Getting your own Spidery {\tt WEB}} +At this time, Spidery {\tt WEB} has been tested only on Unix machines. +It should be easy to port to any machine having a C compiler and an +Awk interpreter, but undoubtedly some changes will be necessary. +The full {Spider} distribution, including this manual, is available by +anonymous {\tt ftp} from {\tt princeton.edu:~ftp/pub/spiderweb.tar.Z}. +You should pick a directory to install {Spider} in, untar the +distribution, and follow the directions in the README file. +The directory you have picked becomes {\tt WEBROOT}. + +If the {\tt Makefile} in the distribution differs from the one given +above, the one in the distribution should be considered the correct +one. + + + + +\section{A real {Spider} file} +I have tried to use real examples to illustrate the use of {Spider}. +I include here, as an extended example, the complete {Spider} file for +the Awk language. +Those who cannot easily study the distribution may find it useful to +study this. +\begingroup\small +\begin{verbatim} +# Copyright 1989 by Norman Ramsey and Odyssey Research Associates. +# Not to be sold, but may be used freely for any purpose. +# For more information, see file COPYRIGHT in the parent directory. + +language AWK extension awk + +at_sign # + +module definition stmt use stmt +# use as stmt is unavoidable since tangle introduces line breaks + +comment begin <"##"> end newline +macros begin +\def\commentbegin{\#} % we don't want \#\# +macros end + +line begin <"#line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness yes +token number category math mathness yes +token newline category newline translation <> mathness maybe +token pseudo_semi category ignore_scrap mathness no translation <opt-0> + +token \ category backslash translation <> mathness maybe +token + category unorbinop +token - category unorbinop +token * category binop +token / category binop +token < category binop +token > category binop +token >> category binop translation <"\\GG"> +token = category equals translation <"\\K"> +token ~ category binop translation <"\\TI"> +token !~ category binop translation <"\\not\\TI"> +token & category binop translation <"\\amp"> +token % translation <"\\%"> category binop +token ( category open +token [ category lsquare +token ) category close +token ] category close +token { translation <"\\;\\{"-indent> category lbrace +token } translation <"\\}\\"-space> category close +token , category binop translation <",\\,"-opt-3> + +token ; category semi translation <";"-space-opt-2> mathness no +# stuff with semi can be empty in for statements +open semi --> open +semi semi --> semi +semi close --> close +semi --> binop + +# token : category colon +# token | category bar +token != name not_eq translation <"\\I"> category binop +token <= name lt_eq translation <"\\L"> category binop +token >= name gt_eq translation <"\\G"> category binop +token == name eq_eq translation <"\\S"> category binop +token && name and_and translation <"\\W"> category binop +token || name or_or translation <"\\V"> category binop +# token -> name minus_gt translation <"\\MG"> category binop +token ++ name gt_gt category unop translation <"\\uparrow"> +token -- name lt_lt category unop translation <"\\downarrow"> +# preunop is for unary operators that are prefix only +token $ category preunop translation <"\\DO"> mathness yes + +default mathness yes translation <*> + +ilk pattern_like category math +reserved BEGIN ilk pattern_like +reserved END ilk pattern_like + +ilk if_like category if +reserved if +ilk else_like category else +reserved else + +ilk print_like category math +# math forces space between this and other math... +reserved print ilk print_like +reserved printf ilk print_like +reserved sprintf ilk print_like + + +ilk functions category unop mathness yes +reserved length ilk functions +reserved substr ilk functions +reserved index ilk functions +reserved split ilk functions +reserved sqrt ilk functions +reserved log ilk functions +reserved exp ilk functions +reserved int ilk functions + +ilk variables category math mathness yes +reserved NR ilk variables +reserved NF ilk variables +reserved FS ilk variables +reserved RS ilk variables +reserved OFS ilk variables +reserved ORS ilk variables + +ilk for_like category for +reserved for ilk for_like +reserved while ilk for_like + +ilk in_like category binop translation <math_bin-*-"}"> mathness yes +# translation <"\\"-space-*-"\\"-space> +reserved in ilk in_like + +ilk stmt_like category math +reserved break ilk stmt_like +reserved continue ilk stmt_like +reserved next ilk stmt_like +reserved exit ilk stmt_like + + +backslash newline --> math +# The following line must be changed to make a backslash +backslash <"\\backslash"> --> math + +math (binop|unorbinop) math --> math +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +(unop|preunop|unorbinop) math --> math +# unorbinop can only act like unary op as *prefix*, not postfix +math unop --> math +math <"\\"-space> math --> math +# concatenation + +math newline --> stmt +newline --> ignore_scrap + +stmt <force> stmt --> stmt + +(open|lsquare) math close --> math + +math lbrace --> lbrace +lbrace <force> stmt --> lbrace +lbrace <outdent-force> close --> stmt + +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> close else <"\\"-space> if --> if +ifbrace <outdent-force> close else lbrace --> ifbrace +ifbrace <outdent-force> close else newline --> ifline +ifbrace <outdent-force> close --> stmt +(ifline|ifmath) <indent-force> stmt <outdent-force> else <"\\"-space> if --> if +(ifline|ifmath) <indent-force> stmt <outdent-force> else lbrace --> ifbrace +(ifline|ifmath) <indent-force> stmt <outdent-force> else newline --> ifline +(ifline|ifmath) <indent-force> stmt <outdent-force> else --> ifmath +(ifline|ifmath) <indent-force> stmt <outdent> --> stmt + +for <"\\"-space> math --> formath +formath lbrace --> forbrace +formath newline --> forline +forbrace <force> stmt --> forbrace +forbrace <outdent-force> close --> stmt +(forline|formath) <indent-force> stmt <outdent> --> stmt + + +? ignore_scrap --> #1 +\end{verbatim} +\endgroup + + + +\section{Bibliography} +\begin{thebibliography}{Knuth~999} +\bibitem[Bentley~87]{bentley:pearls} +Jon L. Bentley, ``Programming Pearls,'' {\sl Communications of the +ACM}~{\bf 29:5}(May 1986), 364--?, and {\bf 29:6}(June 1986), +471--483. +Two columns on literate programming. +The first is an introduction, and the second is an extended example by +Donald Knuth, with commentary by Douglas MacIlroy. +\bibitem[Knuth~83]{knuth:web} +Donald~E. Knuth, +``The {{\tt WEB}} system of structured documentation'' + Technical Report 980, Stanford Computer Science, Stanford, + California, September 1983. +The manual for the original {\tt WEB}. +\bibitem[Knuth~84]{knuth:literate-programming} +Donald E. Knuth, ``Literate Programming,'' {\sl The Computer Journal} +{\bf 27:2}(1984), 97--111. +The original introduction to literate programming with {\WEB}. +\bibitem[Levy~87]{levy:cweb} +Silvio Levy, ``Web Adapted to C, Another Approach'' {\sl TUGBoat} +{\bf 8:2}(1987), 12--13. +A short note about the C implementation of {\WEB}, from which Spidery +{\WEB} is descended. +\bibitem[Sewell~89]{sewell:weaving} +Wayne Sewell, ``Weaving a program: Literate programming in {\tt +WEB},'' +Van Nostrand Reinhold, 1989. +\end{thebibliography} + + +\end{document} diff --git a/web/spiderweb/doc/spiderwebman.tex b/web/spiderweb/doc/spiderwebman.tex new file mode 100644 index 0000000000..c512983ee1 --- /dev/null +++ b/web/spiderweb/doc/spiderwebman.tex @@ -0,0 +1,2268 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +\input webkernel % rank bravery; was webmac + +% macros for itemized lists +\newcount\level +\level=0 + +\def\enum#1{\ifcase\the#1 x\or i\or ii\or iii\else iv\fi} +\def\setenum{\edef\theenum{\csname enum\enum\level\endcsname}} + + +\def\itemize{\begingroup\advance\level by1 + \def\item{\par\noindent + \raise2pt\llap{$\scriptstyle\bullet$\ }}% + \par\advance\leftskip by2em\advance\rightskip by2em} +\def\enditemize{\par\endgroup\noindent\ignorespaces} +% end of stuff for itemized lists + +\parskip 0pt plus 1pt +\def\RA{\char'31 } % right arrow +\def\hang{\hangindent 4em\ignorespaces} +\font\ninerm=cmr9 +\font\ninett=cmtt9 +\font\eighttt=cmtt8 +\let\mc=\ninerm % medium caps for names like SAIL +\def\PASCAL{\newstuff ``X''\endnewstuff} +\def\PAS{\newstuff X\endnewstuff} % used to mark file extensions +\def\oP{{\sl \overline X}} % used in table of control sequences +\font\quoterm=cmssq8 +\font\quoteit=cmssqi8 +\def\pb{\.{|...|}} +\def\lpile{\def\cr{\hfill\endline}\matrix} % I only use \lpile by + % itself + +\def\newstuff{\begingroup\sl} +\def\endnewstuff{\endgroup} + +\outer\def\section #1.{\penalty-50\vskip 12pt plus 3pt minus 3pt + \noindent{\bf #1.}\quad\ignorespaces} + +\def\titlepage{T} +\def\lheader{\mainfont\the\pageno\hfill\sc\runninghead\hfill} +\def\rheader{\hfill\sc\runninghead\hfill\mainfont\the\pageno} +\def\runninghead{SPIDERY {\tentt WEB} USER MANUAL} + +% This verbatim mode assumed that no ? appears in the text being copied. +\def\verbatim{\begingroup + \def\do##1{\catcode`##1=12 } \dospecials + \parskip 0pt \parindent 0pt + \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{}} + +\centerline{\titlefont The Spidery {\ttitlefont WEB} System + of Structured Documentation} + +\vskip 15pt plus 3pt minus 3pt +\noindent +\newstuff +This memo describes how to write programs in the \.{WEB} language, +using \.{WEB} systems generated by {Spider}. +This class of \.{WEB} systems will be referred to (collectively) as +``Spidery \.{WEB}.'' +Most of the material is taken verbatim from Donald Knuth's original +memo introducing \.{WEB}; new material (like this paragraph) appears +in slant type. +Knuth's original memo is available as Stanford University CS technical + report number 980 (September 1983). +Unlike Knuth's, this memo is not accompanied by the full \.{WEB} +documentation for Spidery \.{WEAVE} and \.{TANGLE}, the programs that +read \.{WEB} input and produce {\TeX} output and code, respectively. +Nor does it contain the \.{WEB} documentation for {Spider}, the program that + generates the +language-dependent parts of \.{WEAVE} and \.{TANGLE}. +This memo should be accompanied by ``A {Spider} User's Guide,'' which +explains how to use {Spider} to build a Spidery \.{WEB} system. +\endnewstuff + +The philosophy behind \.{WEB} is +that an experienced system programmer, who wants to provide the best +possible documentation of his or her software products, needs two things +simultaneously: a language like \TeX\ for formatting, and a language +for programming. +\newstuff For convenience, we'll give this programming language a +name; let's call it the \PASCAL\ programming language. +\endnewstuff +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 \PASCAL\ 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. + +Since \.{WEB} is an experimental system developed for internal use within +the \TeX\ project at Stanford, this report is rather terse, and it assumes +that the reader is an experienced programmer who is highly motivated to +read a detailed description of \.{WEB}'s rules. +{\newstuff Spidery \.{WEB} is also an experimental system and +the same warning applies.\endnewstuff} +\newstuff +Before continuing, you may want to read some more introductory +material on {Spider} and \.{WEB}. +Here are some references worth looking at: +\itemize +\rm +\item Donald E. Knuth, ``Literate Programming,'' {\sl Computer +Journal} {\bf 27:2} (1984), 97--111.. +The original introduction of \.{WEB}. +\item Jon L. Bentley, ``Programming Pearls,'' {\sl Communications of +the ACM} {\bf 29:5} (May 1986), 364--368 and +{\bf 29:6} (June 1986), 471--483. +Two columns on literate programming with \.{WEB}. +\item Norman Ramsey, ``Building a Language-Independent \.{WEB},'' +{\sl Communications of the ACM}, September 1989. +An overview of how {Spider} and \.{WEB} work. +\item +Wayne Sewell, ``Weaving a program: Literate programming in \.{WEB},'' +Van Nostrand Reinhold, 1989. +\enditemize +In addition to these, there is a periodic column in the {\sl +Communications of the ACM} devoted to literate programming. +\endnewstuff + +Even if a +less terse manual were to be written, the reader would have to be warned +in advance that \.{WEB} is not for beginners and it never will be: The +user of \.{WEB} must be familiar with both \TeX\ and \PASCAL. +When one +writes a \.{WEB} description of a software system, it is possible to make +mistakes by breaking the rules of \.{WEB} and/or the rules of \TeX\ and/or +the rules of \PASCAL. +In practice, all three types of errors will occur, +and you will get different error messages from the different language +processors. +In compensation for the sophisticated expertise needed to cope +with such a variety of languages, however, experience has shown that +reliable software can be created quite rapidly by working entirely in +\.{WEB} from the beginning; and the documentation of such programs seems +to be better than the documentation obtained by any other known method. +Thus, \.{WEB} users need to be highly qualified, but they can get some +satisfaction and perhaps even a special feeling of accomplishment when +they have successfully created a software system with this method. + +To use \.{WEB}, you prepare a file called \.{COB.WEB} (say), and then you +apply a system program called \.{WEAVE} to this file, obtaining an output +file called \.{COB.TEX}. +When \TeX\ processes \.{COB.TEX}, your output +will be a ``pretty printed'' version of \.{COB.WEB} that takes appropriate +care of typographic details like page layout and the use of indentation, +italics, boldface, etc.; this output will contain extensive cross-index +information that is gathered automatically. +You can also submit the same +file \.{COB.WEB} to another system program called \.{TANGLE}, which will +produce a file \.{COB.\PAS} that contains the \PASCAL\ code of your \.{COB} +program. +The \PASCAL\ compiler will convert \.{COB.\PAS} into +machine-language instructions corresponding to the algorithms that were so +nicely formatted by \.{WEAVE} and \TeX. +Finally, you can (and should) +delete the files \.{COB.TEX} and \.{COB.\PAS}, because \.{COB.WEB} contains +the definitive source code. +Examples of the behavior of \.{WEAVE} and +\.{TANGLE} are +\newstuff +not +\endnewstuff +appended to this manual. +\newstuff +The names {\tt WEAVE} and \.{TANGLE} may vary, especially since there +may be versions for multiple languages. +My site supports, in addition to the original \.{TANGLE}, +\.{CEETANGLE}, \.{AWKTANGLE}, and \.{ADATANGLE}. +\endnewstuff + +Besides providing a documentation tool, \.{WEB} enhances the \PASCAL\ +language by providing a +%rudimentary + macro capability together with the +ability to permute pieces of the program text, so that a large system can +be understood entirely in terms of small modules and their local +interrelationships. +The \.{TANGLE} program is so named because it takes a +given web and moves the modules from their web structure into the order +required by \PASCAL; the advantage of programming in \.{WEB} is that the +algorithms can be expressed in ``untangled'' form, with each module +explained separately. +The \.{WEAVE} program is so named because it takes +a given web and intertwines the \TeX\ and \PASCAL\ portions contained in +each module, 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 web\/}'', and the +corresponding Latin imperative is ``{\it texe\/}''! + +It is impossible to list all of the related work that has influenced the +design of \.{WEB}, but the key contributions should be mentioned +here.\quad (1)~Myrtle Kellington, as executive editor for ACM +publications, developed excellent typographic standards for the +typesetting of Algol programs during the 1960s, based on the original +designs of Peter Naur; the subtlety and quality of this influential work +can be appreciated only by people who have seen what happens when other +printers try to typeset Algol without the advice of ACM's copy +editors.\quad(2)~Bill McKeeman introduced a program intended to automate +some of this task [Algorithm 268, ``Algol~60 reference language editor,'' +{\sl CACM \bf8} (1965), 667--668]; and a considerable flowering of such +programs has occurred in recent years [see especially Derek Oppen, +``Prettyprinting,'' {\sl ACM TOPLAS \bf2} (1980), 465--483; G.~A. +Rose and +J. +Welsh, ``Formatted programming languages,'' {\sl SOFTWARE Practice +\char`\&\ Exper.\ \bf11} (1981), 651--669].\quad(3)~The top-down style of +exposition encouraged by \.{WEB} was of course chiefly influenced by Edsger +Dijkstra's essays on structured programming in the late 1960s. +The less +well known work of Pierre-Arnoul de Marneffe [``Holon programming: A +survey,'' Univ.\ de Liege, Service Informatique, Liege, Belgium, 1973; 135 +pp.\null] also had a significant influence on the author as \.{WEB} was +being formulated.\quad(4)~Edwin Towster has proposed a similar style of +documentation in which the programmer is supposed to specify the relevant +data structure environment in the name of each submodule [``A convention +for explicit declaration of environments and top-down refinement of +data,'' {\sl IEEE Trans.\ on Software Eng.\ \bf SE--5} (1979), 374--386]; +this requirement seems to make the documentation a bit too verbose, +although experience with \.{WEB} has shown that any unusual control +structure or data structure should definitely be incorporated into the +module names on psychological grounds.\quad(5)~Discussions with Luis +Trabb~Pardo in the spring of 1979 were extremely helpful for setting up a +prototype version of \.{WEB} that was called \.{DOC}.\quad (6)~Ignacio +Zabala's extensive experience with \.{DOC}, in which he created a full +implementation of \TeX\ in {Pascal} that was successfully transported to +many different computers, was of immense value while \.{WEB} was taking +its present form.\quad(7)~David~R. +Fuchs made several crucial suggestions +about how to make \.{WEB} more portable; he and Arthur~L. +Samuel +coordinated the initial installations of \.{WEB} on dozens of computer +systems, making changes to the code so that it would be acceptable to +a wide variety of \.{Pascal} compilers.\quad(8)~The name \.{WEB} itself +was chosen in honor of my wife's mother, Wilda Ernestine Bates. + +\newstuff +The work on Spidery \.{WEB} would not have been possible without the +help of Silvio Levy, who first ported \.{WEB} to C. +The name {Spider} was chosen because (in nature at least) webs are +built by spiders. +\endnewstuff + +The appendices to this report +\newstuff +do not +\endnewstuff +contain complete \.{WEB} programs for the +\newstuff {Spider}, \endnewstuff +\.{WEAVE}, and \.{TANGLE} processors. +A study of these examples, together +with an attempt to write \.{WEB} programs by yourself, is the best way +to understand why \.{WEB} has come to be like it is. + +\section General rules. +A \.{WEB} file is a long string of text that has been divided into +individual lines. +\newstuff +Unlike original {\tt WEB}, Spidery {\tt WEB} respects the programmer's +choice of line breaks. +A newline in code is normally passed along through tangle and will +appear in the resulting program. +This is important in languages like awk where line breaks are +significant. +In documentation, +\endnewstuff +the exact line boundaries are not terribly crucial, and +a programmer can pretty much chop up the \.{WEB} file in whatever way seems +to look best as the file is being edited; but string constants and control +texts must end on the same line on which they begin, since this convention +helps to keep errors from propagating. +\newstuff +The line length of the input is limited and is rather small. +\endnewstuff +% The end of a line means +% the same thing as a blank space. + +Two kinds of material go into \.{WEB} files: \TeX\ text and \PASCAL\ text. +A programmer writing in \.{WEB} should be thinking both of the +documentation and of the \PASCAL\ program that he or she is creating; +i.e., the programmer should be instinctively aware of the different +actions that \.{WEAVE} and \.{TANGLE} will perform on the \.{WEB} file. +\TeX\ text is essentially copied without change by \.{WEAVE}, and it is +entirely deleted by \.{TANGLE}, since the \TeX\ text is ``pure +documentation.'' +\PASCAL\ text, on the other hand, is formatted by +\.{WEAVE} and it is shuffled around by \.{TANGLE}, 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 \.{WEB} programs is something +like writing \TeX\ documents, but with an additional ``\PAS\ mode'' +that is added to \TeX's horizontal mode, vertical mode, and math mode. + +A \.{WEB} file is built up from units called {\sl modules\/} that are more +or less self-contained. +Each module has three parts: + +\yskip\item{1)} A \TeX\ part, containing explanatory material about what +is going on in the module. + +\item{2)} A definition part, containing macro definitions that serve as +abbreviations for \PASCAL\ constructions that would be less comprehensible +if written out in full each time. + +\item{3)} An \PASCAL\ part, containing a piece of the program that +\.{TANGLE} will produce. +This \PASCAL\ 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 module must appear in this order; +i.e., the \TeX\ commentary must come first, then the definitions, and +finally the \PASCAL\ code. +Any of the parts may be empty. + +A module begins with the pair of symbols `\.{@\ }' or `\.{@*}', where +`\.{\ }' denotes a blank space. +A module ends +at the beginning of the next module (i.e., at the next +`\.{@\ }' or `\.{@*}'), or at the end of the file, whichever comes first. +The \.{WEB} file may also contain material that is not part of any module +at all, namely the text (if any) that occurs before the first module. +Such text is said to be ``in limbo''; it is ignored by \.{TANGLE} +and copied essentially verbatim by \.{WEAVE}, 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 \.{WEB} file with +\TeX\ code in limbo that loads special fonts, defines special macros, +changes the page sizes, and/or produces a title page. + +Modules are numbered consecutively, starting with 1; these numbers appear +at the beginning of each module of the \TeX\ documentation, and they appear +as bracketed comments at the beginning of the code generated by that +module in the \PASCAL\ program. + +Fortunately, you never mention these numbers yourself when you are writing +in \.{WEB}. +You just say `\.{@\ }' or `\.{@*}' at the beginning of each +new module, and the numbers are supplied automatically by \.{WEAVE} and +\.{TANGLE}. +As far as you are concerned, a module has a +name instead of a number; such a name is specified by writing +`\.{@<}' followed by \TeX\ text followed by `\.{@>}'. +When \.{WEAVE} +outputs a module name, it replaces the `\.{@<}' and `\.{@>}' by +angle brackets and inserts the module number in small type. +Thus, when you +read the output of \.{WEAVE} it is easy to locate any module that is +referred to in another module. + +\newstuff +Spidery {\tt WEB} supports a new kind of module called a ``file +module.'' +File modules open with \.{@(} instead of \.{@<}, and the module name + is taken to be the name of a file to which \.{TANGLE} will write the +contents of the module. +When \.{WEAVE} +outputs a file module name, it replaces the `\.{@(}' and `\.{@>}' by +parentheses and sets the entire name in {\tt typewriter} font. +\endnewstuff + + +For expository purposes, a module name should be a good description of the +contents of that module, i.e., it should stand for the abstraction +represented by the module; then the module can be ``plugged into'' one or +more other modules so that the unimportant details of its inner workings +are suppressed. +A module name therefore ought to be long enough to convey +the necessary meaning. +Unfortunately, however, 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 \.{WEAVE} and \.{TANGLE} +will be able to match the names to the modules. +Therefore a module name +can be abbreviated after its first appearance in the \.{WEB} file, by +typing `\.{@<$\alpha$...@>}', where $\alpha$ is any string that is a prefix of +exactly one module name that appears in the file. +For example, `\.{@<Clear +the arrays@>}' can be abbreviated to `\.{@<Clear...@>}' if no other module +name begins with the five letters `\.{Clear}'. +Module names must otherwise +match character for character, except that consecutive blank spaces and/or +tab marks are treated as equivalent to single spaces, 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. + +We have said that a module begins with `\.{@\ }' or `\.{@*}', but we +didn't say how it gets divided up into a \TeX\ part, a definition part, +and an \PASCAL\ part. +The definition part begins with the first appearance +of `\.{@d}' or `\.{@f}' in the module, and the \PASCAL\ part begins with +the first appearance of `\.{@u}', `\.{@<}', +\newstuff or `\.{@(}'.\endnewstuff +The +%latter + options `\.{@<}' \newstuff and `\.{@(}'.\endnewstuff +stand for the beginning of a module name, which is the name of the module +itself. +An equals sign (\.=) must follow the `\.{@>}' at the end of this +module name; you are saying, in effect, that the module name stands for +the \PASCAL\ text that follows, so you say `$\langle\,$module +name$\,\rangle=\null$\PASCAL\ text'. +Alternatively, if the \PASCAL\ part +begins with `\.{@u}' instead of a module name, the current module is said +to be {\sl unnamed}. +Note that module names cannot appear in the +definition part of a module, because the first `\.{@<}' \newstuff or +`\.{@(}'.\endnewstuff in a module +signals the beginning of its \PASCAL\ part. +Any number of module names +might appear in the \PASCAL\ part, however, once it has started. + +The general idea of \.{TANGLE} is to make an \PASCAL\ program out of these +modules in the following way: First all the \PASCAL\ parts of unnamed +modules are copied down, in order; this constitutes the initial +approximation $T_0$ to the text of the program. +(There should be at least +one unnamed module, otherwise +\newstuff unless there are file modules \endnewstuff +there will be no program.) Then all module +names that appear in the initial text $T_0$ are replaced by the \PASCAL\ +parts of the corresponding modules, and this substitution process +continues until no module names remain. +Then all defined macros are +replaced by their equivalents, according to certain rules that are +explained later. +%The resulting \PASCAL\ code is ``sanitized'' so that it +%will be acceptable to an average garden-variety \PASCAL\ compiler; i.e., +%lowercase letters are converted to uppercase, long identifiers are +%chopped, and the lines of the output file are constrained to be at most 72 +%characters long. +All comments will have been removed from this \PASCAL\ +program except for the meta-comments delimited by `\.{@\{}' and +`\.{@\}}', as explained below, and except for the module-number comments +that point to the source location where each piece of the program text +originated in the \.{WEB} file. +\newstuff +Spidery {\tt WEB} does not support the use of the meta-comments + `\.{@\{}' and `\.{@\}}'. +Their absence can be partially compensated for by clever use of the +``verbatim'' control sequence `\.{@=...@>}'. +\endnewstuff + +Incidentally, module numbers are automatically inserted +as meta-comments into the \PASCAL\ program, in order to help correlate the +outputs of \.{WEAVE} and \.{TANGLE} (see Appendix~C\null). +\newstuff So are {\tt\#line} directives, the exact workings of which +are obscure (but see the ``{Spider} User's Guide'' for more information). +\endnewstuff + +If the same name has been given to more than one module, the \PASCAL\ text +for that name is obtained by putting together all of the \PASCAL\ parts in +the corresponding modules. +This feature is useful, for example, in a +module named `Global variables in the outer block', since one can then +declare global variables in whatever modules those variables are +introduced. +When several modules have the same name, \.{WEAVE} assigns the +first module number as the number corresponding to that name, and it +inserts a note at the bottom of that module telling the reader to `See +also sections so-and-so'; this footnote gives the numbers of all the other +modules having the same name as the present one. +The \PASCAL\ text +corresponding to a module is usually formatted by \.{WEAVE} so that the +output has an equivalence sign in place of the equals sign in the \.{WEB} +file; i.e., the output says `$\langle\,$module +name$\,\rangle\equiv\null$\PASCAL\ text'. +However, in the case of the second +and subsequent appearances of a module with the same name, this `$\equiv$' +sign is replaced by `$\mathrel+\equiv$', as an indication that the \PASCAL\ +text that follows is being appended to the \PASCAL\ text of another +module. + + +The general idea of \.{WEAVE} is to make a \.{TEX} file from the \.{WEB} +file in the following way: The first line of the \.{TEX} file will be +`\.{\\input \PAS web}'; this will cause \TeX\ to read in the macros that +define \.{WEB}'s documentation conventions +\newstuff +for the \PASCAL\ programming language. +\endnewstuff +The next lines of the file +will be copied from whatever \TeX\ text is in limbo before the first +module. +Then comes the output for each module in turn, possibly +interspersed with end-of-page marks. +Finally, \.{WEAVE} will generate a +cross-reference index that lists each module number in which each \PASCAL\ +identifier appears, and it will also generate an alphabetized list +of the module names, as well as a table of contents that +shows the page and module numbers for each ``starred'' module. + +What is a ``starred'' module, you ask? +A module that begins with `\.{@*}' +instead of `\.{@\ }' is slightly special in that it denotes a new major +group of modules. +The `\.{@*}' should be followed by the title of this +group, followed by a period. +Such modules 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 module. +The title will also +appear in the table of contents, and in boldface type at the beginning of +its module. + +\newstuff +Spidery {\tt WEB} supports a hack that makes the module structure +appear more hierarchical in the table of contents. +If the title begins with the special character {\tt =}, or one of the +digits {\tt 1}~through~{\tt 4}, it will be formatted specially. +This table shows the effect of the special titles: +\medskip +{ +\tabskip=0pt plus 1fil +\noindent\halign to \hsize{\strut\tt#\hfil +\tabskip=2em&#\hfil&\hfil #\hfil&#\hfil\tabskip=0pt plus 1fil\cr +\bf Marker&\bf Level&\bf Page Eject?&\bf Other\cr +\noalign{\smallskip} +@*=&chapter&yes&Bold in toc\cr +@*§ion&yes\cr +@*1&subsection&yes\cr +@*2&subsection&no\cr +@*3&subsubsection&yes\cr +@*4&subsubsection&no\cr +} +} +\medskip +\endnewstuff + +Caution: Do not use \TeX\ control sequences in such titles, +unless you know that the \.{webmac} 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 modules, 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. + +\newstuff +Second caution: +do not allow the titles to begin with a non-letter, unless the +non-letter is the control sequence \.{\\relax}. +The reason is that the first character of the titles is checked to see +whether it is the special character {\tt =}, or one of the +digits {\tt 1}~through~{\tt 4}. +A non-letter that is not one of these will only confuse the formatter. +\endnewstuff + +The \TeX\ output produced by \.{WEAVE} for each module consists of +the following: First comes the module number (e.g., `\.{\\M123.}' +at the beginning of module 123, except that `\.{\\N}' appears in place of +`\.{\\M}' at the beginning of a starred module). +Then comes the +\TeX\ part of the module, copied almost verbatim except as noted +below. +Then comes the definition part and the \PASCAL\ part, formatted +so that there will be a little extra space between them if both are +nonempty. +The definition and \PASCAL\ parts are obtained by inserting +a bunch of funny looking \TeX\ macros into the \PASCAL\ program; these +macros handle typographic details about fonts and proper math spacing, +as well as line breaks and indentation. + +When you are typing \TeX\ text, you will probably want to make frequent +reference to variables and other quantities in your \PASCAL\ 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 \.{WEB} language allows you to get the effect of +\PASCAL\ editing within \TeX\ text, if you place `\.|' marks before and +after the \PASCAL\ material. +For example, suppose +\newstuff +you are writing Pascal code and +\endnewstuff +you want to say something +like this: +$$\hbox{The characters are placed into \\{buffer}, which is a +\&{packed} \&{array} $[1\to\|n]$ \&{of} \\{char}.}$$ +The \TeX\ text would look like this in your \.{WEB} file: +$$\.{The characters are placed into |buffer|, which is a |packed +array [1..n] of char|.}$$ +And \.{WEAVE} translates this into something you are glad you didn't have +to type: +$$\lpile{\.{The characters are placed into \\\\\{buffer\},}\cr + \.{which is a \\\&\{packed\}{ }\\\&\{array\}{ }\$ + [1\\to\\|n]\${ }\\\&\{of\}{ }\\\\\{char\}.}\cr}$$ +Incidentally, the cross-reference index that \.{WEAVE} would make, in +the presence of a comment like this, would include +the current module number as one of the index entries for \\{buffer} +and \\{char}, even though \\{buffer} and \\{char} +might not appear in the \PASCAL\ part of +this module. +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 +\&{packed} and \&{array} and \|n\ and \&{of\/} would not be indexed, +because \.{WEAVE} 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. + +Speaking of identifiers, the author of \.{WEB} thinks that +\\{IdentifiersSeveralWordsLong} look terribly ugly when they mix +uppercase and lowercase letters. +He recommends that +\\{identifiers\_several\_words\_long} be written with underline characters +to get a much better effect. +%The actual identifiers sent to the \PASCAL\ +%compiler by \.{TANGLE} will have such underlines removed, and \.{TANGLE} +%will check to make sure that two different identifiers do not become +%identical when this happens. +%(In fact, \.{TANGLE} even checks that +%the first seven characters of identifiers are unique, when lowercase +%letters have been converted to uppercase; the number seven in this +%constraint is more strict than \PASCAL's eight, and it can +%be changed if desired.) +The \.{WEAVE} processor will properly +alphabetize identifiers that have embedded underlines +when it makes the index. +\newstuff +Using Spidery \.{WEB}, you're out of luck if programming language +\PASCAL\ doesn't support underlines in identifiers. +\endnewstuff + +Although a module begins with \TeX\ text and ends with \PASCAL\ text, we +have noted that the dividing line isn't sharp, since \PASCAL\ text can be +included in \TeX\ text if it is enclosed in `\pb'. +Conversely, \TeX\ text +also appears frequently within \PASCAL\ text, because everything in +\PASCAL\ comments is treated as \TeX\ text. +Furthermore, a module name consists of \TeX\ text; thus, a \.{WEB} file +typically involves constructions like `\.{if} \.x \.= \.0 \.{then} +\.{@<Empty} \.{the} \.{|buffer|} \.{array@>}' where we go back and forth +between \PASCAL\ and \TeX\ conventions in a natural way. + +\section Macros. +\newstuff +In the current implementation of Spidery \.{WEB}, a \.{WEB} programmer +can define two kinds of macros to make the programs shorter and more +readable. + +\yskip\hang`\.{@d} \\{identifier} \.{=} \PASCAL\ text' defines a {\sl +simple\/} macro, where the identifier will be replaced by the \PASCAL\ text +when \.{TANGLE} produces its output. + +\yskip\hang`\.{@d} \\{identifier} \.{(}\\{formal parameters}\.{)} +\.{=} \PASCAL\ text' defines a +{\sl parametric\/} macro, where the identifier will be replaced by the +\PASCAL\ +text and where occurrences of the \\{formal parameters} in that +\PASCAL\ text will be replaced by arguments. +For C programmers, this is similar to the C macro processor, but +the \.{=} sign is used to avoid the need for bizarre lexical +requirements. +Whitespace can appear between a macro name and a list of formal +paramters, and newlines in macros need not be escaped with +backslashes. +A macro definition is terminated by a following \.{@d}, \.{@f}, +\.{@u}, \.{@<}, or \.{@(}. +\endnewstuff + + + + +%A \.{WEB} programmer can define three kinds of macros to make the programs +%shorter and more readable: +% +%\yskip\hang`\.{@d} \\{identifier} \.= \\{constant}' defines a {\sl numeric\/} +%macro, allowing \.{TANGLE} to do rudimentary arithmetic. +% +%\yskip\hang`\.{@d} \\{identifier} \.{==} \PASCAL\ text' defines a {\sl +%simple\/} macro, where the identifier will be replaced by the \PASCAL\ text +%when \.{TANGLE} produces its output. +% +%\yskip\hang`\.{@d} \\{identifier}\.{(\#) ==} \PASCAL\ text' defines a +%{\sl parametric\/} macro, where the identifier will be replaced by the \PASCAL\ +%text and where occurrences of \.{\#} in that \PASCAL\ text will be +%replaced by an argument. +% +%\yskip\noindent In all three cases, the identifier must have length greater +%than one; it must not be a single letter. +%Furthermore, the identifier must +%be making its first appearance in the \.{WEB} file; a macro must be defined +%before it is used. +% +%Numeric macros are subject to the following restrictions:\quad +%(1)~The right-hand side of the numeric definition must be made entirely from +%integer constants, numeric macros, preprocessed strings (see below), and +%plus~signs or minus signs. +%No other operations or symbols are allowed, +%not even parentheses, except that \PASCAL-like comments (enclosed in +%braces) can appear. +%Indeed, comments are recommended, since it is usually +%wise to give a brief explanation of the significance of each identifier as +%it is defined.\quad +%(2)~The numeric value must be less than $2^{15}=32768$ in absolute value. +%(For larger values, you can use `\.{==}' in place of~`\.=', thus making use +%of a simple macro instead of a numeric one. +%Note, however, that simple +%macros sometimes have a different effect. +%For example, consider the three +%definitions `\.{@d n1=2 @d n2=2+n1 @d n3==2+n1}'; then `\.{x-n2}' will +%expand into `\.{x-4}', while `\.{x-n3}' will expand into `\.{x-2+2}' which +%is quite different! It is wise to include parentheses in non-numeric +%macros, e.g., `\.{@d n3==(2+n1)}', to avoid such errors.) +% +%When constants are connected by plus signs or minus +%signs in an \PASCAL\ program, \.{TANGLE} does the arithmetic before putting +%the constant into the output file. +%Therefore it is permissible to say, for +%example, `\&{array} $[0\,.\,.\,\\{size}-1]$' if \\{size} has been declared +%as a macro; note that \PASCAL\ doesn't allow this kind of compile-time +%arithmetic if \\{size} is a \&{constant} quantity in the program. +%Another +%use of \.{TANGLE}'s arithmetic is to make \&{case} statement labels such +%as `$\\{flag}+1$' legitimate. +%Of course, it is improper to change \.{2+2} +%into \.4 without looking at the surrounding context; many counterexamples +%exist, such as the phrases `\.{-2+2}', `\.{x/2+2}', and `\.{2+2E5}'. +%The +%program for \.{TANGLE}, in the appendix, gives precise details about this +%conversion, which \.{TANGLE} does only when it is safe. +% +%The right-hand sides of simple and parametric macros +%are required to have balanced parentheses, and the \PASCAL\ texts of +%modules must have balanced parentheses too. +%Therefore when the argument +%to a para\-metric macro appears in parentheses, both parentheses +%will belong to the same \PASCAL\ text. +% +%The appendices to this report contain hundreds of typical examples of the +%usefulness of \.{WEB} macros, so it is not necessary to dwell on the +%subject here. +%However, the reader should know that \.{WEB}'s apparently +%primitive macro capabilities can actually do a lot of rather surprising +%things. +%Here is a construction that sheds further light on what is +%possible: After making the definitions +%$$\catcode`\#=12 +%\lpile{\.{@d two\_cases(#)==case j of 1:#(1); 2:#(2); end}\cr +%\.{@d reset\_file(#)==reset(input\_file@\&#)}\cr}$$ +%one can write `\.{two\_cases(reset\_file)}' and the resulting \PASCAL\ +%output will be +%$$\.{case j of 1:reset(input\_file1); 2:reset(input\_file2); end}$$ +%(but in uppercase letters and with \.\_'s removed). +%The `\.{@\&}' operation used here joins together two adjacent tokens +%into a single token, as explained later; otherwise the \PASCAL\ file would +%contain a space between \.{input\_file} and the digit that followed it. +%This trick can be used to provide the effect of an array of files, if you +%are unfortunate enough to have a \PASCAL\ compiler that doesn't allow such +%arrays. +%Incidentally, the cross-reference index made by \.{WEAVE} from +%this example would contain the identifier \\{input\_file} but it would not +%contain \\{input\_file1} or \\{input\_file2}. +%Furthermore, \.{TANGLE} +%would not catch the error that \.{INPUTFILE1} and \.{INPUTFILE2} both +%begin with the same nine letters; one should be more careful when using +%`\.{@\&}'! But such aspects of the construction in this trick are +%peripheral to our main point, which is that a parametric macro name without +%arguments can be used as an argument to another parametric macro. +% +%Although \.{WEB}'s macros are allowed to have at most one parameter, the +%following example shows that this is not as much of a restriction as it +%may seem at first. +%Let \\{amac} and \\{bmac} be any parametric macros, and +%suppose that we want to get the effect of +%$$\catcode`\#=12 +%\.{@d cmac(#1,#2) == amac(#1) bmac(#2)}$$ +%which \.{WEB} doesn't permit. +%The solution is to make the definitions +%$$\catcode`\#=12 +%\lpile{\.{@d cmac(#) == amac(#) dmac}\cr +%\.{@d dmac(#) == bmac(#)}\cr}$$ +%and then to say `\.{cmac(x)(y)}'. +% +%There is one restriction in the generality of \.{WEB}'s parametric +%macros, however: the argument to a para\-metric macro must not come from +%the expansion of a macro that has not already been ``started.'' For +%example, here is one of the things \.{WEB} cannot handle: +%$$\catcode`\#=12 +%\lpile{\.{@d arg == (p)}\cr +%\.{@d identity(#) == #}\cr +%\.{@p identity arg}\cr}$$ +%In this case \.{TANGLE} will complain that the \.{identity} macro is not +%followed by an argument in parentheses. + +%The \.{WEB} language has another feature that is somewhat similar to a +%numeric macro. +%A {\sl preprocessed string\/} is a string that is like +%a \PASCAL\ string but delimited by double-quote marks (\.") instead of +%single-quotes. +%Double-quote marks inside of such strings are indicated by +%giving two double-quotes in a row. +%If a preprocessed string is +%of length one (e.g., \.{"A"} or \.{""""}), it will be treated by \.{TANGLE} +%as equivalent to the corresponding ASCII-code integer (e.g., \.{65} or +%\.{34}). +%And if a preprocessed string is not of length one, it will be +%converted into an integer equal to 128 or more. +%A {\sl string pool\/} +%containing all such strings will be written out by the \.{TANGLE} +%processor; this string pool file consists of string 128, then string 129, +%etc., where each string is followed by an end-of-line and prefixed by two +%decimal digits that define its length. +%Thus, for example, the empty string +%\.{""} would be represented in the string pool file by a line containing +%the two characters `\.{00}', while the string \.{"""String"""} would be +%represented by `\.{08"String"}'. +%A given string appears at most once in +%the string pool; the use of such a pool makes it easier to cope with +%\PASCAL's restrictions on string manipulation. +%The string pool ends with +%`\.{*nnnnnnnnn}', where \.{nnnnnnnnn} is a decimal number +%called the {\sl string pool check sum}. +%If any string changes, the check +%sum almost surely changes too; thus, the `\.{@\$}' feature +%described below makes it possible for a program to assure itself that it +%is reading its own string pool. +% +%Here is a simple example that combines numeric macros with preprocessed +%strings of length one: +%$$\lpile{\.{@d upper\_case\_Y = "Y"}\cr +%\.{@d case\_difference = -"y"+upper\_case\_Y}\cr}$$ +%The result is to define +%$\\{upper\_case\_Y}=89$, $\\{case\_difference}=-32$. + +\newstuff +Spidery \.{WEB} does not support a string pool file. +Pleas for its restoration will be heard. +\endnewstuff + +\section Control codes. +We have seen several magic uses of `\.{@}' signs in \.{WEB} files, and it +is time to make a systematic study of +these special features. +A \.{WEB} {\sl control code\/} +is a two-character combination of which the first is `\.@'. +\newstuff +In Spidery \.{WEB} the ``magic at sign'' need not be `\.@'; the person +who built your \.{WEB} (with {Spider}) may have defined it to be +something else. +By convention, people building Spidery {\tt WEB}s + use `\.@' as the magic at sign, except when it is +deemed unsuitable for some reason, in which case + cases they use `\.\#'. +\endnewstuff + +Here is a complete list of the legal control codes. +The letters $L$, $T$, +$\PAS$, $M$, $C$, and/or $S$ following each code indicate whether or not that +code is allowable in limbo, in \TeX\ text, in \PASCAL\ text, in module +names, in comments, and/or in strings. +A bar over such a letter means +that the control code terminates the present part of the \.{WEB} file; for +example, $\overline L$ means that this control code ends the limbo material +before the first module. + +\def\@#1[#2] {\yskip\hangindent 2em\noindent\.{@#1\unskip + \spacefactor1000{ }}$[#2]$\quad} +\def\oT{\overline T} + +\@@ [C,L,M,\PAS,S,T] A double \.@ denotes the single character `\.@'. +This is +the only control code that is legal in limbo, in comments, and in strings. + +\@i [L,T] +\newstuff +The \.{@i} control code should always be followed by a file name and a +newline. +It causes the file to be included at the current point in the +\.{WEB} source, just like the C \.{\#include} facility. +\endnewstuff + +\@\ [\overline L,\oP,\oT] This denotes the beginning of a new +(unstarred) module. +A tab mark or end-of-line (carriage return) +is equivalent to a space when it follows an \.@ sign. + +\@* [\overline L,\oP,\oT] This denotes the beginning of a new starred +module, i.e., a module that begins a new major group. +The title of the new +group should appear after the \.{@*}, followed by a period. +\newstuff +As explained above, the first character of the title should be either +a letter or the control sequence \.{\\relax}, unless special +formatting is desired. +Titles beginning with \.=, \.1, \.2, \.3, or \.4 are formatted +specially. +\endnewstuff +As explained +above, \TeX\ control sequences should be avoided in such titles unless +they are quite simple. +When \.{WEAVE} and \.{TANGLE} read a \.{@*}, they +print an asterisk followed by the current module number, so that the user +can see some indication of progress. +The very first module should be starred. + +\@d [\oP,\oT] Macro definitions begin with \.{@d} (or \.{@D}), followed by +the \PASCAL\ text for one of the three kinds of macros, as explained +earlier. + +\@f [\oP,\oT] Format definitions begin with \.{@f} (or \.{@F}); they cause +\.{WEAVE} to treat identifiers in a special way when they appear in +\PASCAL\ text. +The general form of a format definition is `\.{@f} \|l %\.{=} +\|r', followed by an optional comment enclosed in braces, where \|l and \|r +are identifiers; \.{WEAVE} will subsequently treat identifier \|l as it +currently treats \|r. +This feature allows a \.{WEB} programmer to invent +new reserved words and/or to unreserve some of \PASCAL's reserved +identifiers. +\newstuff +It is offensive that the syntax is different from the \.{2d} syntax, +but it is that way for historical reasons (to avoid invalidating +existing code. +\endnewstuff +The definition part of each module consists of any number of +macro definitions (beginning with \.{@d}) and format definitions (beginning +with \.{@f}), intermixed in any order. + + +\@u [\oP,\oT] \newstuff +The \PASCAL\ part of an unnamed module begins with \.{@u} +(or \.{@U}). +\endnewstuff +This causes \.{TANGLE} to append the following \PASCAL\ code +to the initial program text $T_0$ as explained above. +The \.{WEAVE} +processor does not cause a `\.{@u}' to appear explicitly in the \TeX\ +output, so if you are creating a \.{WEB} file based on a \TeX-printed +\.{WEB} documentation you have to remember to insert \.{@u} in the +appropriate places of the unnamed modules. + +\@< [\PAS,\oT] A module name begins with \.{@<} followed by \TeX\ text followed +by \.{@>}; the \TeX\ text should not contain any \.{WEB} control sequences +except \.{@@}, unless these control sequences appear in \PASCAL\ text that +is delimited by \pb. +The module name may be abbreviated, after its first +appearance in a \.{WEB} file, by giving any unique prefix followed by \.{...}, +where the three dots immediately precede the closing \.{@>}. +Module names may +not appear in \PASCAL\ text that is enclosed in \pb, nor may they appear +in the definition part of a module (since the appearance of a module name +ends the definition part and begins the \PASCAL\ part). + + +\@( [\PAS,\oT] \newstuff A module beginning +with \.{@(} is treated like one beginning with \.{@<}, +except that the module name is treated as the name of a file to which +the module will be written. +If such modules are used in other modules the results are undefined. +\endnewstuff + +\@\' [\PAS,T] This denotes an octal constant, to be formed from the +succeeding digits. +For example, if the \.{WEB} file contains `\.{@\'100}', +the \.{TANGLE} processor will treat this an equivalent to `\.{64}'; +the constant will be formatted as ``\O{\~100}'' in the \TeX\ output +produced via \.{WEAVE}. +You should use octal notation only for positive +constants; don't try to get, e.g., $-1$ by saying `\.{@\'777777777777}'. + +\@" [\PAS,T] A hexadecimal constant; `\.{@"D0D0}' tangles to \.{53456} and +weaves to `\O{\^D0D0}'. + +%\@\$ [\PAS] This denotes the string pool check sum. + +%\@\{ [\PAS] The beginning of a ``meta comment,'' i.e., a comment +%that is supposed to appear in the \PASCAL\ code, is indicated by +%\.{@\{} in the \.{WEB} file. +%Such delimiters can be used as +%isolated symbols in macros or modules, but they should be properly nested +%in the final \PASCAL\ program. +%The \.{TANGLE} processor will convert +%`\.{@\{}' into `\.\{' in the \PASCAL\ output file, unless +%the output is already part of a meta-comment; in the latter case +%`\.{@\{}' is converted into `\.[', since +%we don't assume that \PASCAL\ allows +%nested comments. +%Meta-comments +%can be used to put conditional text into an \PASCAL\ program; this helps to +%overcome one of the limitations of \.{WEB}, since the simple macro +%processing routines of \.{TANGLE} do not include the dynamic evaluation of +%boolean expressions. +%\newstuff +%Where is this trick explained, and note that it only works in +%languages whose comments don't end with newline. +%\endnewstuff +% +%\@\} [\PAS] The end of a ``meta comment'' is indicated by `\.{@\}}'; this is +%converted either into `\.\}' or `\.{]}' in the \PASCAL\ output, according +%to the conventions explained for \.{@\{} above. + +\@\& [\PAS] The \.{@\&} operation causes whatever is on its left to be +adjacent to whatever is on its right, in the \PASCAL\ output. +No spaces or +line breaks will separate these two items. +However, the thing on the left +should not be a semicolon, since a line break might occur after a semicolon. + +\@\^ [\PAS,T] The ``control text'' that follows, up to the next +`\.{@>}', will be entered into the index together with the identifiers of +the \PASCAL\ program; this text will appear in roman type. +For example, to +put the phrase ``system dependencies'' into the index, you can type +`\.{@\^system dependencies@>}' in each module +that you want to index as system dependent. +A control text, like a string, +must end on the same line of the \.{WEB} file as it began. +Furthermore, +no \.{WEB} control sequences are allowed in a control text, not even +\.{@@}. +(If you need an \.{@} sign you can get around this restriction by +typing `\.{\\AT!}'.) + +\@. +[\PAS,T] The ``control text'' that follows will be entered into the index +in \.{typewriter} \.{type}; see the rules for `\.{@\^}', which is analogous. + +\@: [\PAS,T] The ``control text'' that follows will be entered into the index +in a format controlled by the \TeX\ macro `\.{\\9}', which the user +should define as desired; see the rules for `\.{@\^}', which is analogous. + +\@t [\PAS] The ``control text'' that follows, up to the next `\.{@>}', will +be put into a \TeX\ \.{\\hbox} and formatted along with the neighboring +\PASCAL\ program. +This text is ignored by \.{TANGLE}, but it can be used +for various purposes within \.{WEAVE}. +For example, you can make comments +that mix \PASCAL\ and classical mathematics, as in `$\\{size}<2^{15}$', by +typing `\.{|size < @t\$2\^\{15\}\$@>|}'. +A control text must end on the +same line of the \.{WEB} file as it began, and it may not contain any +\.{WEB} control codes. + +\@= [\PAS] The ``control text'' that follows, up to the next `\.{@>}', will +be passed verbatim to the \PASCAL\ program. + +%%% \@\\ [\PAS] Force end-of-line here in the \PASCAL\ program file. + +\@! [\PAS,T] The module 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 modules where an identifier is +defined, or where it is explained in some special way, from the modules +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 \.{WEAVE} just after the reserved words \&{function}, \&{procedure}, +%\&{program}, and \&{var}, and just after \.{@d} and \.{@f}. +%But you should +%insert your own `\.{@!}' before the definitions of types, constants, +%variables, parameters, and components of records and enumerated types that +%are not covered by this implicit convention, if you want to improve the +%quality of the index that you get. +\newstuff +Some Spidery \.{WEAVE}s will insert implicit `\.{@!}' tokens in places +like function definitions or variable declarations. +The person who built your Spidery \.{WEB} should have documented these +places; if not, they can be discovered by examing the {\tt .spider} +file. +The automatic definitions work well for some languages, but +for the best possible index you should insert your own `\.{@!}' token before +the defining instance of every identifier. +\endnewstuff + +\@? +[\PAS,T] This cancels an implicit (or explicit) `\.{@!}', so that the next +index entry will not be underlined. +\newstuff This is not implemented in the current version of Spidery \.{WEB}. +\endnewstuff + +\@, [\PAS] This control code inserts a thin space in \.{WEAVE}'s output; it is +ignored by \.{TANGLE}. +Sometimes you need this extra space if you are using +macros in an unusual way, e.g., if two identifiers are adjacent. + +\@/ [\PAS] This control code causes a line break to occur within an \PASCAL\ +program formatted by \.{WEAVE}; it is ignored by \.{TANGLE}. +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. +\newstuff +The line following such a line break is indented at the same level as +the line broken. +\endnewstuff +Caution: `\.{@/}' should be used only after statements or clauses, not in +the middle of an expression; use \.{@|} in the middle of expressions, in +order to keep \.{WEAVE}'s parser happy. + +\@- [\PAS] \newstuff +This control code makes \.{WEAVE} continue the current +statement on the next line; it is ignored by \.{TANGLE}. +If is just like `\.{@/}', except that the following line is indented, +to show that it is a continuation of the line broken. +\endnewstuff + +\@| [\PAS] This control code specifies an optional line break in the midst of +an expression. +For example, if you have a long condition between \&{if} and +\&{then}, or 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. + +\@\# [\PAS] 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 procedure definitions or +between groups of macro definitions that are logically separate but within +the same module. + +\@+ [\PAS] This control code cancels a line break that might otherwise be +inserted by \.{WEAVE}, e.g., before the word `\&{else}', if you want to +put a short if-then-else construction on a single line. +It is ignored by +\.{TANGLE}. + +\@; [\PAS] Usually this control code is treated like a semicolon, for +formatting purposes, except that it is invisible. +\newstuff +The person who built your \.{WEB} can redefine it, though, so check +his documentation to make sure. +\endnewstuff + +You can use it, for example, after +a module name when the \PASCAL\ text represented by that module name ends +with a semicolon. + +\yskip\noindent +The last \newstuff seven \endnewstuff + control codes (namely `\.{@,}', `\.{@/}', `\.{@-}', `\.{@|}', +`\.{@\#}', `\.{@+}', and `\.{@;}') have no effect on the \PASCAL\ +program output by \.{TANGLE}; they merely help to improve the readability +of the \TeX-formatted \PASCAL\ that is output by \.{WEAVE}, in unusual +circumstances. +\.{WEAVE}'s built-in formatting method is fairly good, but +it is incapable of handling all possible cases, because it must deal with +fragments of text involving macros and module names; these fragments do +not necessarily obey \PASCAL's syntax. +Although \.{WEB} allows you to +override the automatic formatting, your best strategy is not to worry +about such things until you have seen what \.{WEAVE} produces automatically, +since you will probably need to make only a few corrections when you are +touching up your documentation. + +Because of the rules by which every module is broken into three parts, +the control codes `\.{@d}', `\.{@f}', and `\.{@u}' are not allowed to occur +once the \PASCAL\ part of a module has begun. + +\section Additional features and caveats. + +%1. +%The character pairs `\.{(*}', `\.{*)}', `\.{(.}', and `\.{.)}' are +%converted automatically in \PASCAL\ text as though they were +%`\.{@\{}', `\.{@\}}', `\.[', and `\.]', respectively, except +%%of course in strings. +%Furthermore in certain installations of \.{WEB} that +%{\def\\#1#2{`{\tentex\char'#1#2}'}% +%have an extended character set, the characters \\32, \\34, \\35, \\30, +%\\36, \\04, \\37, \\05, and \\06} +%can be used as abbreviations for +%`\.{<>}', `\.{<=}', `\.{>=}', `\.{:=}', `\.{==}', `\.{and}', `\.{or}', +%`\.{not}', and `\.{in}', respectively. +%However, the latter abbreviations +%are not used in the standard versions of \.{WEAVE.WEB} and \.{TANGLE.WEB} +%that are distributed to people who are installing \.{WEB} on other +%computers, and the programs are designed to produce only standard ASCII +%characters as output if the input consists entirely of ASCII characters. +% +%2. +%If you have an extended character set, all of the characters listed +%in Appendix C of {\sl The \TeX book\/} can be used in strings. +%But you should +%stick to standard ASCII characters if you want to write programs that will +%be useful to the all the poor souls out there who don't have extended +%character sets. + +3. +The \TeX\ file output by \.{WEAVE} is broken into lines having at most +80 characters each. +The algorithm that does this line breaking is unaware +of \TeX's convention about comments following `\.\%' signs on a line. +When +\TeX\ text is being copied, the existing line breaks are copied as well, +so there is no problem with `\.\%' signs unless the original \.{WEB} file +contains a line more than eighty characters long or a line with \PASCAL\ +text in \pb\ that expands to more than eighty characters long. +Such lines +should not have `\.\%' signs. + +4. +\PASCAL\ 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 +\newstuff prettyprinting \endnewstuff +grammar. +The grammar and the translation process are explained in the +``Spider User's Guide.'' +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 \.{WEAVE} does, but the general mechanism is somewhat complex because +it must handle much more than \PASCAL\ 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 adhere to the following restrictions: + +\yskip\itemitem{a)}Comments in \PASCAL\ text should appear only after +statements or clauses; i.e., +\newstuff(if \PASCAL\ were PASCAL) \endnewstuff +after semicolons, after reserved words like +\&{then} and \&{do}, or before reserved words like \&{end} and \&{else}. +Otherwise \.{WEAVE}'s parsing method may well get mixed up. + +\itemitem{b)}Don't enclose long \PASCAL\ texts in \pb, since the +indentation and line breaking codes are omitted when the \pb\ text is +translated from \PASCAL\ to \TeX. +Stick to simple expressions or +statements. + +\yskip +5. +Comments and module names are not permitted in \pb\ text. +After a `\.|' +signals the change from \TeX\ text to \PASCAL\ text, the next `\.|' that is +not part of a string or control text ends the \PASCAL\ text. + +6. +\newstuff +Spidery {\tt WEB} does not handle nested comments. +\endnewstuff +%A comment must have properly nested occurrences of left and right +% braces, otherwise \.{WEAVE} and \.{TANGLE} will not know where the comment +% ends. +%However, the character pairs `\.{\\\{}' and `\.{\\\}}' do not count +%as left and right braces in comments, and the character pair `\.{\\|}' +%does not count as a delimiter that begins \PASCAL\ text. +%(The actual rule +%is that a character after `\.\\' is ignored; hence in `\.{\\\\\{}' the +%left brace {\sl does\/} count.) At present, \.{TANGLE} and \.{WEAVE} treat +%comments in slightly different ways, and it is necessary to satisfy both +%conventions: \.{TANGLE} ignores `\.|' characters entirely, while \.{WEAVE} +%uses them to switch between \TeX\ text and \PASCAL\ text. +%Therefore, a +%comment that includes a brace in a string in \pb---e.g., `\.{\{{ }look at +%this |"\{"| \}}'---will be handled correctly by \.{WEAVE}, but \.{TANGLE} +%will think there is an unmatched left brace. +%In order to satisfy both +%processors, one can write `\.{\{{ }look at this \\leftbrace\\{ }\}}', after +%setting up`\.{\\def\\leftbrace\{|"\{"|\}}'. + +7. +Reserved words of \PASCAL\ must appear entirely in lowercase letters +in the \.{WEB} file; otherwise their special nature will not be recognized +by \.{WEAVE}. +\newstuff +This could be changed, but the author of Spidery {\tt WEB} does not +believe in case-insensitivity for programming languages. +\endnewstuff +You could, for example, have a macro named \\{END} and it +would not be confused with \&{end}. + +However, you may not want to capitalize macro names just to distinguish them +from other identifiers. +Here is a way to unreserve Pascal's reserved word +`\&{type}' and to substitute another word `\&{mtype}' in the \.{WEB} file. +$$\vbox{\halign{\tt #\hfil\cr +@d type(\char'43) = mem[\char'43].t\cr +@d mtype = t \char'100\char'46{} y \char'100\char'46{} p + \char'100\char'46{} e\cr +@f mtype = type\cr +@f type = true\cr}}$$ +In the output of \.{TANGLE}, the macro \.{mtype} now produces `\.{TYPE}' +and the macro \.{type(x)} now produces `\.{MEM[X].T}'. +In the output of +\.{WEAVE}, these same inputs produce \&{mtype} and \\{type}(\|x), +respectively. + +8. +The \.{@f} feature allows you to define one identifier to act like +another, and these format definitions are carried out sequentially, as the +example above indicates. +However, a given identifier has only one printed format +throughout the entire document (and this format will even be used before +the \.{@f} that defines it). +The reason is that \.{WEAVE} operates in two +passes; it processes \.{@f}'s and cross-references on the first pass and +does the output on the second. + +9. +You may want some \.{@f} formatting that doesn't correspond to any +existing reserved word. +In that case, \.{WEAVE} could be extended +\newstuff +by someone who built Spidery {\tt WEB} +\endnewstuff +to include new ``reserved words'' in its vocabulary. +\newstuff +(The ``\/{Spider} User's Guide'' explains how.) +\endnewstuff + +%The identifier `\&{xclause}' has in fact been included already as a +%reserved word, so that it can be used to format the `\&{loop}' macro, +%where `\&{loop}' is defined to be equivalent to `\&{while \\{true} do}'. + +10. +Sometimes it is desirable to insert spacing into \PASCAL\ 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 \.{webmac} 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.) + +11. +\.{WEAVE} and \.{TANGLE} 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 \.{WEB} file elsewhere in this +report. + +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. + +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. + +This dual-input feature is useful when working with a master \.{WEB} file +that has been received from elsewhere (e.g., \.{TANGLE.WEB} or +\.{WEAVE.WEB} 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. + +\newstuff +There are several multiple-changefile tools in the {\TeX} community; +check back issues of TUGboat for more information. +\endnewstuff + +\section Appendices. +% The basic ideas of \.{WEB} can be understood most easily by looking at +% examples of ``real'' programs. +% Appendix~A shows the \.{WEB} input that +% generated modules 55--59 of the \.{WEAVE} program; Appendix~B shows the +% corresponding \TeX\ code output by \.{WEAVE}; and Appendix~C shows excerpts +% from the corresponding \PASCAL\ code output by \.{TANGLE}. +% +% The complete webs for \.{WEAVE} and \.{TANGLE} appear as the bulk of this +% report, in Appendices D and~E. +% The reader should first compare Appendix~A +% to the corresponding portion of Appendix~D; then the same material should +% be compared to Appendices B and~C. +% Finally, if time permits, the reader may +% enjoy studying the complete programs in Appendices D and~E, since \.{WEAVE} +% and \.{TANGLE} contain several interesting aspects, and since an attempt +% has been made in these appendices to evolve a style of programming that +% makes good use of the \.{WEB} language. +% +% Finally, Appendix F is the `\.{webkernel}' file that sets \TeX\ up to accept +% the output of \.{WEAVE}; Appendix~G discusses how to use some of its macros +% to vary the output formats; and Appendix~H discusses what needs to be done +% when \.{WEAVE} and \.{TANGLE} are installed in a new operating environment. +% +% \section Performance statistics. +% The programs in Appendices D and E will optionally keep statistics on +% how much memory they require. +% Here is what they printed out when +% processing themselves: +% +% \def\pstat#1#2#3 +% #4{\yskip\noindent\.{#1} applied to \.{#2} (cpu time #3 sec)\par +% \halign{\quad\tt##\hfil\cr#4}} +% +% \pstat{TANGLE}{TANGLE}{15} +% {Memory usage statistics:\cr +% 456 names, 215 replacement texts;\cr +% 3396+3361 bytes, 6685+7329+5805 tokens.\cr} +% +% \pstat{TANGLE}{WEAVE}{30} +% {Memory usage statistics:\cr +% 692 names, 339 replacement texts;\cr +% 4576+4294 bytes, 10184+9875+9150 tokens.\cr} +% +% \pstat{WEAVE}{TANGLE}{45} +% {Memory usage statistics: 478 names, 2045 cross references, 4159+3729 bytes;\cr +% parsing required 684 scraps, 1300 texts, 3766 tokens, 119 levels;\cr +% sorting required 34 levels.\cr} +% +% \pstat{WEAVE}{WEAVE}{65} +% {Memory usage statistics: 737 names, 3306 cross references, 4896+4962 bytes;\cr +% parsing required 684 scraps, 1300 texts, 3766 tokens, 119 levels;\cr +% sorting required 73 levels.\cr} +% +% \yskip\noindent The cpu time for \PASCAL\ to process \.{TANGLE.PAS} was +% approximately 13 seconds, and \.{WEAVE.PAS} took approximately 26 seconds; +% thus the tangling time was slightly more than the compiling time. +% The cpu +% time for \TeX\ to process \.{TANGLE.TEX} was approximately 500 seconds, +% and \.{WEAVE.TEX} took approximately 750 seconds (i.e., about 7 +% seconds per printed page, where these pages are substantially larger than +% the pages in a normal book). +% All cpu times quoted are for a DECsystem-10. +% +% \def\K{{\mc K}} +% The file \.{TANGLE.WEB} is about 125\K\ characters long; \.{TANGLE} +% reduces it to a file \.{TANGLE.PAS} whose size is about 42\K\ characters, +% while \.{WEAVE} expands it to a file \.{TANGLE.TEX} of about 185\K\null. +% The corresponding file sizes for \.{WEAVE.WEB}, \.{WEAVE.PAS}, and +% \.{WEAVE.TEX} are 180\K, 89\K, and 265\K. +% +% The much larger file \.{TEX.WEB} led to the following numbers: +% +% \pstat{TANGLE}{TEX}{110} +% {Memory usage statistics:\cr +% 3750 names, 1768 replacement texts;\cr +% 41895+41053 bytes, 42378+45074+41091 tokens.\cr} +% +% \pstat{WEAVE}{TEX}{270} +% {Memory usage statistics: 3412 names, 19699 cross references, +% 37900+40232 bytes;\cr +% parsing required 685 scraps, 1303 texts, 3784 tokens, 104 levels;\cr +% sorting required 52 levels.\cr} +% +% \yskip\noindent +% \PASCAL\ did \.{TEX.PAS} in about 75 seconds; \TeX\ did \.{TEX.TEX} +% in about 3600. +% +% % Here is a quotation that could not really be omitted +% +% \vfill +% +% {\baselineskip9pt +% \halign to\hsize{\hfil\quoteit#\tabskip 0pt plus 100pt& +% \hfil\quoteit#\tabskip 0pt\cr +% O, what a tangled web we weave& +% O, what a tangled WEB we weave\cr +% When first we practise to deceive!& +% When \TeX\ we practise to conceive!\cr +% \noalign{\vskip 2pt} +% \quoterm ---SIR WALTER SCOTT, {\quoteit Marmion} 6:17 (1808)& +% \quoterm ---RICHARD PALAIS (1982)\cr +% }} +% \eject +% +% \def\runninghead{APPENDIX A --- {\tentt WEB} FILE FORMAT} +% \section Appendix A. +% This excerpt from \.{WEAVE.WEB} produced modules 55--59 in Appendix~D. +% Note that some of the lines are indented to show the program structure. +% The indentation is ignored by \.{WEAVE} and \.{TANGLE}, but users find +% that \.{WEB} files are quite readable if they have some such indentation. +% +% \vskip 6pt +% \begingroup \def\tt{\eighttt} \baselineskip9pt +% % Note to myself: I had to remove SAIL characters from the file here! +% % Also tabs replaced by double-space. +% The changes were made in WEAVE source. +% \verbatim +% @* Searching for identifiers. +% The hash table described above is updated by the |id_lookup| procedure, +% which finds a given identifier and returns a pointer to its index in +% |byte_start|. +% The identifier is supposed to match character by character +% and it is also supposed to have a given |ilk| code; the same name may be +% present more than once if it is supposed to appear in the index with +% different typesetting conventions. +% If the identifier was not already present, it is inserted into the table. +% +% Because of the way \.{WEAVE}'s scanning mechanism works, it is most convenient +% to let |id_lookup| search for an identifier that is present in the |buffer| +% array. +% Two other global variables specify its position in the buffer: the +% first character is |buffer[id_first]|, and the last is |buffer[id_loc-1]|. +% +% @<Glob...@>= +% @!id_first:0..long_buf_size; {where the current identifier begins in the buffer} +% @!id_loc:0..long_buf_size; {just after the current identifier in the buffer} +% @# +% @!hash:array [0..hash_size] of sixteen_bits; {heads of hash lists} +% +% @ Initially all the hash lists are empty. +% +% @<Local variables for init...@>= +% @!h:0..hash_size; {index into hash-head array} +% +% @ @<Set init...@>= +% for h:=0 to hash_size-1 do hash[h]:=0; +% +% @ Here now is the main procedure for finding identifiers (and index +% entries). +% The parameter |t| is set to the desired |ilk| code. +% The +% identifier must either have |ilk=t|, or we must have +% |t=normal| and the identifier must be a reserved word. +% +% @p function id_lookup(@!t:eight_bits):name_pointer; {finds current identifier} +% label found; +% var i:0..long_buf_size; {index into |buffer|} +% @!h:0..hash_size; {hash code} +% @!k:0..max_bytes; {index into |byte_mem|} +% @!w:0..ww-1; {row of |byte_mem|} +% @!l:0..long_buf_size; {length of the given identifier} +% @!p:name_pointer; {where the identifier is being sought} +% begin l:=id_loc-id_first; {compute the length} +% @<Compute the hash code |h|@>; +% @<Compute the name location |p|@>; +% if p=name_ptr then @<Enter a new name into the table at position |p|@>; +% id_lookup:=p; +% end; +% +% @ A simple hash code is used: If the sequence of +% ASCII codes is $c_1c_2\ldots c_m$, its hash value will be +% $$(2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\,\bmod\,|hash_size|.$$ +% +% @<Compute the hash...@>= +% h:=buffer[id_first]; i:=id_first+1; +% while i<id_loc do +% begin h:=(h+h+buffer[i]) mod hash_size; incr(i); +% end +% ?endgroup % end of verbatim mode +% \endgroup +% \vfill\eject +% +% \def\runninghead{APPENDIX B --- TRANSLATION BY {\tentt WEAVE}} +% \section Appendix B. +% This excerpt from \.{WEAVE.TEX} corresponds to Appendix A. +% +% % I've inserted \vfill's here at the blank lines, to squeeze this on one page! +% \begingroup \def\tt{\eighttt} \baselineskip9pt +% \verbatim +% ?vfill?verbatimgobble +% \N55. +% Searching for identifiers. +% The hash table described above is updated by the \\{id\_lookup} procedure, +% which finds a given identifier and returns a pointer to its index in +% \\{byte\_start}. +% The identifier is supposed to match character by character +% and it is also supposed to have a given \\{ilk} code; the same name may be +% present more than once if it is supposed to appear in the index with +% different typesetting conventions. +% If the identifier was not already present, it is inserted into the table. +% ?vfill?verbatimgobble +% Because of the way \.{WEAVE}'s scanning mechanism works, it is most convenient +% to let \\{id\_lookup} search for an identifier that is present in the % +% \\{buffer} +% array. +% Two other global variables specify its position in the buffer: the +% first character is $\\{buffer}[\\{id\_first}]$, and the last is $\\{buffer}[% +% \\{id\_loc}-1]$. +% ?vfill?verbatimgobble +% \Y\P$\4\X9:Globals in the outer block\X\mathrel{+}\S$\6 +% \4\\{id\_first}: \37$0\to\\{long\_buf\_size}$;\C{where the current identifier +% begins in the buffer}\6 +% \4\\{id\_loc}: \37$0\to\\{long\_buf\_size}$;\C{just after the current +% identifier in the buffer}\7 +% \4\\{hash}: \37\&{array} $[0\to\\{hash\_size}]$ \1\&{of}\5 +% \\{sixteen\_bits};\C{heads of hash lists}\2\par +% \fi +% ?vfill?verbatimgobble +% \M56. +% Initially all the hash lists are empty. +% ?vfill?verbatimgobble +% \Y\P$\4\X16:Local variables for initialization\X\mathrel{+}\S$\6 +% \4\|h: \37$0\to\\{hash\_size}$;\C{index into hash-head array}\par +% \fi +% ?vfill?verbatimgobble +% \M57. +% \P$\X10:Set initial values\X\mathrel{+}\S$\6 +% \&{for} $\|h\K0\mathrel{\&{to}}\\{hash\_size}-1$ \1\&{do}\5 +% $\\{hash}[\|h]\K0$;\2\par +% \fi +% ?vfill?verbatimgobble +% \M58. +% Here now is the main procedure for finding identifiers (and index +% entries). +% The parameter \|t is set to the desired \\{ilk} code. +% The +% identifier must either have $\\{ilk}=\|t$, or we must have +% $\|t=\\{normal}$ and the identifier must be a reserved word. +% ?vfill?verbatimgobble +% \Y\P\4\&{function}\1\ \37$\\{id\_lookup}(\|t:\\{eight\_bits})$: \37\\{name% +% \_pointer};\C{finds current identifier}\6 +% \4\&{label} \37\\{found};\6 +% \4\&{var} \37\|i: \37$0\to\\{long\_buf\_size}$;\C{index into \\{buffer}}\6 +% \|h: \37$0\to\\{hash\_size}$;\C{hash code}\6 +% \|k: \37$0\to\\{max\_bytes}$;\C{index into \\{byte\_mem}}\6 +% \|w: \37$0\to\\{ww}-1$;\C{row of \\{byte\_mem}}\6 +% \|l: \37$0\to\\{long\_buf\_size}$;\C{length of the given identifier}\6 +% \|p: \37\\{name\_pointer};\C{where the identifier is being sought}\2\6 +% \&{begin} \37$\|l\K\\{id\_loc}-\\{id\_first}$;\C{compute the length}\6 +% \X59:Compute the hash code \|h\X;\6 +% \X60:Compute the name location \|p\X;\6 +% \&{if} $\|p=\\{name\_ptr}$ \1\&{then}\5 +% \X62:Enter a new name into the table at position \|p\X;\2\6 +% $\\{id\_lookup}\K\|p$;\6 +% \&{end};\par +% \fi +% ?vfill?verbatimgobble +% \M59. +% A simple hash code is used: If the sequence of +% ASCII codes is $c_1c_2\ldots c_m$, its hash value will be +% $$(2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\,\bmod\,\\{hash\_size}.$$ +% ?vfill?verbatimgobble +% \Y\P$\4\X59:Compute the hash code \|h\X\S$\6 +% $\|h\K\\{buffer}[\\{id\_first}]$;\5 +% $\|i\K\\{id\_first}+1$;\6 +% \&{while} $\|i<\\{id\_loc}$ \1\&{do}\6 +% \&{begin} \37$\|h\K(\|h+\|h+\\{buffer}[\|i])\mathbin{\&{mod}}\\{hash\_size}$;\5 +% $\\{incr}(\|i)$;\6 +% \&{end}\2\par +% \U section~58.\fi +% ?endgroup +% \endgroup +% \eject +% +% \def\runninghead{APPENDIX C --- TRANSLATION BY {\tentt TANGLE}} +% \section Appendix C. +% The \.{TANGLE} processor converts \.{WEAVE.WEB} into a syntactically +% correct (but not very pretty) \PASCAL\ program \.{WEAVE.PAS}. +% The first three and last two lines of output are shown here, together with the +% lines of code generated by modules 55--62 and the environments of +% those lines. +% There are 1559 lines in all; the notation +% `\.. \\. +% \\.' stands for portions that are not shown. +% +% Note that, for example, the code corresponding to +% module 55 begins with `\.{\{55:\}}' and ends with `\.{\{:55\}}'; +% the code from modules 59--62 has been tangled into the code from module 58. +% +% \vskip6pt +% \verbatim +% {2:}{4:}{$C-,A+,D-}{[$C+,D+]}{:4} +% PROGRAM WEAVE(WEBFILE,CHANGEFILE,TEXFILE);LABEL 9999;CONST{8:} +% MAXBYTES=45000;MAXNAMES=5000;MAXMODULES=2000;HASHSIZE=353;BUFSIZE=100; +% . +% . . +% TOKPTR:0..MAXTOKS;{MAXTOKPTR,MAXTXTPTR:0..MAXTOKS;}{:53}{55:} +% IDFIRST:0..LONGBUFSIZE;IDLOC:0..LONGBUFSIZE; +% HASH:ARRAY[0..HASHSIZE]OF SIXTEENBITS;{:55}{63:}CURNAME:NAMEPOINTER; +% . +% . . +% PROCEDURE INITIALIZE;VAR{16:}I:0..127;{:16}{40:}WI:0..1;{:40}{56:} +% H:0..HASHSIZE;{:56}{247:}C:ASCIICODE;{:247}BEGIN{10:}HISTORY:=0;{:10} +% . +% . . +% TOKPTR:=1;TEXTPTR:=1;TOKSTART[0]:=1;TOKSTART[1]:=1;{MAXTOKPTR:=1; +% MAXTXTPTR:=1;}{:54}{57:}FOR H:=0 TO HASHSIZE-1 DO HASH[H]:=0;{:57}{94:} +% SCANNINGHEX:=FALSE;{:94}{102:}MODTEXT[0]:=32;{:102}{124:}OUTPTR:=1; +% . +% . . +% IF R=0 THEN XREF[P]:=XREFPTR ELSE XMEM[R].XLINKFIELD:=XREFPTR;END;{:51} +% {58:}FUNCTION IDLOOKUP(T:EIGHTBITS):NAMEPOINTER;LABEL 31; +% VAR I:0..LONGBUFSIZE;H:0..HASHSIZE;K:0..MAXBYTES;W:0..1; +% L:0..LONGBUFSIZE;P:NAMEPOINTER;BEGIN L:=IDLOC-IDFIRST;{59:} +% H:=BUFFER[IDFIRST];I:=IDFIRST+1; +% WHILE I<IDLOC DO BEGIN H:=(H+H+BUFFER[I])MOD HASHSIZE;I:=I+1;END{:59}; +% {60:}P:=HASH[H]; +% WHILE P<>0 DO BEGIN IF(BYTESTART[P+2]-BYTESTART[P]=L)AND((ILK[P]=T)OR((T +% =0)AND(ILK[P]>3)))THEN{61:}BEGIN I:=IDFIRST;K:=BYTESTART[P];W:=P MOD 2; +% WHILE(I<IDLOC)AND(BUFFER[I]=BYTEMEM[W,K])DO BEGIN I:=I+1;K:=K+1;END; +% IF I=IDLOC THEN GOTO 31;END{:61};P:=LINK[P];END;P:=NAMEPTR; +% LINK[P]:=HASH[H];HASH[H]:=P;31:{:60};IF P=NAMEPTR THEN{62:} +% BEGIN W:=NAMEPTR MOD 2; +% IF BYTEPTR[W]+L>MAXBYTES THEN BEGIN WRITELN(TERMOUT); +% WRITE(TERMOUT,'! Sorry, ','byte memory',' capacity exceeded');ERROR; +% HISTORY:=3;JUMPOUT;END; +% IF NAMEPTR+2>MAXNAMES THEN BEGIN WRITELN(TERMOUT); +% WRITE(TERMOUT,'! Sorry, ','name',' capacity exceeded');ERROR;HISTORY:=3; +% JUMPOUT;END;I:=IDFIRST;K:=BYTEPTR[W]; +% WHILE I<IDLOC DO BEGIN BYTEMEM[W,K]:=BUFFER[I];K:=K+1;I:=I+1;END; +% BYTEPTR[W]:=K;BYTESTART[NAMEPTR+2]:=K;NAMEPTR:=NAMEPTR+1;ILK[P]:=T; +% XREF[P]:=0;END{:62};IDLOOKUP:=P;END;{:58}{66:} +% FUNCTION MODLOOKUP(L:SIXTEENBITS):NAMEPOINTER;LABEL 31;VAR C:0..4; +% . +% . . +% WRITE(TERMOUT,'(That was a fatal error, my friend.)');END;END{:263}; +% END.{:261} +% ?endgroup +% \vfill\eject +% +% \pageno=199 % take account of the page numbers for App's D and E. +% +% \def\runninghead{APPENDIX F --- MACROS FOR FORMATTING} +% \section Appendix F: The \.{webmac.tex} file. +% This is the file that extends ``plain \TeX'' format in order to support the +% features needed by the output of \.{WEAVE}. +% +% \vskip6pt +% \verbatim +% % standard macros for WEB listings (in addition to PLAIN.TEX) +% \xdef\fmtversion{\fmtversion+WEBMAC1.3} % identifies current set of macros +% \parskip 0pt % no stretch between paragraphs +% \parindent 1em % for paragraphs and for the first line of Pascal text +% +% \font\eightrm=cmr8 +% \let\sc=\eightrm \let\mainfont=\tenrm +% \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) +% +% \def\\#1{\hbox{\it#1\/\kern.05em}} % italic type for identifiers +% \def\|#1{\hbox{$#1$}} % one-letter identifiers look a bit better this way +% \def\{\hbox{\bf#1\/}} % boldface type for reserved words +% \def\.#1{\hbox{\tentex % typewriter type for strings +% \let\\=\BS % backslash in a string +% \let\'=\RQ % right quote in a string +% \let\`=\LQ % left quote 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 +% #1}} +% \def\#{\hbox{\tt\char`\#}} % parameter sign +% \def\${\hbox{\tt\char`\$}} % dollar sign +% \def\%{\hbox{\tt\char`\%}} % percent sign +% \def\^{\ifmmode\mathchar"222 \else\char`^ \fi} % pointer or hat +% % circumflex accents can be obtained from \^^D instead of \^ +% \def\AT!{@} % at sign for control text +% +% \chardef\AM=`\& % ampersand character in a string +% \chardef\BS=`\\ % backslash in a string +% \chardef\LB=`\{ % left brace in a string +% \def\LQ{{\tt\char'22}} % left quote in a string +% \chardef\RB=`\} % right brace in a string +% \def\RQ{{\tt\char'23}} % right quote 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 +% +% \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 +% +% \let\yskip=\smallskip +% \def\to{\mathrel{.\,.}} % double dot, used only in math mode +% \def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1 #2.\par}} +% \def\lapstar{\rlap{*}} +% \def\startsection{\Q\noindent{\let\*=\lapstar\bf\modstar.\quad}} +% \def\defin#1{\global\advance\ind by 2 \1\&{#1 }} % begin `define' or `format' +% \def\A{\note{See also}} % cross-reference for multiply defined section names +% \def\B{\mathopen{\.{@\{}}} % begin controlled comment +% \def\C#1{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % Pascal comments +% \XX\hfil\penalty-1\hfilneg\quad$\{\,$#1$\,\}$\XX} +% \def\D{\defin{define}} % macro definition +% \def\E{\cdot10^} % exponent in floating point constant +% \def\F{\defin{format}} % format definition +% \let\G=\ge % greater than or equal sign +% \def\H#1{\hbox{\rm\char"7D\tt#1}} % hexadecimal constant +% \let\I=\ne % unequal sign +% \def\J{\.{@\&}} % TANGLE's join operation +% \let\K=\gets % left arrow +% \let\L=\le % less than or equal sign +% \outer\def\M#1.{\MN#1.\ifon\vfil\penalty-100\vfilneg % beginning of section +% \vskip12ptminus3pt\startsection\ignorespaces} +% \outer\def\N#1.#2.{\MN#1.\vfil\eject % beginning of starred section +% \def\rhead{\uppercase{\ignorespaces#2}} % define running headline +% \message{*\modno} % progress report +% \edef\next{\write\cont{\Z{#2}{\modno}{\the\pageno}}}\next % to contents file +% \ifon\startsection{\bf\ignorespaces#2.\quad}\ignorespaces} +% \def\MN#1.{\par % common code for \M, \N +% {\xdef\modstar{#1}\let\*=\empty\xdef\modno{#1}} +% \ifx\modno\modstar \onmaybe \else\ontrue \fi \mark{\modno}} +% \def\O#1{\hbox{\rm\char'23\kern-.2em\it#1\/\kern.05em}} % octal constant +% \def\P{\rightskip=0pt plus 100pt minus 10pt % go into Pascal mode +% \sfcode`;=3000 +% \pretolerance 10000 +% \hyphenpenalty 10000 \exhyphenpenalty 10000 +% \global\ind=2 \1\ \unskip} +% \def\Q{\rightskip=0pt % get out of Pascal mode +% \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 } +% \let\R=\lnot % logical not +% \let\S=\equiv % equivalence sign +% \def\T{\mathclose{\.{@\}}}} % terminate controlled comment +% \def\U{\note{This code is used in}} % cross-reference for uses of sections +% \let\V=\lor % logical or +% \let\W=\land % logical and +% \def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name +% \XX$\langle\,$#2{\eightrm\kern.5em#1}$\,\rangle$\XX} +% \def\Y{\par\yskip} +% \let\Z=\let % now you can \send the control sequence \Z +% \def\){\hbox{\.{@\$}}} % sign for string pool check sum +% \def\]{\hbox{\.{@\\}}} % sign for forced line break +% \def\=#1{\kern2pt\hbox{\vrule\vtop{\vbox{\hrule +% \hbox{\strut\kern2pt\.{#1}\kern2pt}} +% \hrule}\vrule}\kern2pt} % verbatim string +% \let\~=\ignorespaces +% \let\*=* +% +% \def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue +% \newif\ifon \newif\iftitle \newif\ifpagesaved +% \def\lheader{\mainfont\the\pageno\eightrm\qquad\rhead\hfill\title\qquad +% \tensy x\mainfont\topmark} % top line on left-hand pages +% \def\rheader{\tensy x\mainfont\topmark\eightrm\qquad\title\hfill\rhead +% \qquad\mainfont\the\pageno} % top line on right-hand pages +% \def\page{\box255 } +% \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} +% +% \def\rhead{\.{WEB} OUTPUT} % this running head is reset by starred sections +% \def\title{} % an optional title can be set by the user +% \def\topofcontents{\centerline{\titlefont\title} +% \vfill} % this material will start the table of contents page +% \def\botofcontents{\vfill} % this material will end the table of contents page +% \def\contentspagenumber{0} % default page number for table of contents +% \newdimen\pagewidth \pagewidth=6.5in % the width of each page +% \newdimen\pageheight \pageheight=8.7in % the height of each page +% \newdimen\fullpageheight \fullpageheight=9in % page height including headlines +% \newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones +% \def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein +% \fullpageheight=9truein\setpage} +% \def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size +% \def\contentsfile{CONTENTS} % file that gets table of contents info +% \def\readcontents{\input CONTENTS} +% +% \newwrite\cont +% \output{\setbox0=\page % the first page is garbage +% \openout\cont=\contentsfile +% \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 +% \write\cont{} % ensure that the contents file isn't empty +% \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\:##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry +% \def\[##1]{$\underline{##1}$} % underlined index item +% \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar +% \hyphenpenalty 10000 \parindent0pt} +% \def\fin{\par\vfill\eject % this is done when we are ending the index +% \ifpagesaved\null\vfill\eject\fi % output a null index column +% \if L\lr\else\null\vfill\eject\fi % finish the current page +% \parfillskip 0pt plus 1fil +% \def\rhead{NAMES OF THE SECTIONS} +% \message{Section names:} +% \output{\normaloutput\page\lheader\rheader} +% \setpage +% \def\note##1##2.{\hfil\penalty-1\hfilneg\quad{\eightrm##1 ##2.}} +% \linepenalty=10 % try to conserve lines +% \def\U{\note{Used in}} % cross-reference for uses of sections +% \def\:{\par\hangindent 2em}\let\*=*} +% \def\con{\par\vfill\eject % finish the section names +% \rightskip 0pt \hyphenpenalty 50 \tolerance 200 +% \setpage +% \output{\normaloutput\page\lheader\rheader} +% \titletrue % prepare to output the table of contents +% \pageno=\contentspagenumber \def\rhead{TABLE OF CONTENTS} +% \message{Table of contents:} +% \topofcontents +% \line{\hfil Section\hbox to3em{\hss Page}} +% \def\Z##1##2##3{\line{\ignorespaces##1 +% \leaders\hbox to .5em{.\hfil}\hfil\ ##2\hbox to3em{\hss##3}}} +% \readcontents\relax % read the contents info +% \botofcontents \end} % print the contents page(s) and terminate +% ?endgroup +% \vfill\eject +% +\def\runninghead{APPENDIX G --- NOTES ON FORMATTING} +\section Appendix G: How to use \.{WEB} macros. +The macros in \.{webkernel} make it possible to produce a variety of formats +without editing the output of \.{WEAVE}, and the purpose of this appendix +is to explain some of the possibilities. + +\def\point#1.{\yskip\indent#1.\quad\ignorespaces} + +\point 1. +Three fonts have been declared in addition to the standard fonts of +\.{PLAIN} format: You can say `\.{\{\\sc stuff\}}' to get {\sc stuff} +in small caps; and you can select the largish fonts \.{\\titlefont} +and \.{\\ttitlefont} in the title of your document, where \.{\\ttitlefont} +is a typewriter style of type. + +\point 2. +When you mention an identifier in \TeX\ text, you normally call +it `\.{|identifier|}'. +But you can also say `\.{\\\\\{identifier\}}'. +The +output will look the same in both cases, but the second alternative +doesn't put \\{identifier} into the index, since +it bypasses \.{WEAVE}'s translation from \PASCAL\ mode. + +\point 3. +To get typewriter-like type, as when referring to `\.{WEB}', you +can use the `\.{\\.}' macro (e.g., `\.{\\.\{WEB\}}'). +In the argument to +this macro you should insert an additional backslash before the symbols +listed as `special string characters' in the index to \.{WEAVE}, i.e., +before backslashes and dollar signs and the like. +A `\.{\\\ }' here will result in the visible space symbol; to get an +invisible space following a control sequence you can say `\.{\{\ \}}'. + +\point 4. +The three control sequences \.{\\pagewidth}, \.{\\pageheight}, +and \.{\\fullpageheight} can be redefined in the limbo section at the +beginning of your \.{WEB} file, to change the dimensions of each page. +The standard settings +$$\lpile{\.{\\pagewidth=6.5in}\cr + \.{\\pageheight=8.7in}\cr + \.{\\fullpageheight=9in}\cr}$$ +were used to prepare the present report; \.{\\fullpageheight} is +\.{\\pageheight} plus room for the additional heading and page numbers at +the top of each page. +If you change any of these quantities, you should +call the macro \.{\\setpage} immediately after making the change. + +\point 5. +The \.{\\pageshift} macro defines an amount by which right-hand +pages (i.e., odd-numbered pages) are shifted right with respect to +left-hand (even-numbered) ones. +By adjusting this amount you may be +able to get two-sided output in which the page numbers line up on +opposite sides of each sheet. + +\point 6. +The \.{\\title} macro will appear at the top of each page +in small caps. +For example, Appendix~D was produced after saying +`\.{\\def\\title\{WEAVE\}}'. +\newstuff +(Appendix~D was omitted from this document; see Don Knuth's original {\tt WEB} +technical report for all the appendices.) +\endnewstuff + +\point 7. +The first page usually is number 1; if you want some other +starting page, just set \.{\\pageno} to the desired number. +For example, +the initial limbo section for Appendix~D included the command +`\.{\\pageno=16}'. + +\point 8. +The macro \.{\\iftitle} will suppress the header line if it is +defined by `\.{\\titletrue}'. +The normal value is \.{\\titlefalse} +except for the table of contents; thus, the contents +page is usually unnumbered. +If your program is so long that the table of +contents doesn't fit on a single page, or if you want a number to appear +on the contents page, you should reset \.{\\pageno} when you begin the +table of contents. + +Two macros are provided to give flexibility to the table of +contents: \.{\\topofcontents} is invoked just before the contents +info is read, and \.{\\botofcontents} is invoked just after. +For example, Appendix~D +was produced with the following definitions: +$$\lpile{\.{\\def\\topofcontents\{\\null\\vfill}\cr + \.{ { }\\titlefalse \% include headline on the contents page}\cr + \.{ { }\\def\\rheader\{\\mainfont Appendix D\\hfil 15\}}\cr + \.{ { }\\centerline\{\\titlefont The \{\\ttitlefont WEAVE\}{ }processor\}}\cr + \.{ { }\\vskip 15pt \\centerline\{(Version 2.5)\}{ }\\vfill\}}\cr}$$ +Redefining \.{\\rheader}, which is the headline for right-hand pages, +suffices in this case to put the desired information at the top of the page. + +\point 9. +Data for the table of contents is written to a file that +is read after the indexes have been \TeX ed; there's one line of data +for every starred module. +For example, when Appendix~D was being generated, +a file +% \.{CONTENTS.TEX} +containing +$$\lpile{\.{\\Z \{{ }Introduction\}\{1\}\{16\}}\cr + \.{\\Z \{{ }The character set\}\{11\}\{19\}}\cr}$$ +and similar lines was created. +The \.{\\topofcontents} macro could +redefine \.{\\Z} so that the information appears in another format. + +\point 10. +Sometimes it is necessary or desirable to divide the output of +\.{WEAVE} into subfiles that can be processed separately. +For example, +the listing of \TeX\ runs to more than 500 pages, and that is enough to +exceed the capacity of many printing devices and/or their software. +When an extremely large job isn't cut into smaller pieces, the entire +process might be spoiled by a single error of some sort, making it +necessary to start everything over. + +Here's a safe way to break a woven file into three parts: +Say the pieces are $\alpha$, +$\beta$, and $\gamma$, where each piece begins with a starred module. +All macros should be defined in the opening limbo section of $\alpha$, +and copies of this \TeX\ code should be placed at the +beginning of $\beta$ and of $\gamma$. +In order to process the parts +separately, we need to take care of two things: The starting page +numbers of $\beta$ and $\gamma$ need to be set up properly, and +the table of contents data from all three runs needs to be +accumulated. + +The \.{webmac} macros include two control sequences \.{\\contentsfile} and +\.{\\readcontents} that facilitate the necessary processing. +We include +`\.{\\def\\contentsfile\{CONT1\}}' in the limbo section of $\alpha$, and +we include `\.{\\def\\contentsfile\{CONT2\}}' in the limbo section of +$\beta$; this causes \TeX\ to write the contents data for $\alpha$ and $\beta$ +into \.{CONT1.TEX} and \.{CONT2.TEX}. +Now in $\gamma$ we say +$$\.{\\def\\readcontents\{\\input CONT1 \\input CONT2 \\input CONTENTS\}};$$ +this brings in the data from all three pieces, in the proper order. + +\newstuff +Warning: life is a little different in Spidery {\tt WEB}. +{\TeX} hackers should go straight to the source. +\endnewstuff + +However, we still need to solve the page-numbering problem. +One way to +do it is to include the following in the limbo material for $\beta$: +$$\lpile{\.{\\message\{Please type the last page number of part 1: \}}\cr + \.{\\read-1to\\\\ \\pageno=\\\\ \\advance\\pageno by 1}\cr}$$ +Then you simply provide the necessary data when \TeX\ requests +it; a similar construction is used at the beginning of $\gamma$. + +This method can, of course, be used to divide a woven file into +any number of pieces. + +\point 11. +Sometimes it is nice to include things in the index that are +typeset in a special way. +For example, we might want to have an +index entry for `\TeX'. +\.{WEAVE} provides only two standard ways to +typeset an index entry (unless the entry is an identifier or a reserved word): +`\.{@\^}' gives roman type, and `\.{@.}' gives typewriter type. +But if we try to typeset `\TeX' in roman type by saying, e.g., +`\.{@\^\\TeX@>}', 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 \.{WEB} file; \.{WEAVE} +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 module +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 \.{\\modno} is set to the number of the +module being typeset. + +\point 13. +If you want to list only the modules that have changed, +together with the index, put the command `\.{\\let\\maybe=\\iffalse}' in +the limbo section before the first module of your \.{WEB} file. +It's +customary to make this the first change in your change file. + +\vfill + +\eject +% +% \def\runninghead{APPENDIX H --- GETTING STARTED} +% \section Appendix H: Installing the \.{WEB} system. +% Suppose you want to use the \.{WEB} programs on your computer, and suppose +% that you can't simply borrow them from somebody else who has the same +% kind of machine. +% Here's what to do: +% +% \yskip +% \def\step(#1){\par\hangindent 2em\noindent\hbox to 2em{\hfil(#1) }\ignorespaces} +% \step(1) Get a tape that contains the files \.{WEAVE.WEB}, \.{TANGLE.WEB}, +% \.{TANGLE.PAS}, and \.{WEBMAC.TEX}. +% The tape will probably also contain an +% example change file \.{TANGLE.CH}. +% \step(2) Look at the sections of \.{TANGLE} that are listed under ``system +% dependencies'' in the index of Appendix~E above, and figure out what changes +% (if any) will be needed for your system. +% \step(3) Make a change file \.{TANGLE.CH} that contains the changes of~(2); +% do not change your copy of \.{TANGLE.WEB}, leave it intact. +% (The +% rules for change files are explained at the end of the manual just before +% the appendices; you may want to look at the example change file that +% arrived with your copy of \.{TANGLE.WEB}. +% It's also a good idea to +% define all the ``switches'' like \&{debug} and \&{gubed} to be null in your +% first change files; then you can sure that your compiler will handle +% all of the code.) +% \step(4) Make the changes of (2) in your copy of \.{TANGLE.PAS}. +% (If these +% changes are extensive, you might be better off finding some computer that +% that already has \.{TANGLE} running, and making the new \.{TANGLE.PAS} +% from \.{TANGLE.WEB} and your \.{TANGLE.CH}.) +% \step(5) Use your \PASCAL\ compiler to convert your copy of \.{TANGLE.PAS} +% to a running program \.{TANGLE}. +% \step(6) Check your changes as follows: Run \.{TANGLE} on \.{TANGLE.WEB} +% and your \.{TANGLE.CH}, yielding $\.{TANGLE.PAS}'$; make a running +% program $\.{TANGLE}'$ by applying \PASCAL\ to +% $\.{TANGLE.PAS}'$; run $\.{TANGLE}'$ on \.{TANGLE.WEB} and +% your \.{TANGLE.CH}, yielding $\.{TANGLE.PAS}''$; and check +% that $\.{TANGLE.PAS}''$ is identical to +% $\.{TANGLE.PAS}'$. +% Once this test has been passed, you have got a +% working \.{TANGLE} program. +% \step(7) Make a change file \.{WEAVE.CH} analogous to (3), but this time +% consider the system-dependent parts of \.{WEAVE} that are listed in +% the index to Appendix~D. +% \step(8) Run \.{TANGLE} on \.{WEAVE.WEB} and your \.{WEAVE.CH}, obtaining +% \.{WEAVE.PAS}. +% \step(9) Use \PASCAL\ on \.{WEAVE.PAS} to make a running \.{WEAVE} program. +% \step(10) Run \.{WEAVE} on \.{TANGLE.WEB} and \.{TANGLE.CH} to produce +% \.{TANGLE.TEX}. +% \step(11) Run \TeX\ on \.{TANGLE.TEX}, obtaining a listing analogous to +% Appendix~E. +% This listing will incorporate your changes. +% \step(12) Run \.{WEAVE} on \.{WEAVE.WEB} and your \.{WEAVE.CH} to produce +% \.{WEAVE.TEX}. +% \step(13) Run \TeX\ on \.{WEAVE.TEX}, obtaining a listing analogous to +% Appendix~D that incorporates your changes. +% +% \yskip\noindent +% This description assumes that you already have a working \TeX82 system. +% But what if you don't have \TeX82? +% Then you start with a tape that also +% contains \.{TEX.WEB} and \.{plain.tex}, and you refer to a hardcopy +% listing of the \TeX82 program corresponding to \.{TEX.WEB}. +% Between steps +% (10) and (11) you do the following: +% +% \yskip +% \def\substep(10.#1){\par\hangindent 4em\noindent +% \hbox to 4em{\hfil(10.#1) }\ignorespaces} +% \substep(10.1) Make a change file \.{TEX.CH} to fix the system dependent +% portions of \.{TEX.WEB}, in a manner analogous to step~(2). +% Since \TeX\ is +% a much more complex program than \.{WEAVE} or \.{TANGLE}, there are more +% system-dependent features to think about, but by now you will be good at +% making such modifications. +% Do not make any changes to \.{TEX.WEB}. +% \substep(10.2) Make an almost-copy of your \.{TEX.CH} called \.{INITEX.CH}; +% this one will have the `\&{init}' and `\&{tini}' macros redefined in order +% to make the initialization version of \TeX. +% It also might have smaller +% font memory and dynamic memory areas, since \.{INITEX} doesn't need as +% much memory for such things; by setting the memory smaller in \.{INITEX}, +% you guarantee that the production system will have a ``cushion.'' +% \substep(10.3) Run \.{TANGLE} on \.{TEX.WEB} and \.{INITEX.CH}, obtaining +% \.{INITEX.PAS} and \.{TEX.POOL}. +% \substep(10.4) Run \PASCAL\ on \.{INITEX.PAS}, obtaining \.{INITEX}. +% \substep(10.5) Run \.{INITEX} on \.{TEX.POOL}, during which run you type +% `\.{plain}' and `\.{\\dump}'. +% This will produce a file \.{plain.fmt} +% containing the data needed to initialize \TeX's memory. +% \substep(10.6) Run \.{TANGLE} on \.{TEX.WEB} and the \.{TEX.CH} of (10.1), +% obtaining \.{TEX.PAS}. +% \substep(10.7) Run \PASCAL\ on \.{TEX.PAS}, obtaining \.{VIRTEX}. +% \substep(10.8) If your operating system supports programs whose core images +% have been saved, run \.{VIRTEX}, type `\.{\&plain}', then save the core image +% and call it \TeX. +% Otherwise, \.{VIRTEX} will be your \TeX, and it will +% read `\.{plain.fmt}' (or some other \.{fmt} file) each time you run. +% +% \yskip +% This 21-step process may seem long, but it is actually an oversimplification, +% since you also need fonts and a way to print the device-independent files +% that \TeX\ spews out. +% On the other hand, the total number of steps is not +% quite so large when you consider that \.{TANGLE}-followed-by-\PASCAL\ and +% \.{WEAVE}-followed-by-\TeX\ may be regarded as single operations. +% +% If you have only the present report, not a tape, you will have to prepare +% files \.{WEAVE.WEB} and \.{TANGLE.WEB} by hand, typing them into the +% computer by following Appendices D and E. +% Then you have to simulate the +% behavior of \.{TANGLE} by converting \.{TANGLE.WEB} manually into +% \.{TANGLE.PAS}; with a good text editor this takes about six hours. +% Then +% you have to correct errors that were made in all this hand work; but still +% the whole project is not impossibly difficult, because in fact the entire +% development of \.{WEAVE} and \.{TANGLE} (including the writing of the +% programs and the manual) took less than two months of work. +% +% \vfill + +\end + diff --git a/web/spiderweb/doc/spiderwebman.toc b/web/spiderweb/doc/spiderwebman.toc new file mode 100644 index 0000000000..66f7f67ff5 --- /dev/null +++ b/web/spiderweb/doc/spiderwebman.toc @@ -0,0 +1 @@ +\catcode`\@=11 diff --git a/web/spiderweb/fixes-to-be-applied/changes b/web/spiderweb/fixes-to-be-applied/changes new file mode 100644 index 0000000000..aab863bc4f --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/changes @@ -0,0 +1,641 @@ +From fubinf!thull Mon Mar 12 09:01:53 1990 +Received: by cs.Princeton.EDU (5.57/1.98) + id AA22774; Mon, 12 Mar 90 09:01:50 EST +Received: from [129.217.64.60] by Princeton.EDU (5.58+++/2.32/mailrelay) + id AA20280; Mon, 12 Mar 90 08:59:12 EST +Received: from fubinf.uucp + by unido.informatik.uni-dortmund.de with uucp via EUnet (UNIDO-2.0.1.d) + for princeton.edu + id AO16211; Mon, 12 Mar 90 14:57:27 +0100 +Received: by fubinf.uucp (4.0/SMI-4.0) + id AA01394; Sat, 3 Nov 90 15:19:31 +0100 +Date: Sat, 3 Nov 90 15:19:31 +0100 +From: fubinf!thull (Klaus Thull) +Message-Id: <9011031419.AA01394@fubinf.uucp> +To: nr@Princeton.EDU +Subject: spider.fixes +Status: R + +These changes made spider operational on several suns, one old +16bitter 68000 pcs cadmus, one 32bittter 68020 same, +the sony news 68030, and the sony risc. +please note that these changes refer to a version that came to me +out of its own accord one day last summer and without bearing an exact date. +please note that there is the issue of awk versions. I constantly +have to take along one awk source to be sure to compile spider. +please note that there is one extension as well: there is a symbolic +printout in weave which has, in the case of knuths pascal-web, +proven very handy. +:::::::::::::: +common.ch +:::::::::::::: +module 19 + +@d buf_size = 200 /* for \.{WEAVE} and \.{TANGLE} */ +@d long_buf_size = 500 /* for \.{WEAVE} */ + + +module 26 + +@d max_modules = 2000 /* number of identifiers, strings, module names; + must be less than 10240 */ + + +de-linting... +@x module 29 +@ @<Add path name from {\tt -I} to search path@>= + pathaddname(*argv+2); +@ @<Other...@>= +@y +@ @<Add path name from {\tt -I} to search path@>= + pathaddname(*argv+2); +@ @<Other...@>= +extern char* getenv(); +@z + + +de-linting... +@x module 33 +@ The included file name should only contain visible ASCII characters, +@y +@ The included file name should only contain visible ASCII characters, +@z + +@x + if ((cur_file=pathopen(cur_file_name,"r"))==NULL) { +@y + if ((cur_file=pathopen(cur_file_name))==NULL) { +@z + + +@d max_bytes = 90000 /* the number of bytes in identifiers, + index entries, and module names */ +@d max_names = 4000 /* number of identifiers, strings, module names; + must be less than 10240 */ + +module 42 + +@d hash_size = 353 /* should be prime */ + + +@x module 62 +@ Some implementations may wish to pass the |history| value to the +@y +@ Some implementations may wish to pass the |history| value to the +@z + +activate stats +@x + @<Print the job |history|@>; +@y +#ifdef STAT + print_stats(); +#endif + @<Print the job |history|@>; +@z + +de-linting... +@x +fatal("! Usage: tangle webfile[.web] [changefile[.ch]] [-Ipathname ...]\n",0)@; +else +fatal("! Usage: weave webfile[.web] [changefile[.ch]] [-x] [-Ipathname ...]\n", + 0); +@y +fatal("! Usage: tangle webfile[.web] [changefile[.ch]] [-Ipathname ...]\n", + "")@; +else +fatal("! Usage: weave webfile[.web] [changefile[.ch]] [-x] [-Ipathname ...]\n", + ""); +@z +:::::::::::::: +spider.ch +:::::::::::::: + +escape backslash... +(and put titles right) +#x module 11 +# We write tokens out to two files: |scrapfile| for \.{WEAVE}, and +#y +# We write tokens out to two files: |scrapfile| for \.{WEAVE}, and +#z + +|ttokfile| for \.{TANGLE}. +#<Set init...#>= + scrapfile = "scraps.web" +#x + print "@*Scrap code generated by {\tt SPIDER}." > scrapfile + ttokfile = "outtoks.web" + print "@*Token code generated by {\tt SPIDER}." > scrapfile +#y + print "@*Scrap code generated by {\\tt SPIDER}." > scrapfile + ttokfile = "outtoks.web" + print "@*Token code generated by {\\tt SPIDER}." > ttokfile +#z + +escape backslash... +#x module 16 +# We use a special file to write grammar information: +#<Set init...#>= + grammarfile = "grammar.web" + print "@*Grammar code generated by {\tt SPIDER}." > grammarfile +#y +# We use a special file to write grammar information: +#<Set init...#>= + grammarfile = "grammar.web" + print "@*Grammar code generated by {\\tt SPIDER}." > grammarfile +#z + +escape backslash... +#x module 62 +# This is how we write out the string or constant scrap, at the end. +#y +# This is how we write out the string or constant scrap, at the end. +#z + +#x + " and \TeX\ strings are identified." > scrapfile +#y + " and \\TeX\\ strings are identified." > scrapfile +#z + +#x module 72 +# We use an ugly trick to get the token numbers different for +#y +# We use an ugly trick to get the token numbers different for +#z + +#x + temp = temp + #'37 - highesttoken ## hackety hack! +#y + temp = temp + #'37 + 3 - highesttoken ## hackety hack! + ## +3 because three highest are already defined! +#z + + +#x module 126 +# It's desirable to put the production in a comment, but we have to +get rid of the confusing \vert, or \.{WEAVE} will think it introduces +code. +#<Remove \vert\ from |inputline[n]| and put results in |this_string|#>= + this_string = inputline[n] + tempi = index(this_string,"|") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\vert " tempb + tempi = index(this_string,"|") + } +#y +# It's desirable to put the production in a comment, but we have to +get rid of the confusing \vert, or \.{WEAVE} will think it introduces +code. And of other things as well\dots +#<Remove \vert\ from |inputline[n]| and put results in |this_string|#>= + tempb = inputline[n] + tempa = "" + tempi = index(tempb,"\\") + while (tempi != 0) { + tempa = tempa substr(tempb,1,tempi-1) "\\BS " + tempb = substr(tempb,tempi+1) + tempi = index(tempb,"\\") + } + this_string = tempa tempb + tempb = this_string + tempa = "" + tempi = index(tempb,"##") + while (tempi != 0) { + tempa = tempa substr(tempb,1,tempi-1) "\\##" + tempb = substr(tempb,tempi+1) + tempi = index(tempb,"##") + } + this_string = tempa tempb + tempb = this_string + tempa = "" + tempi = index(tempb,"$") + while (tempi != 0) { + tempa = tempa substr(tempb,1,tempi-1) "\\$" + tempb = substr(tempb,tempi+1) + tempi = index(tempb,"$") + } + this_string = tempa tempb + tempb = this_string + tempa = "" + tempi = index(tempb,"%") + while (tempi != 0) { + tempa = tempa substr(tempb,1,tempi-1) "\\%" + tempb = substr(tempb,tempi+1) + tempi = index(tempb,"%") + } + this_string = tempa tempb + tempb = this_string + tempa = "" + tempi = index(tempb,"^") + while (tempi != 0) { + tempa = tempa substr(tempb,1,tempi-1) "\\^" + tempb = substr(tempb,tempi+1) + tempi = index(tempb,"^") + } + this_string = tempa tempb + tempb = this_string + tempa = "" + tempi = index(tempb,"@") + while (tempi != 0) { + tempa = tempa substr(tempb,1,tempi-1) "\\@@" + tempb = substr(tempb,tempi+1) + tempi = index(tempb,"@") + } + this_string = tempa tempb + tempi = index(this_string,"|") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\vert " tempb + tempi = index(this_string,"|") + } + tempi = index(this_string,"'") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\RQ " tempb + tempi = index(this_string,"'") + } + tempi = index(this_string,"`") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\LQ " tempb + tempi = index(this_string,"`") + } + tempi = index(this_string,"{") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\LB " tempb + tempi = index(this_string,"{") + } + tempi = index(this_string,"}") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\RB " tempb + tempi = index(this_string,"}") + } + tempi = index(this_string,"~") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\TL " tempb + tempi = index(this_string,"~") + } + tempi = index(this_string,"_") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\UL " tempb + tempi = index(this_string,"_") + } + tempi = index(this_string,"&") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\AM " tempb + tempi = index(this_string,"&") + } +#z + + +activate this if year is field no 8 + + x module 151 +#*1Tracking the generation date. + y +#*1Tracking the generation date. + z + + x + year = $7 + y + year = $8 + z + +:::::::::::::: +tangle.ch +:::::::::::::: + +@ The following parameters were sufficient in the original \.{TANGLE} to +handle \TeX, so they should be sufficient for most applications of \.{TANGLE}. + +If you change |max_bytes|, |max_names| or |hash_size| you should also +change them in the file |"common.web"|. + +@d max_bytes = 90000 /* the number of bytes in identifiers, + index entries, and module names; used in |"common.web"| */ +@d max_toks = 150000 /* number of bytes in compressed \cee\ code */ +@d max_names = 4000 /* number of identifiers, strings, module names; + must be less than 10240; used in |"common.web"| */ +@d max_texts = 2000 /* number of replacement texts, must be less than 10240 */ +@d hash_size = 353 /* should be prime; used in |"common.web"| */ +@d longest_name = 400 /* module names shouldn't be longer than this */ +@d stack_size = 50 /* number of simultaneous levels of macro expansion */ +@d buf_size = 100 /* for \.{WEAVE} and \.{TANGLE} */ + +de-linting... +@x +@ Here's the procedure that decides whether a name of length |l| +starting at position |first| equals the identifier pointed to by |p|: + +@u +names_match(p,first,l) +name_pointer p; /* points to the proposed match */ +ASCII *first; /* position of first character of string */ +int l; /* length of identifier */ +@y +@ Here's the procedure that decides whether a name of length |l| +starting at position |first| equals the identifier pointed to by |p|: + +@u +names_match(p,first,l,t) +name_pointer p; /* points to the proposed match */ +ASCII *first; /* position of first character of string */ +int l; /* length of identifier */ +eight_bits t; /* which is a dummy but lint complains */ + /* it will still complain \dots */ +@z + + + +12-char significance +@x module 110 +@ We use macros with zero or more parameters, and we give the parameters names. +@y +@ We use macros with zero or more parameters, and we give the parameters names. +@z + +@x +@d max_param_name_texts = 256 +@y + +Identifier conflict with PCS C\dots + +@d param_name_texts_end = p_nm_txts_end +@d next_param_name_text = next_p_nm_txt +@# +@d max_param_name_texts = 256 +@z + +de-linting +@x +@ This function prints out a decimal constant using |app_repl|. +@u +app_decimal(c) + int c; /* on entry require |c>=0| */ +{int power; +@y +@ This function prints out a decimal constant using |app_repl|. +This casting trick is due to Tim Morgan's WEB-C. + +@d app_decimal(x) = zapp_decimal((long)(x)) + +@u +zapp_decimal(c) + long c; /* on entry require |c>=0| */ +{long power; +@z +:::::::::::::: +weave.ch +:::::::::::::: + +@x module 1 +#ifdef STAT + @<Print statistics about memory usage@>; +#endif STAT +@y +@z + +module 2 +@ The following parameters were sufficient in the original \.{WEAVE} to +handle \TeX, so they should be sufficient for most applications of \.{CWEAVE}. + +@d max_bytes = 90000 /* the number of bytes in identifiers, + index entries, and module names */ +@d max_names = 4000 /* number of identifiers, strings, module names; + must be less than 10240 */ +@d max_modules = 2000 /* greater than the total number of modules */ +@d hash_size = 353 /* should be prime */ +@d buf_size = 100 /* maximum length of input line, plus one */ +@d longest_name = 400 /* module names and strings shouldn't be longer than this */ +@d long_buf_size = 500 /* |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 */ +@x +@d max_texts = 2000 /* number of phrases in \cee\ texts being parsed; + must be less than 10240 */ +@d max_scraps = 1000 /* number of tokens in \cee\ texts being parsed */ +@y +@d max_texts = 4000 /* number of phrases in \cee\ texts being parsed; + must be less than 10240 */ +@d max_scraps = 4000 /* number of tokens in \cee\ texts being parsed */ +@z +@d stack_size = 400 /* number of simultaneous output levels */ + +@x +/* identifier =200 or octal @'310 */ +@y +/* identifier =200 or octal |@'310| */ +@z + +@x module 57 +@ In the \TeX\ part of a module, cross-reference entries are made only for +@y +@ In the \TeX\ part of a module, cross-reference entries are made only for +@z + +@x doesn't belong here +#ifdef DEBUG + case trace: tracing=next_control-'0'; continue; +#endif DEBUG +@y +@z + + +Print symbolically the entire tree + +@x module 87 +@ Token lists in |@!tok_mem| are composed of the following kinds of +@y +@ Token lists in |@!tok_mem| are composed of the following kinds of +@z + + +@u +#ifdef DEBUG +@x +print_text(p) /* prints a token list */ +text_pointer p; +@y +print_text(p,ind) /* prints a token list */ +text_pointer p; +int ind; +@z +{ + 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"); + if (p>=text_ptr) printf("BAD"); + else for (j=*p; j<*(p+1); j++) { + r=*j%id_flag; + r=*j%id_flag; + switch (*j/id_flag) { + case 1: printf("\\{"); print_id((name_dir+r)); printf("}"); break; + /* |id_flag| */ + case 2: printf("\&{"); print_id((name_dir+r)); printf("}"); break; + /* |res_flag| */ + case 3: printf("<"); print_id((name_dir+r)); printf(">"); break; + /* |mod_flag| */ +@x + case 4: printf("[[%d]]",r); break; /* |tok_flag| */ + case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */ +@y + case 4: /* we make this a recursive prettyprinting here */ + printf("@@/\n"); + { int i; for (i=0; i<ind; i++) printf(" "); } + printf("[[%d:",r); + print_text(r+tok_start,ind+1); + printf("]]"); + break; /* |tok_flag| */ + case 5: + printf("@@/\n"); + { int i; for (i=0; i<ind; i++) printf(" "); } + printf("|[[%d:",r); + print_text(r+tok_start,ind+1); + printf("]]|"); + break; /* |inner_tok_flag| */ +@z + default: @<Print token |r| in symbolic form@>; + } + } +} +#endif DEBUG + +@x module 106 +@ @<If semi-tracing, show the irreducible scraps@>= +#ifdef DEBUG +@y +@ @<If semi-tracing, show the irreducible scraps@>= +#ifdef DEBUG + if (tracing==2) + { + scrap_pointer k; + printf("\nafter...\n"); + for (k=scrap_base; k<=lo_ptr; k++) + { print_cat(k->cat); printf(", %ld:<",(long)(k->trans-tok_start)); + print_text(k->trans,0); printf(">"); + } + new_line; + } +@z +if (lo_ptr>scrap_base && tracing==1) { + printf("\nIrreducible scrap sequence in section %d:",module_count); + mark_harmless; + for (j=scrap_base; j<=lo_ptr; j++) { + printf(" "); print_cat(j->cat); + } +} +#endif DEBUG + +@x module 107 +@ @<If tracing,...@>= +#ifdef DEBUG +if (tracing==2) { + printf("\nTracing after l. %d:\n",cur_line); mark_harmless; + if (loc>buffer+50) { + printf("..."); + ASCII_write(loc-51,51); + } + else ASCII_write(buffer+1,loc-buffer); +} +#endif DEBUG +@y +@ @<If tracing,...@>= +#ifdef DEBUG +if (tracing==2) { + scrap_pointer k; + printf("\nTracing after l. %d:\n",cur_line); mark_harmless; + if (loc>buffer+50) { + printf("..."); + ASCII_write(loc-51,51); + } + else ASCII_write(buffer,loc-buffer); + printf("\nbefore...\n"); + for (k=scrap_base; k<scrap_ptr; k++) + { print_cat(k->cat); printf(", %ld:<",(long)(k->trans-tok_start)); + print_text(k->trans,0); printf(">\n"); + } + new_line; +} +#endif DEBUG +@z + +@x module 144 +@ In the \TeX\ part of a module, we simply copy the source text, except that +@y +@ In the \TeX\ part of a module, we simply copy the source text, except that +@z + +@x + case vertical_bar: /* surround vertical bar with \.{\\CD...\\DC} */ +@y +#ifdef DEBUG + case trace: tracing=*(loc-1)-'0'; continue; +#endif DEBUG + case vertical_bar: /* surround vertical bar with \.{\\CD...\\DC} */ +@z + + + +@x module 262 +@ @<Print statistics about memory usage@>= +printf( +"\nMemory usage statistics: %d of %d names, %d of %d cross-references,\n", + name_ptr-name_dir, name_dir_end-name_dir, + xref_ptr-xmem, xmem_end-xmem); +printf("\t %d of %d bytes;",byte_ptr-byte_mem,byte_mem_end-byte_mem); +printf("\nParsing required %d of %d(%d) scraps, %d of %d(%d) texts,\n", + max_scr_ptr-scrap_info, max_scraps, max_scraps-SCRAP_SLACK, + max_text_ptr-tok_start, max_texts, max_texts-TEXT_SLACK + ); +printf("\t %d of %d(%d) tokens, %d of %d levels;\n", + max_tok_ptr-tok_mem, max_toks, max_toks-TOK_SLACK, + max_stack_ptr-stack, stack_end-stack + ); +printf("\nSorting required %d levels\n", max_sort_ptr-scrap_info); +@y +@ @u print_stats() { +#ifdef STAT +printf( +"\nMemory usage statistics: %d of %d names, %d of %d cross-references,\n", + name_ptr-name_dir, name_dir_end-name_dir, + xref_ptr-xmem, xmem_end-xmem); +printf("\t %d of %d bytes;",byte_ptr-byte_mem,byte_mem_end-byte_mem); +printf("\nParsing required %d of %d(%d) scraps, %d of %d(%d) texts,\n", + max_scr_ptr-scrap_info, max_scraps, max_scraps-SCRAP_SLACK, + max_text_ptr-tok_start, max_texts, max_texts-TEXT_SLACK + ); +printf("\t %d of %d(%d) tokens, %d of %d levels;\n", + max_tok_ptr-tok_mem, max_toks, max_toks-TOK_SLACK, + max_stack_ptr-stack, stack_end-stack + ); +printf("\nSorting required %d levels\n", max_sort_ptr-scrap_info); +#endif +} +@z + +@x +#ifdef STAT + @<Print statistics about memory usage@>; +#endif STAT +@y +@z + diff --git a/web/spiderweb/fixes-to-be-applied/dnn.web b/web/spiderweb/fixes-to-be-applied/dnn.web new file mode 100644 index 0000000000..a9c4d033cd --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/dnn.web @@ -0,0 +1,125 @@ +%<$DNN GRAMMAR Condenser - Ver DN-1A(2) - [PQN-OTFA]$>
+% Copyright 1989--1990 by David Ness
+% Not to be sold, but may be used freely for any purpose or for any purposes of
+% Norman Ramsey
+
+\let\RA\rightarrow
+
+\def\vert{{\tt\char'174}}
+\def\pb{$\.|\ldots\.|$} % C brackets (|...|)
+
+\def\title{DNN GRAMMAR Condenser}
+
+\def\topofcontents{\null\vfill
+ \titlefalse % include headline on the contents page
+ \def\rheader{\hfil}
+ \centerline{\titlefont The {\ttitlefont DNN GRAMMAR} Condenser}
+ \vfill}
+
+
+\def\syntax##1{\leavevmode\hbox{$\langle\hbox{\sl ##1\/}\rangle$}}
+\def\produces{\leavevmode\hbox{${}::={}$}}
+\def\opt##1{$[$##1$]$}
+
+#*=The {\tt SPIDER} grammar condenser.
+#*Introduction.
+This is an \.{AWK} program designed to read a description of a grammar and to
+produce calls on |squash| instead of |reduce| where it can.
+
+This might not look very important, but the grammar of {\tt C} is such that
+MicroSoft C 5.1 can't handle the \.{WEB} for \.{WEAVE} because the |translate|
+function turns out to be too large. By good luck, the condensation done here
+manages to (just) avoid that!
+
+The philosophy here is very simple. We are only `interested' in lines
+which begin with |app1| or |reduce|. When they begin with |app1(pp+n...| we
+table |n| in the array |data| and don't generate anything. When they begin
+with |reduce| we check
+and see if the |reduce| is consistent with the |app1|s. If so then we just
+generate one |squash| for the whole mess.
+
+In all other cases (an inconsistent |reduce| or neither an |app1| or
+|reduce|) we generate all of the lines (if there were any) that got swallowed
+into the |data| array.
+
+#d banner = "DNN GRAMMAR.WEB Condenser -> OUT.TMP Ver DN-1A(2)"
+#u#1
+BEGIN {
+#<Say Hello#>
+#<Set initial values#>
+}
+#@
+#<Define Functions#>
+#<Pattern-action statements#>
+#@
+END {
+#<Do final things#>
+}
+
+
+# #<Set init...#>=
+out = "out.tmp"
+Base = 0
+
+# |dumparray()| dumps any |app1(pp+...)|'s that have been accumulated so far.
+It is called when we get anything other than a |reduce| or |app1|, or if we
+get a |reduce| but it isn't {\it the right stuff!}
+#<Define Functions#>=
+function dumparray()
+{
+ if (Base != 0)
+ {
+ for (i = 0; i < Base; ++i) print "\tapp1(pp+" data[i] ");" >out
+ delete data
+ Base = 0
+ }
+ print $0 >out
+ return
+}
+
+# If we have an |app1(pp+n)| enter |n| into the table and keep going
+#<Pattern-action statements#>=
+#=/app1\(pp\+/#> {
+match($0,"app1\\(pp\\+.*\\)")
+val = substr($0,RSTART+8,RLENGTH-9)
+data[Base++] = val
+}
+
+# If we hit a |reduce(...)|, see if we should process it.
+#<Pattern-action statements#>=
+#=/reduce/#> {
+ match($0,"reduce\\(pp\\+[0-9]*\\,")
+ val = substr($0,RSTART+10,RLENGTH-11)
+ if (data[0] == val)
+ #<|reduce| starts where first |app1| started#>#;
+ else {dumparray()}
+}
+
+# #<|reduce| starts where first |app1| started#>=
+{
+ match($0,",[0-9]+,")
+ val = substr($0,RSTART+1,RLENGTH-2)
+ if (val == (1+data[Base-1]-data[0]))
+ #<|reduce| condenses right number of elements#>#;
+ else {dumparray()}
+}
+
+# #<|reduce| condenses right number of elements#>=
+{
+ match($0,"\\(.*\\);")
+ print "\tsquash" substr($0,RSTART,RLENGTH) >out
+ delete data
+ Base = 0
+}
+
+# When we encounter an `uninteresting' statement, dump anything that we might
+have accumulated.
+#<Pattern-action statements#>=
+#=$0 !~ /app1|reduce/#> {dumparray()}
+
+# #<Say Hello#>=print banner
+
+# #<Do final...#>=
+
+#*=Index.
+
\ No newline at end of file diff --git a/web/spiderweb/fixes-to-be-applied/fixes b/web/spiderweb/fixes-to-be-applied/fixes new file mode 100644 index 0000000000..e751557ded --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/fixes @@ -0,0 +1,139 @@ +From patrick%cs.kuleuven.ac.be@princeton.edu Thu Aug 29 01:20:59 1991 +Return-Path: <patrick%cs.kuleuven.ac.be@princeton.edu> +Received: from alpha.xerox.com by palain.PARC (4.1/SMI-4.1) + id AA13556; Thu, 29 Aug 91 01:20:57 PDT +Received: from Minos.PARC.Xerox.xns by alpha.xerox.com via XNS id <11523>; Thu, 29 Aug 1991 01:20:32 PDT +Received: from Princeton.EDU ([128.112.128.1]) by alpha.xerox.com with SMTP id <11523>; Thu, 29 Aug 1991 01:20:05 PDT +Received: from fs.Princeton.EDU by Princeton.EDU (5.65b/2.80/princeton) + id AA15585; Thu, 29 Aug 91 04:19:59 -0400 +Received: from Princeton.EDU (Princeton.EDU.) by fs.Princeton.EDU (4.0/1.105) + id AA08885; Thu, 29 Aug 91 04:19:57 EDT +Received: from n-kulcs.cs.kuleuven.ac.be by Princeton.EDU (5.65b/2.80/princeton) + id AA15582; Thu, 29 Aug 91 04:19:49 -0400 +Received: from medusa.cs.kuleuven.ac.be by n-kulcs.cs.kuleuven.ac.be (5.64+/n_kulcs1.1) + id AA02072; Thu, 29 Aug 91 10:20:48 +0200 +Received: by medusa.cs.kuleuven.ac.be (5.65b/cs_kuleuven.02) + id AA08766; Thu, 29 Aug 91 10:21:14 +0200 +X-Ns-Transport-Id: 08002008D0FD000FC327 +Date: Thu, 29 Aug 1991 01:21:14 PDT +From: patrick%cs.kuleuven.ac.be@princeton.edu (Patrick Weemeeuw) +Subject: Spidery Web +To: nr@princeton.edu +Message-Id: <9108290821.AA08766@medusa.cs.kuleuven.ac.be> +Status: RO + +Hello, +I'm trying to develop a web system for Prolog. + +One of the difficulties I had is recognizing tokens containing +backslashes. I changed master/spider.web such that it now correctly +handles tokens like: +token \\== category .... +generating the C string "\\==" but checking for a string with lenght *3* +instead of 4. + +The context diff is included below. + +Patrick. +-- +Patrick Weemeeuw mail: Katholieke Universiteit Leuven +Tel: +32 16 200656 x 3544 Dept. of Computer Science +e-mail: patrick@cs.kuleuven.ac.be Celestijnenlaan 200 A +Fax: +32 16 205308 B-3001 Leuven (Belgium) +====================================================================== + + +*** spider.web Wed Aug 28 19:32:01 1991 +--- spider.web.orig Wed Aug 28 17:47:57 1991 +*************** +*** 794,800 + tokenname[$2]="SP_gen_token_" tokennumber + tokennumbers[$2]=tokennumber + tokennumber-- +- #<Find real length of |$2| and put it in |tokenlength[$2]|#> + ## figure out how to recognize the token + temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, tokenlength[$2]) + tokentest[$2]=temp + +--- 794,799 ----- + tokenname[$2]="SP_gen_token_" tokennumber + tokennumbers[$2]=tokennumber + tokennumber-- + ## figure out how to recognize the token + temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, length($2)) + tokentest[$2]=temp +*************** +*** 796,802 + tokennumber-- + #<Find real length of |$2| and put it in |tokenlength[$2]|#> + ## figure out how to recognize the token +! temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, tokenlength[$2]) + tokentest[$2]=temp + + # To find the length of a string considered as a C~string, we scan it looking + +--- 795,801 ----- + tokennumbers[$2]=tokennumber + tokennumber-- + ## figure out how to recognize the token +! temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, length($2)) + tokentest[$2]=temp + tokenlength[$2]=length($2) + +*************** +*** 798,803 + ## figure out how to recognize the token + temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, tokenlength[$2]) + tokentest[$2]=temp + + # To find the length of a string considered as a C~string, we scan it looking + for occurrences of the \.{\\} character. We initialize |templ| with + +--- 797,803 ----- + ## figure out how to recognize the token + temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, length($2)) + tokentest[$2]=temp ++ tokenlength[$2]=length($2) + + + # The setting of attributes is as for all tokens: +*************** +*** 799,827 + temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, tokenlength[$2]) + tokentest[$2]=temp + +- # To find the length of a string considered as a C~string, we scan it looking +- for occurrences of the \.{\\} character. We initialize |templ| with +- |length($2)|, and each time we find a legitimate escape sequence, we decrement +- |templ|. Remark that, given the current lexical analysis, \.{\\f}, \.{\\n} etc. +- cannot occur in a token. +- #<Find real length of |$2| and put it in |tokenlength[$2]|#>= +- templ=length($2) +- i=1 #/ +- while(i<=length($2)) { #/ +- if(substr($2,i,1)=="\\") { #/ +- if(i<length($2)) { +- tempc=substr($2,i+1,1) #/ +- if((tempc=="a") || (tempc=="b") || (tempc=="\\") || (tempc=="?") || (tempc=="'")) { +- templ-- +- i++ +- } else { #/ +- i++ #/ +- } #/ +- } #/ +- } #/ +- i++ #/ +- } #/ +- tokenlength[$2]=templ + + # The setting of attributes is as for all tokens: + #<Set attributes of token |$2|#>= + +--- 799,804 ----- + tokentest[$2]=temp + tokenlength[$2]=length($2) + + + # The setting of attributes is as for all tokens: + #<Set attributes of token |$2|#>= + diff --git a/web/spiderweb/fixes-to-be-applied/latex/README b/web/spiderweb/fixes-to-be-applied/latex/README new file mode 100644 index 0000000000..e237cf9dbe --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/README @@ -0,0 +1,66 @@ +This is a collection of files to enable you to use Spidery Web with +LaTeX as the formatter rather than plain TeX. It is copyright D.Love, +SERC Daresbury Laboratory 1991 under the same conditions as the Spider +distribution. + +-------------------------------------------------------------------- +#include <disclaimer.h> +Snail mail: | JANET: d.love@uk.ac.dl +Dr. David Love, | modern BIT/INTERNET: d.love@dl.ac.uk +SERC Daresbury Laboratory, | old UUCP: ...!ukc!daresbury!d.love +Warrington WA4 4AD, | alternative BITNET: d.love%dl@ukacrl +UK | alternative ARPA: d.love%dl@nsfnet-relay.ac.uk + 'Phone: (+44/0)925 603573, Telex: ...925 629609, FAX: ...925 603173 + + +Here is a contents list. You will need to copy the files to the +correct sub-directories of the spider source (once you are sure you +want to) and invoke, for instance, `make weave' in the C directory to +make a LaTeX version of weave. See web.doc for definitive information +on the TeX aspect of things. + +* README.LaTeX This file; + +* latexweb.tex A short LaTeX document describing this stuff, + intended for submission to TUGboat; + +* weave.ltx A change file for $MASTER/weave.web which + inserts #defines to allow it to be compiled + for LaTeX-compatible output; + +* tangle.ltx Trivial change file for $MASTER/tangle.web to + allow woven output from it to be printed with + either LaTeX or plain; + +* spider.ltx Change file for $MASTER/spider.web to allow it + to produce output for a plain or LaTeX weave; + +* WebMakefile Changed version of $MASTER/WebMakefile + to cope with the change files above and the + different possible versions (also with my + filenames wired in); + +* web.doc Self-documenting LaTeX sub-style for use + instead of webkernel.tex. Probably needs + Mittelbach's newdoc.sty, v1.6d or later to + produce documentation -- instructions at the + front of it; + +* web.sty web.doc with comments stripped; + +* cmake Changed version of $SPIDER/c/make to produce + LaTeX ceeweave; + +* awkmake Changed version of $SPIDER/awk/make to produce + LaTeX awkweave; + +* cspider.dif Trivial diff from $SPIDER/c/c.spider to allow + it to work with LaTeX or plain; + +* tie.web Translation of the TIE processor to spidery + C-web. This allows you to merge change files + with the original or with other change files, + which may be useful for combining the LaTeX + changes with any you already have; + +* tiedoc.tex Explanation of the above. diff --git a/web/spiderweb/fixes-to-be-applied/latex/WebMakefile b/web/spiderweb/fixes-to-be-applied/latex/WebMakefile new file mode 100644 index 0000000000..4e948515af --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/WebMakefile @@ -0,0 +1,172 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +# Modified by Dave Love, Daresbury Lab (d.love@daresbury.ac.uk) for local +# setup and to incorporate change files, particularly for LaTeX mods. +# To make LaTeX versions of weave, set WEAVECHANGEFILE=$(MASTER)/weave.ltx +# and include -DLaTeX in CFLAGS. To get a version of spider.awk usable for +# LaTeX or plain, define SPIDERCHANGEFILE=$(MASTER)/spider.ltx and define +# LaTeX=1 so that spider.awk generates LaTeX-compatible webs. I'm sure all +# this could be tidied up. + +#HOME=/home/users0/fx# # Make no longer inherits environment vars +# (it does inherit env vars on my system!) +THETANGLE=tangle +THEWEAVE=weave +SPIDER=any.spider +WEAVECHANGEFILE= +TANGLECHANGEFILE= +SPIDERCHANGEFILE= + +# +DVI=dvi +CFLAGS=-DDEBUG -DSTAT + +# CPUTYPE is a grim hack that attempts to solve the problem of multiple +# cpus sharing a file system. In my environment I have to have different +# copies of object and executable for vax, sun3, next, iris, and other +# cpu types. If you will be using Spidery WEB in a homogenous processor +# environment, you can just set CPUTYPE to a constant, or eliminate it +# entirely. +# +# In my environment, the 'cputype' program returns a string that +# describes the current processor. That means that the easiest thing +# for you to do is to define a 'cputype' program that does something +# sensible. A shell script that says 'echo "vax"' is fine. + +#CPUTYPE=`cputype` +CPUTYPE=`arch` + +# Change the following three directories to match your installation +# +# the odd placement of # is to prevent any trailing spaces from slipping in + +WEBROOT=$(HOME)/ltxspiderweb# # root of the WEB source distribution +DEST=$(HOME)/bin# # place where the executables go +MACROS=$(HOME)/tex/inputs# # place where the macros go + +MASTER=$(WEBROOT)/master# # master source directory +OBDIR=$(MASTER)/$(CPUTYPE)# # common object files + +TANGLESRC=tangle +CTANGLE=ceetangle -I$(MASTER) +CWEAVE=ceeweave -I$(MASTER) +AWKTANGLE=awktangle -I$(MASTER) +COMMONOBJS=$(OBDIR)/common.o $(OBDIR)/pathopen.o +COMMONC=$(MASTER)/common.c $(MASTER)/pathopen.c +COMMONSRC=$(COMMONC) $(MASTER)/spider.awk + + + +# Our purpose is to make tangle and weave + +web: tangle weave + +tangle: $(COMMONOBJS) $(TANGLESRC).o + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + +weave: $(COMMONOBJS) weave.o + cc $(CFLAGS) -o $(DEST)/$(THEWEAVE) $(COMMONOBJS) weave.o + + +source: $(TANGLESRC).c $(COMMONSRC) # make tangle.c and common src, then clean + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.web weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + +# Here is how we make the common stuff + +$(MASTER)/common.c: $(MASTER)/common.web $(MASTER)/common.ch + $(CTANGLE) $(MASTER)/common $(MASTER)/common + +$(OBDIR)/common.o: $(MASTER)/common.c + cc $(CFLAGS) -c $(MASTER)/common.c + mv common.o $(OBDIR) + + +$(MASTER)/pathopen.c: $(MASTER)/pathopen.web $(MASTER)/pathopen.ch + $(CTANGLE) $(MASTER)/pathopen $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +$(OBDIR)/pathopen.o: $(MASTER)/pathopen.c + cc $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(OBDIR) + + +## Now we make the tangle and weave source locally + +$(TANGLESRC).c: $(MASTER)/$(TANGLESRC).web $(MASTER)/common.h grammar.web \ + $(TANGLECHANGEFILE) + -/bin/rm -f $(TANGLESRC).web + ln $(MASTER)/$(TANGLESRC).web $(TANGLESRC).web +# chmod -w $(TANGLESRC).web + $(CTANGLE) $(TANGLESRC) $(TANGLECHANGEFILE) + +weave.c: $(MASTER)/weave.web $(MASTER)/common.h grammar.web $(WEAVECHANGEFILE) + -/bin/rm -f weave.web + ln $(MASTER)/weave.web weave.web +# chmod -w weave.web + $(CTANGLE) weave $(WEAVECHANGEFILE) + +## Here's where we run SPIDER to create the source + +grammar.web: $(MASTER)/cycle.awk $(MASTER)/spider.awk $(SPIDER) + echo "date" `date` | cat - $(SPIDER) | awk -f $(MASTER)/spider.awk \ + LaTeX=$(LaTeX) - + cat $(MASTER)/transcheck.list trans_keys.unsorted | awk -f \ + $(MASTER)/transcheck.awk + awk -f $(MASTER)/cycle.awk < cycle.test + sort *.unsorted | awk -f $(MASTER)/nodups.awk + mv *web.tex $(MACROS) + +## We might have to make spider first. + +$(MASTER)/spider.awk: $(MASTER)/spider.web $(SPIDERCHANGEFILE) + $(AWKTANGLE) $(MASTER)/spider $(SPIDERCHANGEFILE) + mv cycle.awk nodups.awk transcheck.awk $(MASTER) + rm junk.list + +# $(MASTER)/cycle.awk: $(MASTER)/cycle.web # making spider also makes cycle +# $(AWKTANGLE) $(MASTER)/cycle + +# Weaving: + +weave.tex: $(MASTER)/weave.web grammar.web $(WEAVECHANGEFILE) + ceeweave -I$(MASTER) $(MASTER)/weave.web $(WEAVECHANGEFILE) + mv $(MASTER)/weave.tex . + +tangle.tex: $(MASTER)/tangle.web $(TANGLECHANGEFILE) + ceeweave -I$(MASTER) $(MASTER)/tangle.web $(TANGLECHANGEFILE) + mv $(MASTER)/tangle.tex . + +spider.tex: $(MASTER)/spider.web $(SPIDERCHANGEFILE) + awkweave -I$(MASTER) $(MASTER)/spider.web $(SPIDERCHANGEFILE) + mv $(MASTER)/spider.tex . + +# This cleanup applies to every language + +clean: + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.web weave.web common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog +# vital bootstrap files are kept as SAVE..., hence only remove .c files whose +# names start with lower case + -rm -f [a-z]*.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + + + +# booting the new distribution +boot: + cd ../master; rm -f *.o; for i in $(COMMONC); do \ + cc $(CFLAGS) -c $$i; \ + mv *.o $(OBDIR) ; \ + done; cd ../c + cc $(CFLAGS) -c $(TANGLESRC).c; \ + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + + diff --git a/web/spiderweb/fixes-to-be-applied/latex/awkmake b/web/spiderweb/fixes-to-be-applied/latex/awkmake new file mode 100644 index 0000000000..02cc270328 --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/awkmake @@ -0,0 +1,5 @@ +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=awktangle THEWEAVE=awkweave SPIDER=awk.spider \ +SPIDERCHANGEFILE=../master/spider.ltx WEAVECHANGEFILE=../master/weave.ltx \ +TANGLECHANGEFILE=../master/tangle.ltx \ +CFLAGS='-O1 -DC_FLOATING_POINT -DLaTeX' LaTeX=1 $* diff --git a/web/spiderweb/fixes-to-be-applied/latex/cmake b/web/spiderweb/fixes-to-be-applied/latex/cmake new file mode 100644 index 0000000000..d2853dbaa1 --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/cmake @@ -0,0 +1,5 @@ +#!/bin/csh -f +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ +CFLAGS="-O1 -DC_FLOATING_POINT -DLaTeX" LaTeX=1 THETANGLE=ceetangle \ +THEWEAVE=ceeweave SPIDER=c.spider TANGLECHANGEFILE=../master/tangle.ltx \ +WEAVECHANGEFILE=../master/weave.ltx SPIDERCHANGEFILE=../master/spider.ltx $* diff --git a/web/spiderweb/fixes-to-be-applied/latex/cspider.dif b/web/spiderweb/fixes-to-be-applied/latex/cspider.dif new file mode 100644 index 0000000000..1ed829d428 --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/cspider.dif @@ -0,0 +1,17 @@ +*** c/c.spider Mon Feb 19 03:47:06 1990 +--- /home/users0/fx/ltxspiderweb/c/c.spider Wed Mar 13 11:58:35 1991 +*************** +*** 326,330 **** + + # control sequence \8 puts things on the left margin +! <force-"\\8"> sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc + preproc backslash <force-"\\8\\hskip1em"-space> newline --> preproc + preproc <force-outdent> newline --> ignore_scrap +--- 326,332 ---- + + # control sequence \8 puts things on the left margin +! #<force-"\\8"> sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +! # changed to work with LaTeX as well: +! <force-"\\8"> sharp <"{\\let\\idfont=\\reservedfont"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc + preproc backslash <force-"\\8\\hskip1em"-space> newline --> preproc + preproc <force-outdent> newline --> ignore_scrap diff --git a/web/spiderweb/fixes-to-be-applied/latex/latexweb.tex b/web/spiderweb/fixes-to-be-applied/latex/latexweb.tex new file mode 100644 index 0000000000..63219a188d --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/latexweb.tex @@ -0,0 +1,81 @@ +\documentstyle[ltugboat]{article} + +\let\tensl=\sl +\title{\WEB{} Adapted to \LaTeX{} --- a First Attempt} +\author{David Love} +\netaddress{d.love@daresbury.ac.uk} +\begin{document} +\maketitle +\noindent +Following Knuth's original Pascal/TeX{} \WEB{} system a number of +\WEB-like systems have been developed. Mostly these use the same +plain \TeX{} formatting system and differ in the languages supported +(although Thimbleby's CWEB system uses Troff and there are non-\WEB{} +literate programming systems like Scheme\TeX{} and {\tt doc.sty} that +use \LaTeX)\footnote{For a \WEB{} bibliography, see Lisa M. C. Smith +and Mansur Samadzadeh, {\sl SIGPLAN Notices\/} {\bf 26} (1991)}\@. +There are two advantages to using \LaTeX{} rather than plain \TeX{} +for formatting: +\begin{itemize} +\item greater accessibility for many (familiarity and ease of use) +which may encourage more people to use it; +\item the availability of extra intrinsic \LaTeX{} facilities and +especially style options. These might, for instance, support setting +your formal specification material as well as the code refined from +it, and in non-CM fonts. +\end{itemize} +This note describes a first attempt at integrating \LaTeX{} with +\WEB\ (actually Ramsey's Spider system for +`language-independent' \WEB s\footnote{Sometimes Spider doesn't do the +whole job for you: non-Algol-like languages may need the lexing +routines hacking. This gives the complication of +amalgamating the basic \WEAVE{} change file for \LaTeX{} formatting +with changes for the lexical routines etc.}). + +I have made minimal changes necessary for Spidery \WEB s to work with +\LaTeX\@. These take the form of change files for the base {\tt +weave.web}, {\tt tangle.web} and {\tt spider.web} (which generates the +language-dependent parts), conversion of the {\tt webkernel.tex} macro +file to a \LaTeX{} sub-style and trivial updates to the make files. A +trivial change to the {\tt c.spider} file that describes the +prettyprinting grammar for C was also necessary. The result of +merging the change files with the original webs would be a {\tt +weave.web} that can be built for use with either plain \TeX\ or +\LaTeX\ using a makefile flag and a {\tt spider.web} that produces a +{\tt spider.awk} with a run-time switch to determine the formatter. +(\WEAVE\ cannot change the formatter assumed at run time, although it +would not be difficult to make it do so.) \WEB\ files can be woven +with either a plain or \LaTeX\ \WEAVE\ if they avoid using +incompatible macros or define them appropriately in limbo +according to whether the \LaTeX\ macros are present. + +The changes to {\tt spider.web} are minor; changes to {\tt weave.web} +and the macros are more extensive. Many of the original \WEB{} macros +clash with \LaTeX{} names or conventions and have been changed +appropriately, but only where necessary. The formatting style is +essentially unchanged apart from the use of the \LaTeX\ page headers +and contents list. {\tt web.sty} is documented with {\tt doc.sty} +since it is a pity not to use literate techniques to build literate +programming tools---the bulk of the work! There are some remaining +infelicities, such as floats being disrupted by the way the sectioning +code avoids page breaks and a lot of messiness due to the assumptions +of existing Spider descriptions. + +This hack could be developed in other directions, for instance: +\begin{itemize} +\item proper parameterisation of the formatting commands, perhaps +modelled after {\tt makeindex}; +\item adapting the formatting macros more to the \LaTeX{} style; +\item inclusion of a proper multi-level sectioning scheme. I think +the extra structure would be helpful in large webs, but implementing +it would require considerable attention to the guts of \TANGLE{} and +\WEAVE\@. (It affects \TANGLE{} through the comments it writes in the +code); +\item replacing the index processing with {\tt makeindex}. +\end{itemize} + +The changes should be available from the Aston archive as {\tt +[.web.spiderweb]latexmods.shar}. + +\makesignature +\end{document} diff --git a/web/spiderweb/fixes-to-be-applied/latex/spider.ltx b/web/spiderweb/fixes-to-be-applied/latex/spider.ltx new file mode 100644 index 0000000000..6e26a5304e --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/spider.ltx @@ -0,0 +1,107 @@ +% this is spider.ch $Header: /home/users0/fx/ltxspiderweb/master/spider.ltx,v 1.3 91/03/22 11:19:54 fx Exp $ +% for a LaTeX version of spider +% d.love@daresbury.ac.uk + +l 5 (don't want batchmode for debugging; only print changes; for + LaTeX: want \documentstyle and fix use of \. and \title) +#x +\message{OK, entering \string\batchmode...} +\batchmode +#y +\ifx\enddocument\undefined \else % check for LaTeX + \documentstyle[web]{article} + \let\maybe\iffalse + \let\.=\str + \def\LaTeX{{\rm L\kern-.36em\raise.3ex\hbox{\sc a}\kern-.15em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} +\fi +#z + +l 13 (change title page stuff) +#x +\def\title{SPIDER} + +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont SPIDER} processor} + \vfill} +#y +\ifx\enddocument\undefined % check for LaTeX +\def\title{SPIDER} + +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont SPIDER} processor} + \vfill} +\else + \title{The {\tt SPIDER} processor} \date{} +\fi +#z + +l 39 +#x +The unusual lexical requirements of FORTRAN are probably beyond it, at +least until the lexical analysis is modernized.) +#y +The unusual lexical requirements of FORTRAN are probably beyond it, at +least until the lexical analysis is modernized.) + +This version of Spider has been changed to be able to produce a +\.{WEAVE} suitable for use with \LaTeX{} rather than plain \TeX{}. +The changes are minor and can be found by looking up ``LaTeX'' in the +index. You get the \LaTeX{} version by defining |LaTeX=1| or +something (the variable |LaTeX| should be non-null) on +the \.{awk} command line when you run Spider. The limbo part will sort +itself out for \LaTeX{} or plain when you weave this file. +#z + +l 188 (bug fix) +#x +#<Set init...#>= + scrapfile = "scraps.web" + print "@*Scrap code generated by {\tt SPIDER}." > scrapfile + ttokfile = "outtoks.web" + print "@*Token code generated by {\tt SPIDER}." > scrapfile +#y +#<Set init...#>= + scrapfile = "scraps.web" + print "@*Scrap code generated by {\\tt SPIDER}." > scrapfile + ttokfile = "outtoks.web" + print "@*Token code generated by {\\tt SPIDER}." > scrapfile +#z + +l 211 (bug fix) +#x + grammarfile = "grammar.web" + print "@*Grammar code generated by {\tt SPIDER}." > grammarfile +#y + grammarfile = "grammar.web" + print "@*Grammar code generated by {\\tt SPIDER}." > grammarfile +#z + +l 2108 (change for LaTeX) +#x + printf "*out_ptr='x'; tex_printf(\"\\\\input %sweb.te\");\n", \ + extension > wlang +#y + if (LaTeX=="") { #^LaTeX#> + printf "*out_ptr='x'; tex_printf(\"\\\\input %sweb.te\");\n", \ + extension > wlang + }else{ + printf "*out_ptr='}'; tex_printf(\"\\\\def\\\\webmacs{%sweb.tex\");\n", \ + extension > wlang + } +#z + +l 2121 (change for LaTeX) +#x +#<Write the first line of the macro file#>= + macrofile = extension "web.tex" + print "\\input webkernel.tex" > macrofile +#y +#<Write the first line of the macro file#>= + macrofile = extension "web.tex" + if (LaTeX=="") print "\\input webkernel.tex" > macrofile #^LaTeX#> +#z diff --git a/web/spiderweb/fixes-to-be-applied/latex/tangle.ltx b/web/spiderweb/fixes-to-be-applied/latex/tangle.ltx new file mode 100644 index 0000000000..c7c054c5a2 --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/tangle.ltx @@ -0,0 +1,79 @@ +this is tangle.latex-ch to fix tangle.web so that it can be woven with +the LaTeX version of weave +$Header: /home/users0/fx/ltxspiderweb/master/tangle.ltx,v 1.1 91/03/22 11:32:59 fx Exp $ +d.love@daresbury.ac.uk + +l 12 (fix for use with LaTeX or plain) +@x +% Here is TeX material that gets inserted after \input webmac + +\message{OK, entering \string\batchmode...} +\batchmode + +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps +\def\cee{C} +\def\pb{$\.|\ldots\.|$} % C brackets (|...|) +\def\v{\char'174} % vertical (|) in typewriter font +\def\ceeref{{\it The C Reference Manual}} +\mathchardef\RA="3221 % right arrow +\mathchardef\BA="3224 % double arrow + +\def\title{Spidery TANGLE} +\def\contentspagenumber{1} % should be odd +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont Spidery TANGLE} processor} + \vfill +} +@y +% Here is TeX material that gets inserted after \documentstyle + +% \message{OK, entering \string\batchmode...} +% \batchmode + +\ifx\enddocument\undefined % LaTeX? +\font\ninerm=cmr9 % no... +\let\mc=\ninerm % medium caps (not actually used) +\def\title{Spidery TANGLE} +\def\contentspagenumber{1} % should be odd +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont Spidery TANGLE} processor} + \vfill +} +\else % yes... +\documentstyle[web]{article} +\title{Spidery TANGLE}\date{} +\let\.=\str +\fi + +\def\hang{\hangindent 3em\indent\ignorespaces} +\def\cee{C} +\def\pb{$\.|\ldots\.|$} % C brackets (|...|) +\def\v{\char'174} % vertical (|) in typewriter font +\def\ceeref{{\it The C Reference Manual}} +\mathchardef\RA="3221 % right arrow +\mathchardef\BA="3224 % double arrow +@z + +l 1296 (fix \item) +@x +\yskip \item{a)}Module names are not allowed in macros; +in fact, the appearance of a module name terminates such macros and denotes +the name of the current module. + +\item{b)}The symbols \.{@@d} and \.{@@f} and \.{@@u} are not allowed after +module names, while they terminate macro definitions. +@y +\begin{itemize} + \item[a)]Module names are not allowed in macros; +in fact, the appearance of a module name terminates such macros and denotes +the name of the current module. +\item[b)]The symbols \.{@@d} and \.{@@f} and \.{@@u} are not allowed after +module names, while they terminate macro definitions. +\end{itemize} +@z diff --git a/web/spiderweb/fixes-to-be-applied/latex/tie.web b/web/spiderweb/fixes-to-be-applied/latex/tie.web new file mode 100644 index 0000000000..3739558e19 --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/tie.web @@ -0,0 +1,1276 @@ +% This is TIE.CWB as of 25 Oct 89 +%--------------------------------------------------------- +% (c) 1989 by THD/ITI. Put into the public domain. + +% +% Version 1.7 was built alike TIE.WEB Version 1.6 (89-01-27) +% but used a command line interface only +% Version 2.0 was revised to include optional tab expansion (89-02-01) +% Version 2.1 deleted WEB relicts. (-js) (89-10-25) +% + +% Converted to spidery web Dave Love Feb 91 & bug fixed at line 990 +% and took out a couple of `@+' after `*' which break spidery weave + +% Here is TeX material that gets inserted after \input cwebmac + +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\mc=cmr9 +\def\PASCAL{Pascal} +\def\Cl{{\rm C}} +\def\ASCII{{\mc ASCII}} + +\def\title{TIE} +\def\topofcontents{\null\vfill + \centerline{\titlefont The {\ttitlefont TIE} processor} + \vskip 15pt + \centerline{(CWEB Version 2.1)} + \vfill} +\def\botofcontents{ +\null\vfill +\item{$\copyright$}1989 + by Technische Hochschule Darmstadt,\hfill\break +Fachbereich Informatik, Institut f\"ur Theoretische Informatik\hfill\break +All rights reserved.\hfill\break +This program is put into the public domain and may be used freely +for any non commercial purposes. +} + + + + + +@* Introduction. + +\noindent Whenever a programmer wants to change a given +\.{WEB} or \.{CWEB} program (referred to as a \.{WEB} program throughout +this program) because of system dependencies, he will +create a new change file. In addition there may be a second +change file to modify system independent modules of the +program. But the \.{WEB} file cannot be tangled and weaved +with more than one change file simultaneously. Therefore, +we introduce the present program to merge a \.{WEB} file and +several change files producing a new \.{WEB} file. Since +the input files are tied together, the program is called +\.{TIE}. Furthermore, the program can be used to merge +several change files giving a new single change file. This +method seems to be more important because it doesn't modify +the original source file. The use of \.{TIE} can be +expanded to other programming languages since this processor +only knows about the structure of change files and does not +interpret the master file at all. + +The program \.{TIE} has to read lines from several input +files to bring them in some special ordering. For this +purpose an algorithm is used which looks a little bit +complicated. But the method used only needs one buffer line +for each input file. Thus the storage requirement of +\.{TIE} does not depend on the input data. + +The program is written in \Cl\ and uses only few features of a +particular environment that may need to be changed in other +installations. +E.g.\ it will not use the |enum| type declarations. +The changes needed may refer to the access of the command line +if this can be not supported by any \Cl\ compiler. + +The ``banner line'' defined here should be changed whenever +\.{TIE} is modified. This program is put into the public +domain. Nevertheless the copyright notice must not be +replaced or modified. + +@d banner="This is TIE, CWEB Version 2.1." +@d copyright= + "Copyright (c) 1989 by THD/ITI. All rights reserved." + + +@ The main outline of the program is given in the next section. +This can be used more or less for any \Cl\ program. +@c +@<Global |#include|s@> +@<Global constants@> +@<Global types@> +@<Global variables@> +@<Error handling functions@> +@<Internal functions@> +@<The main function@> + +@ Here are some macros for common programming idioms. + +@d incr(a) = a+=1 /* increase a variable by unity */ +@d decr(a) = a-=1 /* decrease a variable by unity */ +@d loop = @+ while (1)@+ /* repeat over and over until a |break| happens */ +@d do_nothing = /* empty statement */ +@f loop repeat + + +@ Furthermore we include the additional types |boolean| and |string|. + +@<Global types@>= +#define @!false 0 +#define @!true 1 +typedef int @!boolean; +typedef char* string; + + +@ The following parameters should be sufficient for most +applications of \.{TIE}. +@^system dependencies@> + +@<Global constants@>= +#define @!buf_size 512 /* maximum length of one input line */ +#define @!max_file_index 9 +/* we don't think that anyone needs more than 9 change files, + but \dots\ just change it */ + + +@ We introduce a history variable that allows us to set a +return code if the operating system can use it. +First we introduce the coded values for the history. +This variable must be initialized. +(We do this even if the value given may be the default for +variables, just to document the need for the initial value.) +@d spotless=0 +@d troublesome=1 +@d fatal=2 + +@<Global variables@>= +int @!history=spotless; + + + +@* The character set. + +\noindent One of the main goals in the design of \.{TIE} has +been to make it readily portable between a wide variety of +computers. Yet \.{TIE} by its very nature must use a +greater variety of characters than most computer programs +deal with, and character encoding is one of the areas in +which existing machines differ most widely from each other. + +To resolve this problem, all input to \.{TIE} is converted to an +internal seven-bit code that is essentially standard \ASCII{}, the +``American Standard Code for Information Interchange.'' The conversion +is done immediately when each character is read in. Conversely, +characters are converted from \ASCII{} to the user's external +representation just before they are output. But the algorithm is +prepared for the usage of eight-bit data. + +\noindent Here is a table of the standard visible \ASCII{} codes: +$$\def\:{\char\count255\global\advance\count255 by 1} +\count255='40 +\vbox{ +\hbox{\hbox to 40pt{\it\hfill0\/\hfill}% +\hbox to 40pt{\it\hfill1\/\hfill}% +\hbox to 40pt{\it\hfill2\/\hfill}% +\hbox to 40pt{\it\hfill3\/\hfill}% +\hbox to 40pt{\it\hfill4\/\hfill}% +\hbox to 40pt{\it\hfill5\/\hfill}% +\hbox to 40pt{\it\hfill6\/\hfill}% +\hbox to 40pt{\it\hfill7\/\hfill}} +\vskip 4pt +\hrule +\def\^{\vrule height 10.5pt depth 4.5pt} +\halign{\hbox to 0pt{\hskip -24pt\O{#0}\hfill}&\^ +\hbox to 40pt{\tt\hfill#\hfill\^}& +&\hbox to 40pt{\tt\hfill#\hfill\^}\cr +04&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +05&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +06&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +07&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +10&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +11&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +12&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +13&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +14&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +15&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +16&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +17&\:&\:&\:&\:&\:&\:&\:\cr} +\hrule width 280pt}$$ +(Actually, of course, code @'040 is an invisible blank space.) Code @'136 +was once an upward arrow (\.{\char'13}), and code @'137 was +once a left arrow (\.^^X), in olden times when the first draft +of ASCII code was prepared; but \.{TIE} works with today's standard +ASCII in which those codes represent circumflex and underline as shown. +The maximum value used is also defined, it must be changed if an +extended \ASCII{} is used. + +If the \Cl\ compiler is not able to process \&{unsigned char}'s, you +should define |ASCII_Code| as \&{short}. +@^system dependencies@> + +@<Global types@>= +#define max_ASCII @`~'+1 +typedef unsigned char @!ASCII_Code; + /* eight-bit numbers, a subrange of the integers */ + + +@ \Cl\ was first implemented on a machine that uses the +\ASCII{} representation for characters. But to make it readily +available also for other machines (big brother is watching?)\ +we add a conversion that may be undone for most installations. +\.{TIE} assumes that it is being used +with a character set that contains at least the +characters of standard \ASCII{} as listed above. + +In order to accommodate this difference, we shall use the +name |text_char| to stand for the data type of the +characters in the input and output files. We shall also +assume that |text_char| consists of the elements +|first_text_char| through |last_text_char|, +inclusive. The following definitions should be adjusted if +necessary. +@^system dependencies@> + +@d text_char = @+ unsigned char /* the data type of characters in text files */ +@d first_text_char=0 /* ordinal number of the smallest element of |text_char|*/ +@d last_text_char=255 /* ordinal number of the largest element of |text_char|*/ +@f FILE int + +@<Global types@>= +typedef FILE* @!text_file; + + +@ The \.{TIE} processor converts between \ASCII{} code and +the user's external character set by means of arrays |xord| +and |xchr| that are analogous to \PASCAL's |ord| and |chr| +functions. + +The mapping may be disabled by changing the following macro +definitions to just a cast. If your \Cl\ compiler does not support +\&{unsigned char}'s, you should incorporate a binary and with @"ff. +@^system dependencies@> + +@d map_xchr(a)=xchr[a] + /* change this to |(text_char)(a)| on \ASCII{} machines */ +@d map_xord(a)=xord[a] + /* change this to |(ASCII_Code)(a)| on \ASCII{} machines */ + +@<Global variables@>= +ASCII_Code @!xord[last_text_char+1]; + /* specifies conversion of input characters */ +text_char @!xchr[max_ASCII+1]; + /* specifies conversion of output characters */ + + +@ If we assume that every system using \.{WEB} is able to +read and write the visible characters of standard \ASCII{} +(although not necessarily using the \ASCII{} codes to +represent them), the following assignment statements +initialize most of the |xchr| array properly, without +needing any system-dependent changes. For example, the +statement |xchr[@`A']='A'| that appears in the present +\.{WEB} file might be encoded in, say, {\mc EBCDIC} code on +the external medium on which it resides, but \.{CTANGLE} will +convert from this external code to \ASCII{} and back again. +Therefore the assignment statement |xchr[65]='A'| will +appear in the corresponding \Cl\ file, and \Cl\ will +compile this statement so that |xchr[65]| receives the +character \.A in the external code. Note that it +would be quite incorrect to say |xchr[@`A']=@`A'|, because +|@`A'| is a constant of type |int| not \&{char}, and +because we have |@`A'==65| regardless of the external +character set. + +@<Set initial values@>= +xchr[@` ']=' '; +xchr[@`!']='!'; +xchr[@`"']='"'; +xchr[@`#']='#';@/ +xchr[@`$']='$'; +xchr[@`%']='%'; +xchr[@`&']='&'; +xchr[@`'']='\'';@/ +xchr[@`(']='('; +xchr[@`)']=')'; +xchr[@`*']='*'; +xchr[@`+']='+';@/ +xchr[@`,']=','; +xchr[@`-']='-'; +xchr[@`.']='.'; +xchr[@`/']='/';@/ +xchr[@`0']='0'; +xchr[@`1']='1'; +xchr[@`2']='2'; +xchr[@`3']='3';@/ +xchr[@`4']='4'; +xchr[@`5']='5'; +xchr[@`6']='6'; +xchr[@`7']='7';@/ +xchr[@`8']='8'; +xchr[@`9']='9'; +xchr[@`:']=':'; +xchr[@`;']=';';@/ +xchr[@`<']='<'; +xchr[@`=']='='; +xchr[@`>']='>'; +xchr[@`?']='?';@/ +xchr[@`@@']='@@'; +xchr[@`A']='A'; +xchr[@`B']='B'; +xchr[@`C']='C';@/ +xchr[@`D']='D'; +xchr[@`E']='E'; +xchr[@`F']='F'; +xchr[@`G']='G';@/ +xchr[@`H']='H'; +xchr[@`I']='I'; +xchr[@`J']='J'; +xchr[@`K']='K';@/ +xchr[@`L']='L'; +xchr[@`M']='M'; +xchr[@`N']='N'; +xchr[@`O']='O';@/ +xchr[@`P']='P'; +xchr[@`Q']='Q'; +xchr[@`R']='R'; +xchr[@`S']='S';@/ +xchr[@`T']='T'; +xchr[@`U']='U'; +xchr[@`V']='V'; +xchr[@`W']='W';@/ +xchr[@`X']='X'; +xchr[@`Y']='Y'; +xchr[@`Z']='Z'; +xchr[@`[']='[';@/ +xchr[@`\\']='\\'; +xchr[@`]']=']'; +xchr[@`^']='^'; +xchr[@`_']='_';@/ +xchr[@`'']='`'; +xchr[@`a']='a'; +xchr[@`b']='b'; +xchr[@`c']='c';@/ +xchr[@`d']='d'; +xchr[@`e']='e'; +xchr[@`f']='f'; +xchr[@`g']='g';@/ +xchr[@`h']='h'; +xchr[@`i']='i'; +xchr[@`j']='j'; +xchr[@`k']='k';@/ +xchr[@`l']='l'; +xchr[@`m']='m'; +xchr[@`n']='n'; +xchr[@`o']='o';@/ +xchr[@`p']='p'; +xchr[@`q']='q'; +xchr[@`r']='r'; +xchr[@`s']='s';@/ +xchr[@`t']='t'; +xchr[@`u']='u'; +xchr[@`v']='v'; +xchr[@`w']='w';@/ +xchr[@`x']='x'; +xchr[@`y']='y'; +xchr[@`z']='z'; +xchr[@`{']='{';@/ +xchr[@`|']='|'; +xchr[@`}']='}'; +xchr[@`~']='~';@/ +xchr[0]=' '; xchr[@"7F]=' '; /* these \ASCII{} codes are not used */ + + +@ Some of the \ASCII{} codes below @"20 have been given a +symbolic name in \.{TIE} because they are used with a special +meaning. + +@d tab_mark = @"09 /* \ASCII{} code used as tab-skip */ +@d nl_mark = @"0A /* \ASCII{} code used as line end marker */ +@d form_feed = @"0C /* \ASCII{} code used as page eject */ + + +@ When we initialize the |xord| array and the remaining +parts of |xchr|, it will be convenient to make use of an +index variable, |i|. + +@<Local variables for initialisation@>= +int i; + + +@ Here now is the system-dependent part of the character +set. If \.{TIE} is being implemented on a garden-variety +\Cl\ for which only standard \ASCII{} codes will appear +in the input and output files, you don't need to make any +changes here. +@^system dependencies@> + +Changes to the present module will make \.{TIE} more +friendly on computers that have an extended character set, +so that one can type things like \.^^Z. If you have an +extended set of characters that are easily incorporated into +text files, you can assign codes arbitrarily here, giving an +|xchr| equivalent to whatever characters the users of +\.{TIE} are allowed to have in their input files, provided +that unsuitable characters do not correspond to special +codes like |tab_mark| that are listed above. + +@<Set init...@>= +for (i=1;i<@` ';xchr[i++]=' '); +xchr[tab_mark]='\t'; +xchr[form_feed]='\f'; +xchr[nl_mark]='\n'; + + +@ The following system-independent code makes the |xord| +array contain a suitable inverse to the information in +|xchr|. + +@<Set init...@>= +for ( i=first_text_char ; i<=last_text_char ; xord[i++]=@` ' ) do_nothing; +for ( i=1 ; i<=@`~' ; i++ ) xord[xchr[i]] = i; + + + + + +@* Input and output. + +\noindent Output for the user is done by writing on file |term_out|, +which is assumed to consist of characters of type \&{text\_char}. It +should be linked to |stdout| usually. Terminal input is not needed in +this version of \.{TIE}. |stdin| and |stdout| are predefined if we +include the \.{stdio.h} definitions. Although I/O redirection for +|stdout| is usually available you may lead output to another file if +you change the definition of |term_out|. Also we define some macros +for terminating an output line and writing strings to the user. These +distinguish the number of parameters used to ease translation with a +\.{CWEB} like Sylvio Levy's that does not support a variable number of +parameters for macros. + +@^system dependencies@> +@d term_out=stdout +@d print(a)=fprintf(term_out,a) /* `|print|' means write on the terminal */ +@d print2(a)=fprintf(term_out,a) /* same with two arguments */ +@d print3(a)=fprintf(term_out,a) /* same with three arguments */ +@d print_c(a)=fputc(a,term_out); /* print a single character */ +@d new_line(a)=fputc('\n',a) /* start new line */ +@d term_new_line=new_line(term_out) /* start new line of the terminal */ +@d print_ln(a)={fprintf(term_out,a);term_new_line;} + /* `|print|' and then start new line */ +@d print2_ln(a)={print2(a);term_new_line;} /* same with two arguments */ +@d print3_ln(a)={print3(a);term_new_line;} /* same with three arguments */ +@d print_nl(a)= /* print information starting on a new line */ + {term_new_line; print(a);} +@d print2_nl(a)= /* same for two arguments */ + {term_new_line; print2(a);} + +@<Global |#include|s@>= +#include <stdio.h> + + +@ And we need dynamic memory allocation. +This should cause no trouble in any \Cl\ program. +@^system dependencies@> + +@<Global |#include|s@>= +extern char *malloc(); + + +@ The |update_terminal| function 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(term_out) /* empty the terminal output buffer */ + + + + + +@* Data structures. + +\noindent The multiple input files (master file and change +files) are treated the same way. To organize the +simultaneous usage of several input files, we introduce the +data type \&{in\_file\_modes}. + +The mode |search| indicates that \.{TIE} searches for a +match of the input line with any line of an input file in +|reading| mode. |test| is used whenever a match is found +and it has to be tested if the next input lines do match +also. |reading| describes that the lines can be read without +any check for matching other lines. |ignore| denotes +that the file cannot be used. This may happen because an +error has been detected or because the end of the file has +been found. + +\leavevmode |file_types| is used to describe whether a file +is a master file or a change file. The value |unknown| is added +to this type to set an initial mode for the output file. +This enables us to check whether any option was used to select +the kind of output. (this would even be necessary if we +would assume a default action for missing options.) + +@<Global types@>= +#define search 0 +#define test 1 +#define reading 2 +#define ignore 3 +typedef int @!in_file_modes; /* should be |enum(search,test,reading,ignore)| */ +#define unknown 0 +#define master 1 +#define chf 2 +typedef int @!file_types; /* should be |enum(unknown,master,chf)| */ + + +@ A variable of type |out_md_type| will tell us in what state the output +change file is during processing. |normal| will be the state, when we +did not yet start a change, |pre| will be set when we write the lines +to be changes and |post| will indicate that the replacement lines are +written. + +@<Global types@>= +#define normal 0 +#define pre 1 +#define post 2 +typedef int @!out_md_type; /* should be |enum(normal,pre,post)| */ + + +@ Two more types will indicate variables used as an index into either +the file buffer or the file table. + +@<Global types@>= +typedef int @!buffer_index; /* |-1..buf_size| */ +typedef int @!file_index; /* |-1..max_file_index+1| */ + + +@ The following data structure joins all informations needed to use +these input files. + +@<Global types@>= +typedef struct _idsc{ + string @!name_of_file; + ASCII_Code @!buffer[buf_size]; + in_file_modes @!mode; + long @!line; + file_types @!type_of_file; + buffer_index @!limit; + text_file the_file; + } @!input_description; + + +@ These data types are used in the global variable section. +They refer to the files in action, the number of change files, +the mode of operation and the current output state. + +@<Global variables@>= +file_index @!actual_input,@!test_input,@!no_ch; +file_types @!prod_chf=unknown; +out_md_type @!out_mode; + + +@ All input files (including the master file) are recorded +in the following structure. +Mostly the components are accessed through a local pointer variable. +This corresponds to \PASCAL's \&{with}-statement +and results in a one-time-computation of the index expression. + +@f input_description int + +@<Global variables@>= +input_description *@!input_organization[max_file_index+1]; + + + + + +@* File I/O. + +\noindent The basic function |get_line| can be used to get a line from +an input file. The line is stored in the |buffer| part of the +descriptor. The components |limit| and |line| are updated. If the +end of the file is reached |mode| is set to |ignore|. On some systems +it might be useful to replace tab characters by a proper number of +spaces since several editors used to create change files insert tab +characters into a source file not under control of the user. So it +might be a problem to create a matching change file. +@^tab character expansion@> + +We define |get_line| to read a line from a file specified by +the corresponding file descriptor. + +@<Internal functions@>= +@h void get_line(i) + file_index i; +{register input_description *inp_desc=input_organization[i]; + if (inp_desc->mode==ignore) return; + if (feof(inp_desc->the_file)) + @<Handle end of file and return@>; + @<Get line into buffer@>; +} + + +@ End of file is special if this file is the master file. +Then we set the global flag variable |input_has_ended|. + +@<Handle end of file ...@>= +{ + inp_desc->mode=ignore; + inp_desc->limit=-1; /* mark end-of-file */ + if (inp_desc->type_of_file==master) input_has_ended=true; + return; +} + + +@ This variable must be declared for global access. + +@<Global variables@>= +static boolean input_has_ended=false; + + +@ Lines must fit into the buffer completely. +We read all characters sequentially until an end of line is found +(but do not forget to check for |EOF|!). +Too long input lines will be truncated. +This will result in a damaged output if they occur in the +replacement part of a change file, or in an incomplerte check if the +matching part is concerned. +Tab character expansion might be done here. +@^tab character expansion@> + +@<Get line into buffer@>= +{int final_limit; /* used to delete trailing spaces */ + int c; /* the actual character read */ + @<Increment the line number and print a progess report at + certain times@> + inp_desc->limit=final_limit=0; + while (inp_desc->limit<buf_size) { + c=fgetc(inp_desc->the_file); + @<Check |c| for |EOF|, |return| if line was empty, otherwise + |break| to process last line@> + inp_desc->buffer[inp_desc->limit++]=c=map_xord(c); + if (c==nl_mark) break; /* end of line found */ + if (c!=@` ' && c!=tab_mark) + final_limit=inp_desc->limit; + } + @<Test for truncated line, skip to end of line@> + inp_desc->limit=final_limit; +} + + +@ This section does what its name says. Every 100 lines +in the master file we print a dot, every 500 lines the number +of lines is shown. + +@<Increment the line number and print ...@>= +incr(inp_desc->line); +if (inp_desc->type_of_file==master && inp_desc->line % 100==0) { + if (inp_desc->line % 500 == 0) print2("%ld",inp_desc->line); + else print_c('.'); + update_terminal; +} + + +@ There may be incomplete lines of the editor used does +not make sure that the last character before end of file +is an end of line. In such a case we must process the +final line. Of the current line is empty, we just can \&{return}. +Note that this test must be done {\sl before} the character read +is translated. +@^system dependencies@> + +@<Check |c| for |EOF|...@>= + if (c==EOF) { + if (inp_desc->limit<=0) { + inp_desc->mode=ignore; + inp_desc->limit=-1; /* mark end-of-file */ + if (inp_desc->type_of_file==master) input_has_ended=true; + return; + } else { /* add end of line mark */ + c=nl_mark; + break; + } + } + + +@ If the line is truncated we must skip the rest +(and still watch for |EOF|!). +@<Test for truncated line, skip to end of line@>= +if (c!=nl_mark) { + err_print("! Input line too long")(i); +@.Input line too long@> + while ( (c=fgetc(inp_desc->the_file)) != EOF && map_xord(c) != nl_mark ) + do_nothing; /* skip to end */ + } + + + + + +@* Reporting errors to the user. + +\noindent There may be errors if a line in a given change +file does not match a line in the master file or a +replacement in a previous change file. Such errors are +reported to the user by saying +$$ + \hbox{|err_print("! Error message")(file_no)|;} +$$ +where |file_no| is the number of the file which is concerned by the +error. Please note that no trailing dot is supplied by the error +message because it is appended by |err_print|. + +This function is implemented as a macro. It gives a message and an +indication of the offending file. The actions to determine the error +location are provided by a function called |err_loc|. + +@d error_loc(a) = err_loc(a); history=troublesome; @+ } +@d err_print(a) = { @+ print_nl(a); error_loc + +@<Error handling...@>= +@h void err_loc(i) /* prints location of error */ + int i; +{ + print3_ln(" (file %s, l.%ld).", + input_organization[i]->name_of_file, + input_organization[i]->line); +} + + +@ Non recoverable errors are handled by calling |fatal_error| that +outputs a message and then calls `|jump_out|'. |err_print| will print +the error message followed by an indication of where the error was +spotted in the source files. |fatal_error| cannot state any files +because the problem is usually to access these. + +@d fatal_error(a) = { + print(a); print_c('.'); history=fatal; + term_new_line; jump_out(); + } + + +@ |jump_out| just cuts across all active procedure levels and jumps +out of the program. It is used when no recovery from a particular +error has been provided. The return code from this program should be +regarded by the caller. + +@d jump_out(a) = exit(1) + + + + + +@* Handling multiple change files. + +\noindent In the standard version we take the name of the +files from the command line. +It is assumed that filenames can be used as given in the +command line without changes. + +First there are some sections to open all files. +If a file is not accessible, the run will be aborted. +Otherwise the name of the open file will be displayed. + +@<Prepare the output file@>= +{ + out_file=fopen(out_name,"w"); + if (out_file==NULL) { + fatal_error("! Could not open/create output file"); +@.Could not open/create output file@> + } +} + + +@ The name of the file and the file desciptor are stored in +global variables. + +@<Global variables@>= +text_file @!out_file; +string @!out_name; + + +@ For the master file we start just reading its first line +into the buffer, if we could open it. + +@<Get the master file started@>= +{ input_organization[0]->the_file= + fopen(input_organization[0]->name_of_file,"r"); + if (input_organization[0]->the_file==NULL) + fatal_error("! Could not open master file"); +@.Could not open master file@> + print2("(%s)",input_organization[0]->name_of_file); + term_new_line; + input_organization[0]->type_of_file=master; + get_line(0); +} + +@ For the change files we must skip the comment part and +see, whether we can find any change in it. +This is done by |init_change_file|. + +@<Prepare the change files@>= +{file_index i; + i=1; + while (i<no_ch) { + input_organization[i]->the_file= + fopen(input_organization[i]->name_of_file,"r"); + if (input_organization[i]->the_file==NULL) + fatal_error("!Could not open change file"); +@.Could not open change file@> + print2("(%s)",input_organization[i]->name_of_file); + term_new_line; + init_change_file(i,true); + incr(i); + } +} + + + + + +@*Input/output organization. + +\noindent Here's a simple function that checks if two lines +are different. + +@<Internal functions@>= +@h boolean lines_dont_match(i,j) + file_index i,j; +{ + buffer_index k,lmt; + if (input_organization[i]->limit != input_organization[j]->limit) + return(true); + lmt=input_organization[i]->limit; + for ( k=0 ; k<lmt ; k++ ) + if (input_organization[i]->buffer[k] != input_organization[j]->buffer[k]) + return(true); + return(false); +} + + +@ Function |init_change_file(i,b)| is used to ignore all +lines of the input file with index |i| until the next change +module is found. The boolean parameter |b| indicates +whether we do not want to see \.{@@x} or \.{@@y} entries during +our skip. + +@<Internal functions@>= +@h void init_change_file(i,b) + file_index i; boolean b; +{register input_description *inp_desc=input_organization[i]; + @<Skip over comment lines; |return| if end of file@>; + @<Skip to the next nonblank line; |return| if end of file@>; +} + + +@ 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} or \.{@@z} (which would +probably indicate that the change file is fouled up). + +@<Skip over comment lines...@>= +loop@+ {ASCII_Code c; + get_line(i); + if (inp_desc->mode==ignore) return; + if (inp_desc->limit<2) continue; + if (inp_desc->buffer[0] != @`@@') continue; + c=inp_desc->buffer[1]; + if (c>=@`X' && c<=@`Z') + c+=@`z'-@`Z'; /*lowercasify*/ + if (c==@`x') break; + if (c==@`y' || c==@`z') + if (b) /* scanning for start of change */ + err_print("! Where is the matching @@x?")(i); +@.Where is the match...@> +} + + +@ Here we are looking at lines following the \.{@@x}. + +@<Skip to the next nonblank line...@>= +do{ + get_line(i); + if (inp_desc->mode==ignore) { + err_print("! Change file ended after @@x")(i); +@.Change file ended...@> + return; + } +} while (inp_desc->limit<=0); + + +@ The |put_line| function is used to write a line from +input buffer |j| to the output file. + +@<Internal functions@>= +@h void put_line(j) + file_index j; +{buffer_index i; /* index into the buffer */ + buffer_index lmt; /* line length */ + string p; /* output pointer */ + lmt=input_organization[j]->limit; + p=input_organization[j]->buffer; + for (i=0;i<lmt;i++) fputc(map_xchr(*p++),out_file); + new_line(out_file); +} + + +@ The function |e_of_ch_module| returns true if the input +line from file |i| starts with \.{@@z}. + +@<Internal functions@>= +@h boolean e_of_ch_module(i) + file_index i; +{register input_description *inp_desc=input_organization[i]; + if (inp_desc->limit<0) { + print_nl("! At the end of change file missing @@z "); +@.At the end of change file...@> + print2("%s",input_organization[i]->name_of_file); + term_new_line; + return(true); + } else if (inp_desc->limit>=2) if (inp_desc->buffer[0]==@`@@' && + (inp_desc->buffer[1]==@`Z' || inp_desc->buffer[1]==@`z')) + return(true); + return(false); +} + + +@ The function |e_of_ch_preamble| returns |true| if the input +line from file |i| starts with \.{@@y}. + +@<Internal functions@>= +@h boolean e_of_ch_preamble(i) + file_index i; +{register input_description *inp_desc=input_organization[i]; + if (inp_desc->limit>=2 && inp_desc->buffer[0]==@`@@') + if (inp_desc->buffer[1]==@`Y'||inp_desc->buffer[1]==@`y') return(true); + return(false); +} + + + +@ To process the input file the next section +reads a line of the actual input file and updates the +|input_organization| for all files with index |test_file| greater +|actual_input|. + +@<Process a line, |break| when end of source reached@>= +{file_index test_file; + @<Check the current files for any ends of changes@> + if (input_has_ended && actual_input==0) break; /* all done */ + @<Scan all other files for changes to be done@> + @<Handle output@> + @<Step to next line@> +} + + +@ Any of the current change files may have reached the end of change. +In such a case intermediate lines must be skipped and the next start +of change is to be found. This may make a change file inactive if +it reaches end of file. + +@<Check the...@>= +{register input_description *inp_desc; +while (e_of_ch_module(actual_input)) { + inp_desc=input_organization[actual_input]; + if (inp_desc->type_of_file==master) { + /* emergency exit, everything mixed up!*/ + fatal_error("! This can't happen: change file is master file"); +@.This can't happen...@> + } + inp_desc->mode=search; + init_change_file(actual_input,true); + while ((input_organization[actual_input]->mode!=reading + && actual_input>0)) decr(actual_input); +} +} + + +@ Now we will set |test_input| to the file that has another match +for the current line. This depends on the state of the other +change files. If no other file matches, |actual_input| refers to +a line to write and |test_input| ist set to |none|. + +@d none = (max_file_index+1) + +@<Scan all other files...@>= +test_input=none; +test_file=actual_input; +while (test_input==none && test_file</*no\_ch*/no_ch-1) { /* bug fix DL */ + incr(test_file); + switch (input_organization[test_file]->mode) { + case search: if (lines_dont_match(actual_input,test_file)==false) { + input_organization[test_file]->mode=test; + test_input=test_file; + } + break; + case test: if (lines_dont_match(actual_input, test_file)==true) { + /* error, sections do not match */ + input_organization[test_file]->mode=search; + err_print("! Sections do not match")(actual_input); +@.Sections do not match@> + err_loc(test_file); + init_change_file(test_file,false); + } else test_input=test_file; + break; + case reading: do_nothing; /* this can't happen */ + break; + case ignore: do_nothing; /* nothing to do */ + break; + } +} + + +@ For the output we must distinguish whether we create a new change +file or a new master file. The change file creation needs some closer +inspection because we may be before a change, in the pattern part or +in the replacement part. For a master file we have to write the line +from the current actual input. + +@<Handle output@>= +if (prod_chf==chf) { + loop @+ { + @<Test for normal, |break| when done@> + @<Test for pre, |break| when done@> + @<Test for post, |break| when done@> + } +} else +if (test_input==none) put_line(actual_input); + + +@ Check whether we have to start a change file entry. +Without a match nothing must be done. + +@<Test for normal...@>= +if (out_mode==normal) { + if (test_input!=none) { + fputc(map_xchr(@`@@'),out_file); fputc(map_xchr(@`x'),out_file); + new_line(out_file); + out_mode=pre; + } else break; +} + + +@ Check whether we have to start the replacement text. +This is the case when we have no more matching line. +Otherwise the master file source line must be copied to the +change file. +@<Test for pre...@>= + + if (out_mode==pre) { + if (test_input==none) { + fputc(map_xchr(@`@@'),out_file); fputc(map_xchr(@`y'),out_file); + new_line(out_file); + out_mode=post; + } else { + if (input_organization[actual_input]->type_of_file==master) + put_line(actual_input); + break; + } + } + + +@ Check whether an entry from a change file is complete. +If the current change was a change for a change file in effect, +then this change file line must be written. +If the actual input has been reset to the master file we +can finish this change. + +@<Test for post...@>= + if (out_mode==post) { + if (input_organization[actual_input]->type_of_file==chf) { + if (test_input==none) put_line(actual_input); + break; + } else { + fputc(map_xchr(@`@@'),out_file); fputc(map_xchr(@`z'),out_file); + new_line(out_file); + new_line(out_file); + out_mode=normal; + } + } + + +@ If we had a change, we must proceed in the actual file +to be changed and in the change file in effect. + +@<Step to next line@>= +get_line(actual_input); +if (test_input!=none) { + get_line(test_input); + if (e_of_ch_preamble(test_input)==true) { + get_line(test_input); /* update current changing file */ + input_organization[test_input]->mode=reading; + actual_input=test_input; + test_input=none; + } +} + + +@ To create the new output file we have to scan the whole +master file and all changes in effect when it ends. +At the very end it is wise to check for all changes +to have completed--in case the last line of the master file +was to be changed. + +@<Process the input@>= +actual_input=0; +input_has_ended=false; +while (input_has_ended==false||actual_input!=0) + @<Process a line...@> +if (out_mode==post) { /* last line has been changed */ + fputc(map_xchr(@`@@'),out_file); fputc(map_xchr(@`z'),out_file); + new_line(out_file); + } + + +@ 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 the master file or any of the change files. + +@<Check that all changes have been read@>= +{file_index i; +for (i=1;i<no_ch;i++) {/* all change files */ + if (input_organization[i]->mode!=ignore) + err_print("! Change file entry did not match")(i); +@.Change file entry ...@> + } +} + + +@ We want to tell the user about our command line options. This is +done by the |usage()| function. It contains merely the necessary +print statement and exits afterwards. + +@<Intern...@>= +@h void usage() +{ + print("Usage: tie -[mc] outfile master changefile(s)"); + term_new_line; + jump_out(); +} + + +@ We must scan through the list of parameters, given in |argv|. The +number is in |argc|. We must pay attention to the flag parameter. We +need at least 5~parameters and can handle up to |max_file_index| +change files. The names fo the file parameters will be inserted into +the structure of |input_organization|. The first file is special. It +indicates the output file. When we allow flags at any position, we +must find out which name is for what purpose. The master file is +already part of the |input_organization| structure (index~0). As long +as the number of files found (counted in |no_ch|) is |-1| we have not +yet found the output file name. + +@<Scan the parameters@>= +{int act_arg,act_orgpart; + if ( argc < 5 || argc > max_file_index+4-1 ) usage(); + no_ch = -1; /* fill this part of |input_organization| */ + for ( act_arg=1 ; act_arg<argc ; act_arg++ ) { + if (argv[act_arg][0]=='-') @<Set a flag@> + else @<Get a file name@> + } + if (no_ch<=0|| prod_chf==unknown) usage(); +} + + +@ The flag is about to determine the processing mode. +We must make sure that this flag has not been set before. +Further flags might be introduced to avoid/force overwriting of +output files. +Currently we just have to set the processing flag properly. + +@<Set a flag@>= +if (prod_chf!=unknown) usage(); +else + switch (argv[act_arg][1]) { + case 'c': + case 'C': prod_chf=chf; break; + case 'm': + case 'M': prod_chf=master; break; + default: usage(); + } + + +@ We have to distinguish whether this is the very first file name +(known if |no_ch==(-1)|) or if the next element of |input_organization| +must be filled. + +@<Get a file name@>= +{ if (no_ch==(-1)) { + out_name=argv[act_arg]; + } else { register input_description *inp_desc; + inp_desc=(input_description *) + malloc(sizeof(input_description)); + if (inp_desc==NULL) + fatal_error("! No memory for descriptor"); +@.No memory for descriptor@> + inp_desc->mode=search; + inp_desc->line=0; + inp_desc->type_of_file=chf; + inp_desc->limit=0; + inp_desc->name_of_file=argv[act_arg]; + input_organization[no_ch]=inp_desc; + } + incr(no_ch); +} + + +@* The main program. + +\noindent Here is where \.{TIE} starts, and where it ends. + +@<The main function@>= +@h main(argc,argv) + int argc; string *argv; +{{@<Local variables for initialisation@> + @<Set initial...@> + } + print_ln(banner); /* print a ``banner line'' */ + print_ln(copyright); /* include the copyright notice */ + actual_input=0; + out_mode=normal; + @<Scan the parameters@> + @<Prepare the output file@> + @<Get the master file started@>; + @<Prepare the change files@> + @<Process the input@>; + @<Check that all changes have been read@>; + @<Print the job |history|@>; +} + +@ We want to pass the |history| value to the operating system so that +it can be used to govern whether or not other programs are started. +Additionaly we report the history to the user, although this may not +be ``{\mc UNIX}'' style---but we are in best companion: \.{WEB} and +\TeX{} do the same. +@^system dependencies@> + +@<Print the job |history|@>= +{string msg; + switch (history) { + case spotless: msg="No errors were found"; break; + case troublesome: msg="Pardon me, but I think I spotted something wrong."; + break; + case fatal: msg="That was a fatal error, my friend"; break; + } /* there are no other cases */ + print2_nl("(%s.)",msg); term_new_line; + exit ( history == spotless ? 0 : 1 ); +} + + + + + +@* System-dependent changes. + +\noindent This section should be replaced, if necessary, by +changes to the program that are necessary to make \.{TIE} +work at a particular installation. It is usually best to +design your change file so that all changes to previous +modules preserve the module numbering; then everybody's +version will be consistent with the printed program. More +extensive changes, which introduce new modules, can be +inserted here; then only the index itself will get a new +module number. +@^system dependencies@> + + + + + +@* Index. + +\noindent Here is the cross-reference table for the \.{TIE} +processor. + diff --git a/web/spiderweb/fixes-to-be-applied/latex/tiedoc.tex b/web/spiderweb/fixes-to-be-applied/latex/tiedoc.tex new file mode 100644 index 0000000000..525ae60b4e --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/tiedoc.tex @@ -0,0 +1,138 @@ +% tiedoc.tex 25 Oct 89 + +% adapted to CWEB by J.Schrod on 89-10-25 + +\documentstyle[a4]{article} +\font\mc=cmcsc10 +\def\TANGLE{{\tt TANGLE}} +\def\TIE{{\tt TIE}} +\def\WEAVE{{\tt WEAVE}} +\def\WEB{{\tt WEB}} +\def\CWEB{{\mc cweb}} +\def\PASCAL{{\mc Pascal}} +\title{The TIE Processor} +\author{Klaus Guntermann\\ +TH Darmstadt\\ +Fachbereich Informatik\\ +Institut f\"ur Theoretische Informatik} + +\date{October 1989} +\begin{document} +\maketitle +\section{Introduction} + +To install a program on a computer usually +system dependent changes are needed. +The \WEB\ system allows to describe these changes in a +so called change file. +To incorporate the changes into the program \TANGLE\ processes +the original source file and inserts the changes into the proper places. + +Sometimes it is good practice to develop a set of change files to be able to +distinguish between different changes like +program enhancements, bug fixes, system dependent changes +and output device dependent modifications. +Additionally this allows combinations of changes that can be used with a set of +programs that share some common features. + +The processors \TANGLE\ and \WEAVE\ can handle only one change file. +The combination of change files is done best in another preprocessing step. +\TIE\ is able to create either a new master file or a single change file that +comprises the effect of all change files. + +Since \TIE\ does not know anything about \WEB\ programs but only about the +structure of change files, it is possible to use this program for other +programming languages as well. +You just pretend that you want to create a new master file and \TIE\ will go +and insert all the changes from your change files. + + + +\section{Application} + +The current version of \TIE\ accepts a master file and up to 9 change files. +Because in general it is important to use the changes in their proper sequence +the order of the files must be chosen carefully. + +The CWEB version of \TIE{} may be called with the following command +line interface: +% +\begin{verbatim} + tie -[mc] output_file master_file changefile(s) +\end{verbatim} +% +The option \verb|-m| results in the creation of a new master file, +\verb|-c| yields a new changefile. Usually wildcards may be used for +the filenames. + +The multiple change files are used as if the single change files were merged +into the master files step by step. +Thus more than 9 change files might be incorporated by repeated application of +\TIE. + +Please note that even when multiple change files are processed each of the +files is read only once. +For each of the change files and for the master file there is only one line in +memory at a time (neglecting operating system buffering). +Thus the storage requirement of \TIE\ does not depend on the size of the change +files or the size of a single changed section. + +\vfill\eject +\def\eof{$\langle$EOF$\rangle$} +\section{Example} + +To illustrate the actions \TIE\ performs you may inspect the following example +that exercises some of the border line cases. + +$$\vbox{ +\halign{#\hfill\qquad\quad&#\hfill\qquad\quad&#\hfill\qquad\quad&#\hfill\cr +``master'' &{\tt CF1} &{\tt CF2} &{\tt CF3}\cr +line 1 &@x &@x &@x\cr +line 2 &line 2 &line 1 &changed line 4\cr +line 3 &line 3 &changed line 2 &@y\cr +line 4 &@y &changed line 3 &final line 4\cr +line 5 &changed line 2 &inserted line &@z\cr +line 6 &changed line 3 &line 4 &\eof\cr +line 7 &inserted line &@y\cr +line 8 &@z &final line 2\cr +line 9 & &final line 3\cr +line 10 &@x &changed line 4\cr +\eof &line 7 &@z\cr + &@y\cr + &changed line 7 &@x\cr + &@z &changed line 7\cr + &\eof &line 8\cr + & &@y\cr + & &final line 7\cr + & &final line 8\cr + & &@z\cr + & &\eof\cr} +}$$ +\vfill\eject +Using these input files and running \TIE\ twice to create a new master file +and a new change file will result in the following output files: + +$$\vbox{ +\halign{#\hfill\qquad\quad&&#\hfill\qquad\quad\cr +``master'' &``change''\cr +final line 2 &@x\cr +final line 3 &line 1\cr +final line 4 &line 2\cr +line 5 &line 3\cr +line 6 &line 4\cr +final line 7 &@y\cr +final line 8 &final line 2\cr +line 9 &final line 3\cr +line 10 &final line 4\cr +\eof &@z\cr + &\cr + &@x\cr + &line 7\cr + &line 8\cr + &@y\cr + &final line 7\cr + &final line 8\cr + &@z\cr + &\eof\cr} +}$$ +\end{document} diff --git a/web/spiderweb/fixes-to-be-applied/latex/weave.ltx b/web/spiderweb/fixes-to-be-applied/latex/weave.ltx new file mode 100644 index 0000000000..7b5454fee6 --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/weave.ltx @@ -0,0 +1,700 @@ +% This is `weave.ltx' to fix spidery weave for LaTeX. See +% `web.doc' for some comments about how it works. + +% changes copyright D.Love, SERC Daresbury Laboratory +% (d.love@daresbury.ac.uk) under the same conditions as the Spider +% distribution. + +%$Header: /home/users0/fx/ltxspiderweb/master/weave.ltx,v 1.4 91/03/22 11:24:35 fx Exp $ + + l 11 (remove \batchmode so we can see what's happening) +@x +% Here is TeX material that gets inserted after \input webmac + +\message{Entering \string\batchmode...} +\batchmode +@y +% Here is TeX material that gets inserted after \documentstyle[web]... + +% we turn off batch mode for debugging purposes + +%\message{Entering \string\batchmode...} +%\batchmode +@z + + l 16 (swicth for LaTeX or plain) +@x +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps +\def\cee{C} +\def\Pascal{Pascal} +\def\PASCAL{Ada} +\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 module names + +\def\title{Spidery WEAVE} +\def\contentspagenumber{1} % should be odd +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont Spidery WEAVE} processor} + \vfill} +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iftrue +@y +\ifx \enddocument\undefined % are we using LaTeX? + \font\ninerm=cmr9 % no... + \let\mc=\ninerm % medium caps + +\def\title{Spidery WEAVE} +\def\contentspagenumber{1} % should be odd +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont Spidery WEAVE} processor} + \vfill} + \pageno=\contentspagenumber \advance\pageno by 1 +\def\LaTeX{{\rm L\kern-.36em\raise.3ex\hbox{\sc a}\kern-.15em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}}% +\else % yes... + \documentstyle[web]{article} + \let\.=\str % new name + \title{Spidery WEAVE} \date{} +\fi + +\def\hang{\hangindent 3em\indent\ignorespaces} +\def\cee{C} +\def\Pascal{Pascal} +\def\PASCAL{Ada} +\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 module names + +\let\maybe=\iffalse % only changed sections -- perhaps you + % want to change this if you're + % weaving WEAVE for the first time + +@z + + l 39 +@x +@* Introduction. +\.{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, and finally it sorts and outputs the index. It can be compiled +with certain optional flags, |DEBUG| and |STAT|, the latter being used +to keep track of how much of \.{WEAVE}'s resources were actually used. +@y +@* Introduction. +\.{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, and finally it sorts and outputs the index. It can be compiled +with certain optional flags, |DEBUG| and |STAT|, the latter being used +to keep track of how much of \.{WEAVE}'s resources were actually used. + +This version has changes to make it work with \LaTeX{} as the +formatter, rather than plain \TeX\@@. The sections which are changed +for \LaTeX{} are indicated by |#ifdef LaTeX|, so you can define the +|LaTeX| switch when you compile it. You could generate a new +\.{weave.web} using \.{wmerge} or \.{tie} which you could use for +either plain or \LaTeX, since the limbo section will check for the +existence of \.{\\enddocument} (which presumably indicates \LaTeX). +@z + + l 361 +@x +@d underline = @'176 /* this code will be intercepted without confusion */ +@d param = @'177 /* ASCII delete will not appear */ +/* identifier =200 or octal @'310 */ +@#/* following three must be conseccutive for indexing to work */ +@d xref_roman = (identifier+roman) /* control code for `\.{@@\^}' */ +@y +@d underline = @'176 /* this code will be intercepted without confusion */ +@d param = @'177 /* ASCII delete will not appear */ +/* identifier =200 or octal |@'310| */ +@#/* following three must be consecutive for indexing to work */ +@d xref_roman = (identifier+roman) /* control code for `\.{@@\^}' */ +@z + + l 1140 +@x + for (k=p->byte_start; k<k_end; k++) { + if (*k=='$') {out('\\'); out('D'); out('O'); out(' ');} + else if (*k=='&') {out('\\'); out('a'); out('m'); out('p');} + else { + if (*k=='_' || *k=='%' || *k=='#' || *k=='^' || *k=='{' || *k=='}') +@y + for (k=p->byte_start; k<k_end; k++) { + if (*k=='$') {out('\\'); out('D'); out('O'); out(' ');} + else if (*k=='&') {out('\\'); out('a'); out('m'); out('p'); out(' ');} + else { + if (*k=='_' || *k=='%' || *k=='#' || *k=='^' || *k=='{' || *k=='}') +@z + + l 1159 +@x +No `\.{@@}' signs should occur in such material except in `\.{@@@@}' +pairs; such pairs are replaced by singletons. + +@u copy_limbo() +@y +No `\.{@@}' signs should occur in such material except in `\.{@@@@}' +pairs; such pairs are replaced by singletons. +For \LaTeX{} we have to introduce the start of the {\tt document} +environment.@^LaTeX{}@> + +@u copy_limbo() +@z + + l 1172 +@x + if (c!='z' && c!='Z') { + out(at_sign); + if (c!=at_sign) err_print("! Double @@ required outside of sections"); +@.Double \AT! required...@> + } + } + } +} +@y + if (c!='z' && c!='Z') { + out(at_sign); + if (c!=at_sign) err_print("! Double @@ required outside of sections"); +@.Double \AT! required...@> + } + } + } +#ifdef LaTeX + out_str("\n\\begin{document}\\maketitle\n"); +#endif LaTeX +} +@z + + l 1368 +@x +\.{\\mathrel\{} and \.{\\mathbin\{}, respectively. +Also |math_op| to \.{\\mathop\{}. +Other control sequences in the \TeX\ output will be `\.{\\\\\{}$\,\ldots\,$\.\}' +surrounding identifiers, `\.{\\\&\{}$\,\ldots\,$\.\}' surrounding +reserved words, `\.{\\.\{}$\,\ldots\,$\.\}' surrounding strings, +@y +\.{\\mathrel\{} and \.{\\mathbin\{}, respectively. +Also |math_op| to \.{\\mathop\{}. +Other control sequences in the plain \TeX\ output will be `\.{\\\\\{}$\,\ldots\,$\.\}' +surrounding identifiers, `\.{\\\&\{}$\,\ldots\,$\.\}' surrounding +reserved words, `\.{\\.\{}$\,\ldots\,$\.\}' surrounding strings, +@z + + l 1374 +@x +`\.{\\X$n$:}$\,\ldots\,$\.{\\X}' surrounding module names, where +|n| is the module number. + +@d math_bin = @'205 /* should these be octal or decimal? */ +@y +`\.{\\X$n$:}$\,\ldots\,$\.{\\X}' surrounding module names, where +|n| is the module number. +@^\LaTeX{}@> +In the \LaTeX\ output we'll have `\.{\\id\{}$\,\ldots\,$\.\}' +surrounding identifiers, `\.{\\res\{}$\,\ldots\,$\.\}' surrounding +reserved words, `\.{\\str\{}$\,\ldots\,$\.\}' surrounding strings, +`\.{\\cee\{}$\,\ldots\,$\.\}$\,$|force|' surrounding comments, and +`\.{\\X$n$:}$\,\ldots\,$\.{\\X}' surrounding module names, where +|n| is the module number. +@.\\id@>@.\\res@>@.\\str@> + +@d math_bin = @'205 /* should these be octal or decimal? */ +@z + + l 1472 +@x +\yskip\item{$\bullet$}ASCII 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$}|mod_flag+p| represents module 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. +@y +\begin{itemize} +\item ASCII codes and special codes like |force| and +|math_rel| represent themselves; + +\item |id_flag+p| represents \.{\\\\\{{\rm identifier $p$}\}} in the +plain \TeX\ version or \.{\\str\{{\rm identifier $p$}\}} in the \LaTeX\ +version; + +\item |res_flag+p| represents \.{\\\&\{{\rm identifier $p$}\}} in +plain or \.{\\id\{{\rm identifier $p$}\}}; + +\item |mod_flag+p| represents module name |p|; + +\item |tok_flag+p| represents token list number |p|; + +\item |inner_tok_flag+p| represents token list number |p|, to be +translated without line-break controls. +\end{itemize} +@z + + l 1501 +@x + else for (j=*p; j<*(p+1); j++) { + r=*j%id_flag; + switch (*j/id_flag) { + case 1: printf("\\{"); print_id((name_dir+r)); printf("}"); break; + /* |id_flag| */ +@y + else for (j=*p; j<*(p+1); j++) { + r=*j%id_flag; +#ifdef LaTeX + switch (*j/id_flag) { + case 1: printf("\id{"); print_id((name_dir+r)); printf("}"); break; + /* |id_flag| */ + case 2: printf("\res{"); print_id((name_dir+r)); printf("}"); break; + /* |res_flag| */ + case 3: printf("<"); print_id((name_dir+r)); printf(">"); break; + /* |mod_flag| */ + case 4: printf("[[%d]]",r); break; /* |tok_flag| */ + case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */ + default: @<Print token |r| in symbolic form@>; + } +@.\\id@>@.\\res@> +#else + switch (*j/id_flag) { + case 1: printf("\\{"); print_id((name_dir+r)); printf("}"); break; + /* |id_flag| */ +@z + + l 1512 +@x + default: @<Print token |r| in symbolic form@>; + } + } +} +@y + default: @<Print token |r| in symbolic form@>; + } +#endif LaTeX + } +} +@z + + l 2075 +@x + +@<Append a string or...@>= +if (next_control==constant) app_str("\\O{"); +@.\\O@> +@y + +@<Append a string or...@>= +#ifdef LaTeX +if (next_control==constant) app_str("\\const{"); +@.\\const@> +else if (next_control==string) app_str("\\str{"); +@.\\str@> +else app_str("\\vstr{"); +@.\\vstr@> +#else +if (next_control==constant) app_str("\\O{"); +@.\\O@> +@z + + l 2079 +@x +@.\\.@> +else app_str("\\={"); +@.\\=@> +while (id_first<id_loc) { + if (*id_first==at_sign) { +@y +@.\\.@> +else app_str("\\={"); +@.\\=@> /* verbatim string */ +#endif LaTeX +while (id_first<id_loc) { + if (*id_first==at_sign) { +@z + + l 2197 +@x +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\\P}'. + +@ The output process uses a stack to keep track of what is going on at +@y +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\\P}' (or `\.{\\Y\\code}' +with \LaTeX{}).@^\LaTeX@> + +@ The output process uses a stack to keep track of what is going on at +@z + + l 2394 +@x +looks slightly better if set in a math-italic font instead of a (slightly +narrower) text-italic font. Thus we output `\.{\\\char'174a}' but +`\.{\\\\\{aa\}}'. + +@<Output an identifier@>= +out('\\'); +if (a==identifier) + if (length(cur_name)==1) out('|')@; +@.\\|@> +@y +looks slightly better if set in a math-italic font instead of a (slightly +narrower) text-italic font. Thus we output `\.{\\\char'174a}' but +`\.{\\\\\{aa\}}'. In \LaTeX\ we use `\.{\\ida a}' and `\.{\\id\{aa\}}'. +@^\LaTeX{}@> + +@<Output an identifier@>= +#ifdef LaTeX +out('\\'); +if (a==identifier) + if (length(cur_name)==1) out_str("ida "); +@.\\ida@> + else out_str("id"); +@.\\id@> +else out_str("res"); /* |a==res_word| */ +@.\\res@> +#else +out('\\'); +if (a==identifier) + if (length(cur_name)==1) out('|')@; +@.\\|@> +@z + + l 2045 +@x +else out('&')@; /* |a==res_word| */ +@.\\\&@> +if (length(cur_name)==1) out((cur_name->byte_start)[0])@; +else out_name(cur_name); +@y +else out('&')@; /* |a==res_word| */ +@.\\\&@> +#endif LaTeX +if (length(cur_name)==1) out((cur_name->byte_start)[0])@; +else out_name(cur_name); +@z + + l 2430 +@x +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\\P}'). + +@<Look ahead for st...@>= { +@y +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\\code}'). +@^\LaTeX{}@> + +@<Look ahead for st...@>= { +@z + + l 2442 +@x + if ((a!=' ' && a<indent) || a==backup || a>big_force) { + if (save_mode==outer) { + if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\P",4)==0) + goto reswitch; + @<Output saved |indent| or |outdent| tokens@>; +@y + if ((a!=' ' && a<indent) || a==backup || a>big_force) { + if (save_mode==outer) { +#ifdef LaTeX + if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\code",4)==0)@^\LaTeX{}@>@.\\code@> +#else + if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\P",4)==0) +#endif LaTeX + goto reswitch; + @<Output saved |indent| or |outdent| tokens@>; +@z + + l 2632 +@x + +@ @<Translate an octal constant appearing in \TeX\ text@>= { +out_str("\\O{\\~"); + while ('0'<=*loc && *loc<'8') out(*loc++); +out('}'); +@y + +@ @<Translate an octal constant appearing in \TeX\ text@>= { +#ifdef LaTeX +out_str("\\code{\\~"); /* this occurrence of \.{\~} is OK for \LaTeX\ since +the control sequence is only defined within the scope of the \.{\\code} +macro */@^\LaTeX{}@>@.\\code@> +#else +out_str("\\O{\\~"); +#endif LaTeX + while ('0'<=*loc && *loc<'8') out(*loc++); +out('}'); +@z + + l 2638 +@x + +@ @<Translate a hex constant appearing in \TeX\ text@>= { +out_str("\\O{\\^"); + while (isxdigit(*loc)) { + out(islower(*loc) ? toupper(*loc):*loc); +@y + +@ @<Translate a hex constant appearing in \TeX\ text@>= { +#ifdef LaTeX +out_str("\\code{\\^"); /* OK for \LaTeX{} as above */ +@^\LaTeX{}@>@.\\code@> +#else +out_str("\\O{\\^"); +#endif LaTeX + while (isxdigit(*loc)) { + out(islower(*loc) ? toupper(*loc):*loc); +@z + + l 2662 +@x + +@ The |finish_C| procedure outputs the translation of the current +scraps, preceded by the control sequence `\.{\\P}' and followed by the +control sequence `\.{\\par}'. It also restores the token and scrap +memories to their initial empty state. +@y + +@ The |finish_C| procedure outputs the translation of the current +scraps, preceded by the control sequence `\.{\\P}' (`\.{\\code}' in +\LaTeX{}) and followed by the@^\LaTeX{}@> +control sequence `\.{\\par}'. It also restores the token and scrap +memories to their initial empty state. +@z + + l 2674 +@x +{ + text_pointer p; /* translation of the scraps */ + out_str("\\P"); app_tok(force); app_scrap(SP_ignore_scrap,no_math); + p=translate(); +@.\\P@> +@y +{ + text_pointer p; /* translation of the scraps */ +#ifdef LaTeX + out_str("\\code"); app_tok(force); app_scrap(SP_ignore_scrap,no_math); +@.\\code@>@^\LaTeX{}@> +#else + out_str("\\P"); app_tok(force); app_scrap(SP_ignore_scrap,no_math); +#endif LaTeX + p=translate(); +@.\\P@> +@z + + l 2710 +@x + token following the parameter list@>; + if (next_control==@`=') { + small_app('\\'); small_app('S'); /* equivalence sign */ + @<Set |next_control| to the first non-newline token@>@; + } else { +@y + token following the parameter list@>; + if (next_control==@`=') { +#ifdef LaTeX +@^\LaTeX{}@>@.\\equiv@> + small_app('\\'); app_str("equiv"); +#else + small_app('\\'); small_app('S'); /* equivalence sign */ +#endif LaTeX + @<Set |next_control| to the first non-newline token@>@; + } else { +@z + + l 2823 +@x + this_module=name_dir; /*so we won't give cross-reference info here*/ +} +app_str("\\S"); /* output an equivalence sign */ +@.\\S@> +app_str("{}$"); +small_app(force); +@y + this_module=name_dir; /*so we won't give cross-reference info here*/ +} +#ifdef LaTeX +app_str("\\equiv");@^\LaTeX{}@>@.\\equiv@> +#else +app_str("\\S"); /* output an equivalence sign */ +@.\\S@> +#endif LaTeX +app_str("{}$"); +small_app(force); +@z + + l 2950 +@x +if (no_xref) { + finish_line(); + out_str("\\vfill\\end"); + finish_line(); +} +@y +if (no_xref) { + finish_line(); +#ifdef LaTeX + out_str("\\end{document}");@^\LaTeX{}@>@.\\end{document}@> +#else + out_str("\\vfill\\end"); +#endif LaTeX + finish_line(); +} +@z + + l 2958 +@x + finish_line(); @<Tell about changed modules@>; + } + finish_line(); out_str("\\inx"); finish_line(); +@.\\inx@> + @<Do the first pass of sorting@>; + @<Sort and output the index@>; + out_str("\\fin"); finish_line(); +@.\\fin@> + @<Output all the module names@>; + out_str("\\con"); finish_line(); +@.\\con@> +} +@y + finish_line(); @<Tell about changed modules@>; + } +#if 0 + finish_line(); out_str("\\begin{theindex}"); finish_line(); +#endif + finish_line(); out_str("\\inx"); finish_line(); +@.\\inx@> + @<Do the first pass of sorting@>; + @<Sort and output the index@>; +#if 0 + out_str("\\end{theindex}\\fin"); finish_line(); +#endif + out_str("\\fin"); finish_line(); +@.\\fin@> + @<Output all the module names@>; + out_str("\\con\\end{document}"); finish_line(); +@.\\con@> +} +@z + + l 3137 +@x +@ @<Output the name...@>= +switch (cur_name->ilk) { + case normal: if (length(cur_name)==1) out_str("\\|"); + else out_str("\\\\"); break; +@y +@ @<Output the name...@>= +switch (cur_name->ilk) { +#ifdef LaTeX# + case normal: if (length(cur_name)==1) out_str("\\ida "); + else out_str("\\id"); break; +@^\LaTeX{}@>@.\\ida@>@.\\id@> +#else + case normal: if (length(cur_name)==1) out_str("\\|"); + else out_str("\\\\"); break; +@z + + l 3141 +@x +@.\\|@> +@.\\\\@> + case roman: break; + case wildcard: out_str("\\9"); break; +@.\\9@> + case typewriter: out_str("\\."); break; +@.\\.@> +@y +@.\\|@> +@.\\\\@> +#endif LaTeX + case roman: break; + case wildcard: out_str("\\9"); break; +@.\\9@> +#ifdef LaTeX + case typewriter: out_str("\\str"); break; +@.\\str@> + default: out_str("\\res"); +@.\\res@>@^\LaTeX{}@> +#else + case typewriter: out_str("\\."); break; +@.\\.@> +@z + + l 3148 +@x + default: out_str("\\&"); +@.\\\&@> +} +out_name(cur_name); +@y + default: out_str("\\&"); +@.\\\&@> +#endif LaTeX +} +out_name(cur_name); +@z + + l 3152 +@x + +@ Section numbers that are to be underlined are enclosed in +`\.{\\[}$\,\ldots\,$\.]'. + +@<Output the cross-references...@>= +@y + +@ Section numbers that are to be underlined are enclosed in +`\.{\\[}$\,\ldots\,$\.]' or `\.{\\underline}$\,\ldots\,$\.\}' in \LaTeX{}. +@^\LaTeX{}@> + +@<Output the cross-references...@>= +@z + + l 3159 +@x + out_str(", "); cur_val=cur_xref->num; + if (cur_val<def_flag) out_mod(cur_val); + else {out_str("\\["); out_mod(cur_val%def_flag); out(']');} +@.\\[@> + cur_xref=cur_xref->xlink; +} while (cur_xref!=xmem); +@y + out_str(", "); cur_val=cur_xref->num; + if (cur_val<def_flag) out_mod(cur_val); +#ifdef LaTeX + else {out_str("\\underline{"); out_mod(cur_val%def_flag); out('}');} +@.\\underline@>@^\LaTeX{}@> +#else + else {out_str("\\["); out_mod(cur_val%def_flag); out(']');} +@.\\[@> +#endif LaTeX + cur_xref=cur_xref->xlink; +} while (cur_xref!=xmem); +@z diff --git a/web/spiderweb/fixes-to-be-applied/latex/web.doc b/web/spiderweb/fixes-to-be-applied/latex/web.doc new file mode 100644 index 0000000000..e3e2615a4e --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/web.doc @@ -0,0 +1,945 @@ +\iffalse + +%% Copyright D.Love, SERC Daresbury Laboratory, 1991 +%% The `doc' version of this style is re-distributable and usuable +%% under conditions of the GNU copyleft, but please mark any changes, +%% list them here and report any major enhancements to the author. + +% This is a self-documenting style. To produce the documentation you +% might use a driver file like this: +% \def\webmacs{null} \documentstyle[a4,makeidx,newdoc,web]{article} +% \EnableCrossrefs \CodelineIndex +% \begin{document} \DocInput{web.sty} \PrintIndex +% \end{document} +% and run `makeindex -s gind.ist doc' in between passes. You need +% Mittelbach's newdoc.sty at v1.6d or later. + +% To produce the .sty file use `latex docstrip' to remove most of the +% comments. Please don't distribute the .sty file without the .doc +% file. +\fi + +\iffalse % hack RCS info into a sensible form: +\fi +\def\next$#1: #2/#3/#4 #5 ${\def\filedate{#4/#3/#2}\def\filetime{#5}} +\next$Date: 91/03/06 15:27:01 $ + +\def\next$#1: #2 ${\def\fileversion{#2}} +\next$Revision: 1.3 $ + +% \title{A a \web{} style file for \LaTeX{}\thanks{This file is version +% \fileversion\ of \filedate}} +% \author{David Love\\[2ex]{\it SERC Daresbury Laboratory, Warrington +% WA4 4AD, UK}\\ \tt d.love@daresbury.ac.uk} +% \date{} +% +% \newcommand{\web}{{\tt WEB}} +% \newcommand{\weave}{{\tt WEAVE}} +% \newcommand{\tangle}{{\tt tangle}} +% \newcommand{\spider}{Spider} +% \MakeShortVerb{\"} + +% \DoNotIndex{\/,\@date,\@ifundefined,\@makefnmark,\@starttoc} +% \DoNotIndex{\@topnum,\addpenalty,addvspace,\advance,aftergroup} +% \DoNotIndex{\begin,\begingroup,\bgroup,\char,\def,\egroup,\else,\end} +% \DoNotIndex{\endgroup,\fi,\fnsymbol,\hfil,\hfill,\hfilneg,\hss,\kern} +% \DoNotIndex{\let,\lineskip,\newcommand,\protect,\qquad,\quad,\relax} +% \DoNotIndex{\thanks,\thefootnote,\z@,\@M,\@thanks,\@thefnmark,\hbox} +% \DoNotIndex{\empty,\mbox} + +% \maketitle +% +% \begin{abstract} \noindent +% This style file is for use with a version of the Spidery \weave\ system +% that has been adapted to use \LaTeX\ rather than plain \TeX\ for the +% formatting. It is a first attempt. +% \end{abstract} +% +% \section{Assumptions of \weave{} and the {\tt .web} file} +% +% We assume we're using the version of Spidery \weave{} \cite{spider} +% changed for \LaTeX\@. This will write out +% \begin{quote}"\def\webmacs{"\meta{ext}"web.tex}",\end{quote} +% (where \meta{ext} is +% the \spider{} {\tt extension}), then the limbo section, then +% \begin{quote}"\begin{document}\maketitle" \end{quote} +% the latter to stop you forgetting it. The "\webmacs" file will be +% included at the end of this style. +% After the index (if any), we get +% "\end{document}". The user thus has to put the "\documentstyle" +% command in the limbo part and include "web" in the style options to +% get this stuff and can use other options as appropriate. You're +% meant to use the "article" main style, although I think "report" +% would work too. +% +% \section{Strategy} +% +% The idea was to change the original \spider{} \TeX{} stuff as little +% as possible, although it has actually been changed quite +% substantially. Changes are forced where there is a clash of macro +% names; most of the original one-character control sequences are +% already used by \LaTeX, for instance. Some features have been +% converted to a \LaTeX{} equivalent, +% notably the table of contents mechanism, the title page, running +% header and double-columning for the index. For safety, "\def"s have +% been replaced by "\newcommands" where possible since there are +% probably plenty of possibilities for name clashes. +% User-visible differences from the plain version are given in +% appendix~\ref{changes}. +% +% \section{Use with old webs} +% +% Examples of the use of this style with old webs using the plain +% conventions can be found in the accompanying changes files for +% {\tt weave.web} and {\tt spider.web}. You can use the limbo section +% to check whether the generated ".tex" file is being run through +% \LaTeX\ or plain \TeX\ by doing something like this: +% \begin{quote} +% \begin{verbatim} +% \ifx\enddocument\undefined +% % plain things +% \else +% % LaTeX things +% \fi +% \end{verbatim} +% \end{quote} +% +% \section{Bugs} +% +% Floats +% don't always come out where you'd expect due to interaction with +% \web's attempts to keep all of a module on one page if possible. +% "\str" and "\vstr", which +% might well get used in a moving argument, are +% fragile. Module titles (after "@*") are moving arguments. I think +% if you use \web's "|"\dots"|" construction in a +% moving argument it will break and there's not much you can do about +% it. +% +% \section{Code} +% \subsection{Preliminaries --- page layout} +% +% Let's announce ourselves as usual: +% \begin{macrocode} +\typeout{Sub-style `web', version \fileversion\space of \filedate} +% \end{macrocode} +% We don't want stretch between paragraphs. +% \begin{macrocode} +\parskip \z@ +% \end{macrocode} +% \begin{macro}{\textwidth}\begin{macro}{\textheight} +% \begin{macro}{\oddsidemargin} \begin{macro}{\evensidemargin} +% The default page width should be large for \web\@. This is for +% non-Americans (A4)---if you want to alter the page dimensions with a +% suitable style option put it {\em after\/} "web" in the +% "\documentstyle" list. The width here is too big for decently +% readable text, but is +% still less than the $6.5''$ of the original. Note that there's no +% point in trying to use "\marginpar" at +% this width since the margins have disappeared! The "twoside" option +% will work sensibly if you care to use it.\DescribeMacro{twoside} We +% want to avoid doing this when typesetting the documenttation, hence +% the test for "\DocInput". +% \begin{macrocode} +\ifx\DocInput\undefined +\ifcase \@ptsize + \textheight = 53 \baselineskip +\or + \textheight = 47 \baselineskip +\or + \textheight = 43 \baselineskip +\fi \advance \textheight by \topskip +\textwidth=6.27in \oddsidemargin=\z@ \evensidemargin=\z@ +\fi +% \end{macrocode} +% \end{macro}\end{macro}\end{macro}\end{macro} +% We use the "myheadings" page style with headings containing section +% information (see below). +% \begin{macrocode} +\pagestyle{myheadings} +% \end{macrocode} +% If we start off with a "\sectionmark" we won't miss the running +% header off the first page where it should appear. +% \begin{macrocode} +\ifx\DocInput\undefined \sectionmark{1} \fi +% \end{macrocode} +% +% \subsubsection{Font selection} +% +% \begin{macro}{\normal@font} +% We have to check whether we're in the old or new font selection scheme +% and set up appropriately. "\normal@font" is invoked before the font +% changes for identifiers, reserved words and strings to make sure +% that they use the default series and shape in the new scheme. This +% is actually only necessary if "\id", "\res" or "\str" is used in +% \TeX\ text that is being set in a different shape or series, not +% normally in the code. If you use the new selection scheme you can +% do things like using Concrete or PostScript fonts easily. +% \begin{macrocode} +\@ifundefined{selectfont}{% + \let\normal@font=\relax} % old scheme + {% new scheme + \def\normal@font{\series \mediumseriesdefault + \shape \normalshapedefault}} +% \end{macrocode} +% \end{macro} +% +% \subsection{Front matter} +% +% We depart from the plain version here. The first page (or pages, if +% the contents are very long) is produced with the "titlepage" +% environment. The "\author", "\date" and +% "\title" \DescribeMacro{\title} can be specified +% as usual in \LaTeX\@. Note that you now say +% "\title{"\meta{title}"}" rather than "\def\title{"\meta{title}"}" as +% in the plain version and this title will be used in the running +% header. +% +% \begin{macro}{\@maketitle} +% We'll re-define "\@maketitle" to include the "\topofcontents" and +% "\botofcontents" information, with the contents information in the +% middle. The normal title, author and date will be put automatically +% at the top---"\topofcontents" is extra. You get the titling and +% contents information automatically, since "\maketitle" is inserted +% by \weave{} immediately after "\begin{document}". If you want to +% suppress it, "\let\maketitle=\relax" in the limbo part. +% +% Of course, you have to make two +% passes to get the contents printed, unlike the original plain +% system. This should not be much hardship as one usually reckons on +% running \LaTeX{} at least twice. (Putting the titlepage at the back +% won't help, since the ".toc" file only exists after the ".aux" file +% has been read on the secind pass. One could change the standard +% behaviour so that the ".toc" file was created at the end of the +% first pass, I guess.) +% We first test for "\DocInput" as above to +% avoid messing things up when typesetting the documentation. +% \begin{macrocode} +\ifx\DocInput\undefined +\def\@maketitle{% + \newpage \thispagestyle{empty} \null + \begin{center} + {\LARGE \@title \par} \vskip 1.5em + {\large \lineskip .5em + \begin{tabular}[t]{c} \@author \end{tabular} \par} + \vskip 1em {\large \@date} + \end{center} + \par \vskip 1.5em + \topofcontents \tableofcontents \par \botofcontents \newpage } +\fi +% \end{macrocode} +% \end{macro} +% \begin{macro}{\maketitle} +% We change "\maketitle" to avoid the "\thispagestyle{plain}" that it +% otherwise contains, to set the page number to 1 at the end and to +% avoid losing the definitions of "\@title" and "\@author". +% ("\@title" is used in the running header.) +% \begin{macrocode} +\ifx\DocInput\undefined +\def\maketitle{% + \par \begingroup + \def\thefootnote{\fnsymbol{footnote}} + \def\@makefnmark{\hbox to \z@ {$^{\@thefnmark}$\hss}} + \if@twocolumn \twocolumn[\@maketitle] + \else \newpage \global\@topnum\z@ \@maketitle \fi + \@thanks + \endgroup + \setcounter{footnote}{0} \setcounter{page}{1} + \let\maketitle\relax \let\@maketitle\relax + \gdef\@thanks{}\let\thanks\relax} +\fi +% \end{macrocode} +% \end{macro} +% \begin{macro}{\@title} \begin{macro}{\@author} +% We better define these in case they're not supplied: +% \begin{macrocode} +\let\@title=\empty \let\@author=\empty +% \end{macrocode} +% \end{macro} \end{macro} +% \begin{macro}{\tableofcontents} +% "\tableofcontents" is re-defined to produce a header saying +% ``Section'' and ``Page'' a bit like the plain version, although the +% section number is at the left. +% \begin{macrocode} +\def\tableofcontents{% + \noindent Section \hfill Page \par \@starttoc{toc}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\topofcontents} \begin{macro}{\botofcontents} +% The "\topofcontents" material that comes between the title\slash author +% information and the contents list and the "\botofcontents" stuff +% that comes after the contents list are empty initially. I'm not +% sure it's worth preserving them. +% \begin{macrocode} +\def\topofcontents{} \def\botofcontents{} +% \end{macrocode} +% \end{macro} \end{macro} +% \begin{macro}{\ttitlefont} \begin{macro}{\titlefont} +% These are just for compatibility with the plain version---they +% should probably go. +% \begin{macrocode} +\let\ttitlefont=\tt \let\titlefont=\rm +% \end{macrocode} +% \end{macro} \end{macro} +% +% \subsection{Prettyprinting stuff} +% \subsubsection{Identifiers, reserved words and strings} +% +% \begin{macro}{\id}\begin{macro}{\ida}\begin{macro}{\idfont} +% Multi-letter identifiers are set by the macro "\id" in font "\idfont", +% which is italic by default i.e., \id{identifier}. +% One-letter identifiers are +% actually set by "\ida" in math italic as they are supposed to look +% better that way (\ida{a} rather than \id{a}). +% \begin{macrocode} +\newcommand{\id}[1]{\mbox{\idfont #1\/\kern.05em}} +\newcommand{\ida}[1]{\mbox{$ #1 $}} +\newcommand{\idfont}{\normal@font \it} +% \end{macrocode} +% \end{macro} \end{macro} \end{macro} +% \begin{macro}{\reservedfont}\begin{macro}{\res} +% Reserved words are set by macro "\res", using "\reservedfont" which +% is bold by default i.e., \res{reserved}. +% \begin{macrocode} +\newcommand{\reservedfont}{\normal@font \bf} +\newcommand{\res}[1]{\mbox{\reservedfont#1\/}} +% \end{macrocode} +% \end{macro}\end{macro} +% +% \begin{macro}{\str} +% Typewriter type is used for strings, set by "\str" i.e., +% \str{string}. The definitions of the escaped characters +% are given below. I don't understand why the ampersand is treated +% like this, since "\&" is defined anyway, but quotes and "^" are +% escaped to avoid +% ligatures.\footnote{{\tt \char`\^} and {\tt \char`\~} form ligatures +% in PostScript virtual fonts as well as "'".} It's necessary to do a +% "\def" of "\^" rather than just +% "\let\^\CF" to avoid an error with the use of "\^" not matching its +% definition. Note the use of "\@tempa" below rather than "\XX" as +% used in the same situation elsewhere---using "\XX", "\str" breaks if +% it is used in, say, a comment. +% \begin{macrocode} +\def\str#1{% + \ifmmode \gdef\@tempa{\null$\null}\else \gdef\@tempa{}\fi + \@tempa {% + \let\\=\BS \let\'=\RQ \let\`=\LQ \let\{=\LB \let\}=\RB + \let\~=\TL \let\ =\SP \let\&=\AM \def\^{{\tt \char`\^}}% + \leavevmode \normal@font\tt #1}\@tempa} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\AM} \begin{macro}{\BS} \begin{macro}{\LB} +% \begin{macro}{\LQ} \begin{macro}{\RB} \begin{macro}{\UL} +% \begin{macro}{\TL} +% Here are the definitions of the control sequences for strings. The +% plain version redefined "\#", "\$", "\%" and "\^" globally. "\$" +% isn't used by awk or C \web s, and has been removed. The others are +% done only in code, using "\startcodehook" (below). +% \begin{macrocode} +\chardef\AM=`\& % ampersand +\chardef\BS=`\\ % backslash +\chardef\LB=`\{ % left brace +\def\LQ{{\tt\char'22}} % left quote +\chardef\RB=`\} % right brace +\def\RQ{{\tt\char'23}} % right quote +\def\UL{{\tt\char`\_}} % underline character in a string +\def\TL{{\tt\char`\~}} % tilde +% \end{macrocode} +% \end{macro}\end{macro}\end{macro}\end{macro}\end{macro}\end{macro} +% \end{macro} +% \begin{macro}{\SP} +% Strings may be rather long and we want some way of breaking +% them, so +% "\SP" produces a visible space (\str{\SP}) and also adds a discretionary +% break afterwords. If a break occurs, the line is ended with a +% backslash. Spaces are probably the most sensible place to break +% strings, especially if they are messages, but one could consider +% doing the same thing for other of the macros above e.g., "\BS" might +% check if the next character was "n" and insert a discretionary break +% after that. +% \begin{macrocode} +\newcommand{\SP}{\char`\ \discretionary{\hbox{\char`\\}}{}{}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\vstr} +% This does a verbatim string (from "@=") using the existing \LaTeX +% nology rather than the original definition to put a frame around it +% (\vstr{string}). +% \begin{macrocode} +\newcommand{\vstr}[1]{\kern 2pt \fbox{\str{#1}}\kern 2pt} +\setlength{\fboxsep}{2pt} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\const} +% This looks after setting octal, hex or decimal constants. The first +% thing in its argument may be one of the control sequences in the +% example on the left, +% producing the result in the middle: +% \[\begin{tabular}{lll} +% "\const{\$10}" & $\const{\$10}$ & (long) \\ +% "\const{\_10}" & $\const{\_10}$ & (power of ten)\\ +% "\const{\~10}" & $\const{\~10}$ & (octal) \\ +% "\const{\^AB10}" & $\const{\^AB10}$ & (hex) \\ +% \end{tabular}\] +% \DeleteShortVerb{\"} +% \begin{macrocode} +\def\const#1{{% + \def\?{\kern.2em}% + \def\${\ell}% long + \def\_{\RealConstFormat{\aftergroup}}% power of ten + \def\~{\hbox{\rm \char'23\kern-.2em \it \aftergroup\?\aftergroup}}% octal +% \end{macrocode} +% The \verb+"+ here was originally \verb+\char'175+ which, +% unfortunately, is different in PostScript virtual fonts and Computer +% Modern: +% \begin{macrocode} + \def\^{\hbox{\rm "\tt \aftergroup}}% hex + #1}} % (\def{\const}) +% \end{macrocode} +% \end{macro} +% \MakeShortVerb{\"} +% \begin{macro}{\RealConstFormat} +% I prefer to re-define the decimal style +% to print as the more code-like `$\mbox{\rm e}10$'. You can +% do this by using the hook "\RealConstFormat" in your Spider "macros" +% section: +% \begin{quote} "\newcommand{\RealConstFormat}{\mbox{\rm e}}" .\end{quote} +% For a go at a Fortran web, I hacked the lexing so that an "e" or "d" in +% a real or double-precision constant was transmitted verbatim into the +% argument of "\const" instead of "\_" and re-defined "\const" to ensure +% this was set in roman. +% \begin{macrocode} +\newcommand{\RealConstFormat}{\cdot 10^} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Indentation and breaks} +% +% \begin{macro}{\ind} +% This counter stores the current indentation in ems. +% \begin{macrocode} +\newcount\ind +% \end{macrocode} +% \end{macro} +% \begin{macro}{\bak} \begin{macro}{\bakk} +% These backspace one and two ems respectively. +% \begin{macrocode} +\newbox\bak \setbox\bak=\hbox to \m@ne em{} +\newbox\bakk \setbox\bakk=\hbox to -2em{} +% \end{macrocode} +% \end{macro}\end{macro} +% \begin{macro}{\0} +% A forced break, as from "@/": +% \begin{macrocode} +\def\0{% + \ifmmode + \ifinner$\par\hangindent\ind em\noindent\kern\ind em\ignorespaces$\fi + \else + \par\hangindent\ind em\noindent \kern\ind em\ignorespaces + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\1} +% Indent one more notch: +% \begin{macrocode} +\newcommand{\1}{\global\advance\ind by 1 \hangindent\ind em} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\2} +% Indent one less notch: +% \begin{macrocode} +\newcommand{\2}{\global\advance\ind by \m@ne } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\3} +% An optional break within a statement, as from "@|": +% \begin{macrocode} +\newcommand{\3}[1]{\hfil \penalty#10 \hfilneg} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\4} +% Backspace one notch: +% \begin{macrocode} +\newcommand{\4}{\copy\bak} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\5} +% Optional break: +% \begin{macrocode} +\newcommand{\5}{\hfil \penalty \m@ne \hfilneg \kern 2.5em \copy\bakk + \ignorespaces} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\6} +% A forced break with no indentation: +% \begin{macrocode} +\def\6{\ifmmode \else \par + \hangindent\ind em\startline \ignorespaces \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\startline} +% This is used by "\code" as well as "\6" above. +% \begin{macrocode} +\def\startline{\noindent \count255=\ind \advance\count255 by -2 + \hskip\count255 em} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\7} +% A forced break and a little extra vertical space, as from "@#": +% \begin{macrocode} +\newcommand{\7}{\Y\6} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\8} +% No indentation. It works only in code, not in "|"\dots"|". +% \begin{macrocode} +\newcommand{\8}{\unskip} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\J} +% \tangle's join operation ("@&"): +% \begin{macrocode} +\newcommand{\J}{\str{@\&}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\C} +% This looks after comments. The hooks are inserted because comments +% aren't code (see below). +% \begin{macrocode} +\def\C#1{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi + \XX \hfil \penalty \m@ne\hfilneg\quad % original spider + $\commentbegin\,$\endcodehook{#1}\startcodehook$\, + \commentend$\XX} +% \end{macrocode} +% \end{macro} +% +% \subsection{Modules} +% +% \begin{macro}{\onmaybe} \begin{macro}{\maybe} \begin{macro}{\ifon} +% These switches are concerned with only printing changed sections if +% so desired. +% \begin{macrocode} +\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue \newif\ifon +% \end{macrocode} +% \end{macro}\end{macro}\end{macro} +% \begin{macro}{\M} +% Beginning of an un-starred section: +% \begin{macrocode} +\outer\def\M#1.{% + \MN#1.\ifon\vfil\penalty-100\vfilneg + \vskip12ptminus3pt \startsection \ignorespaces} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\startsection} \begin{macro}{\lapstar} +% Some auxilliary definitions: +% \begin{macrocode} +\def\startsection{\Q \noindent {\let\*=\lapstar \bf \modstar.\quad }} +\newcommand{\lapstar}{\rlap{*}} +% \end{macrocode} +% \end{macro} \end{macro} +% \begin{macro}{\N} +% This introduces a starred section (where "#2" is the title). We +% have to check the title with "\headcheck" for a leading +% character indicating a subsection. Then we write a contents entry, +% change the running header and set the title in bold. "\old@S" is +% used in the header rather than "\S" since "\S" is probably +% wrongly-defined at this point (see below). +% \begin{macrocode} +\outer\def\N#1.#2.{% + \MN#1.\headcheck#2\headcheck + \typeout{*\modno} % progress report + \addcontentsline{toc}{\headcheck@type} + {\hbox to 2em{\modno\hfill} \quad \theopen \relax \themodtitle} + \markboth{% running headline + {\protect\small \qquad\uppercase{\ignorespaces\themodtitle}} + \hfill {\protect\small \@title}\qquad{\rm \old@S \modno}} + {\rm \old@S \modno\qquad {\protect\small \@title}\hfill + {\protect\small \uppercase{\ignorespaces\themodtitle\qquad}}} + \ifon\startsection {\bf \ignorespaces \themodtitle.\quad }\ignorespaces} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\MN} +% Here is some common code for "\M" and "\N"\@. Like the normal \LaTeX{} +% "\section", it looks after setting a +% "\sectionmark" and advancing the section counter using +% "\refstepcounter" so that it can be cross-referenced as usual. It +% looks after the decision about whether or not to set this module if it +% is not starred. +% \begin{macrocode} +\def\MN#1.{% + \par {\xdef\modstar{#1}\let\*=\empty\xdef\modno{#1}}% + \ifx\modno\modstar \onmaybe \else \ontrue \fi + \sectionmark{\modno} \refstepcounter{section}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\note} \begin{macro}{\A} +% Auxilliary macros. "\A" is for cross-references for multiply +% defined section names. +% \begin{macrocode} +\def\note#1#2.{\Y \noindent {\hangindent 2em \footnotesize + \baselineskip 10pt#1 #2.\par}} +\newcommand{\A}{\note{See also}} +% \end{macrocode} +% \end{macro} \end{macro} +% +% \subsubsection{Processing special section headings} +% +% This complicated stuff, introduced with \spider{} and modified for the +% \LaTeX{} version, is to allow an inital =, 1, 2, 3 or 4 in +% starred module titles to indicate a hierarchy. Their effect is as follows: +% \[ \begin{tabular}{c|c|c} +% Introduction & Page eject? & Indentation in contents\\ \hline +% "@*=" & yes & 0 \\ +% "@*1" & yes & 2 em \\ +% "@*2" & no & 2 em \\ +% "@*3" & yes & 4 em \\ +% "@*4" & no & 4 em \\ +% \end{tabular} \] +% "@*=" also suppresses a following page eject and emboldens the +% table of contents entry and puts some extra vertical space before +% it. Normal starred sections have no indentation in the contents and +% don't do anything special about page breaks. +% +% \begin{macro}{\l@part} \begin{macro}{\l@norm} \begin{macro}{\l@num} +% Two new sorts of contents entry are defined here and the `part' +% type re-defined. (See "latex.tex" for details of how this works.) +% "\l@part" determines the t.o.c.\ entry for a "@*=" section, +% "\l@norm" the entry for a normal starred section and "\l@num" that +% for a numbered section. Some penalties are inserted (the normal +% values for the main style) in case the t.o.c.\ extends over more +% than one page. The "\headcheck@type" definition is used in the +% sectioning commands to write the t.o.c.\ entry. +% \begin{macrocode} +\def\l@part{\addpenalty{\@secpenalty} + \addvspace{3pt plus 1pt} % space above part line + \@dottedtocline{0}{\z@ }{4em}} +\def\l@norm{\addpenalty{\@secpenalty} + \@dottedtocline{0}{\z@ }{4em}} +\def\l@num{\@dottedtocline{0}{0em}{4em}} +% \end{macrocode} +% \end{macro}\end{macro}\end{macro} +% \begin{macro}{\ifcancel} \begin{macro}{\ifnextchar} +% \begin{macro}{\ifnch} \begin{macro}{\makethechar} +% Here's the tricky stuff, presented without further comment! +% \begin{macrocode} +\newif\ifcancel \cancelfalse +\def\ifnextchar#1#2#3{% + \let\@tempe=#1\def\@tempa{#2}\def\@tempb{#3}\@ifnch} +\def\@ifnch{% + \ifx \@tempc \@tempe\let\@tempd\@tempa + \else \let\@tempd\@tempb + \fi + \@tempd} +\def\makethechar#1{\let\@tempc=#1} +% \end{macrocode} +% \end{macro} \end{macro} \end{macro} \end{macro} +% \begin{macro}{\headcheck} +% ~ +% \begin{macrocode} +\def\headcheck#1#2\headcheck{% + \makethechar{#1}% + \def\theskipper{\vfil\penalty-100 % skip before new module + \vfilneg\vskip12ptminus3pt}% + \def\theopen{}% opening skip in toc entry + \def\thetocskip{}% vertical skip before toc entry + \def\themodtitle{{#2}}% + \def\headcheck@type{num}% + \ifnextchar={% + \def\theskipper{\newpage} \canceltrue + \def\headcheck@type{part} \def\theopen{\bf}% + \def\thetocskip{\vskip 3pt plus 1in \penalty-100 + \vskip \z@ plus -1in}% + }{\ifnextchar1{% + \cancelfalse \def\theskipper{\newpage}% + \def\theopen{\hskip2em}% + }{\ifnextchar2{% + \cancelfalse \def\theopen{\hskip2em}% + }{\ifnextchar3{% + \cancelfalse \def\theskipper{\newpage}% + \def\theopen{\hskip4em}% + }{\ifnextchar4{% + \cancelfalse \def\theopen{\hskip4em}% + }{% else + \ifcancel\else \def\theskipper{\newpage}\fi + \cancelfalse \def\headcheck@type{norm}% + \def\themodtitle{#1{#2}}% + }}}}}% + \theskipper } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Starting and ending code sections} +% +% \begin{macro}{\code} +% This takes us into code mode. The old version used infinite hyphen +% penalty which stopped the discretionary breaks in strings. Extra +% space is put after ";" with the "\sfcode". +% \begin{macrocode} +\newcommand{\code}{% + \rightskip=\z@ plus 100pt minus 10pt + \sfcode`;=3000 \pretolerance \@M + \hyphenpenalty 9999 \exhyphenpenalty \@M + \global\ind=2 \1 \startline +% \end{macrocode} +% \DescribeMacro{\@} +% The original says that every web must define "\?", where "?" is the +% at-sign. Since "\@" is used for end-of-sentence space in \LaTeX, we +% make sure this is only done in code mode. We need the old and new +% definitions, "\old@" and "\code@", between which to switch. +% \spider{} unfortunately uses "\S" instead of "\equiv" and the awk +% and C \web s assume that "\%" and "\#" translate to typewriter +% versions, so we have to define these properly in code mode too. +% \DescribeMacro{\startcodehook} \DescribeMacro{\endcodehook} +% For convenience, we define token registers +% "\startcodehook" and "\endcodehook" for this sort of purpose when we +% go into and out of code mode. These might be altered by the +% \spider\ description if appropriate. +% \begin{macrocode} + \startcodehook} % \def\code +% \end{macrocode} +% \end{macro} +% \begin{macro}{\old@}\begin{macro}{\code@}\begin{macro}{\old@S} +% \begin{macro}{\old@percent} \begin{macro}{\old@hash} +% Let's store the original definitions of these: +% \begin{macrocode} +\let\old@=\@ \let\old@S=\S \let\old@percent=\% +\let\old@hash=\# +% \end{macrocode} +% \end{macro}\end{macro}\end{macro}\end{macro}\end{macro} +% \begin{macro}{\code@}\begin{macro}{\tt@percent}\begin{macro}{\tt@hash} +% And here are replacements for use in code mode. +% \begin{macrocode} +\chardef\code@=`\@ +\def\tt@percent{\hbox{\tt\char`\%}} \def\tt@hash{\hbox{\tt\char`\#}} +% \end{macrocode} +% \end{macro}\end{macro}\end{macro} +% \begin{macro}{\startcodehook}\begin{macro}{\endcodehook} +% Here are the hooks. Should these be token registers? +% \begin{macrocode} +\def\startcodehook{\let\@=\code@ \let\S=\equiv \let\%=\tt@percent + \let\#=\tt@hash \def\^{\hbox{\tt\char`\^}}} +\def\endcodehook{\let\@=\old@ \let\S=\old@S \let\%=\old@percent + \let\#=\old@hash \def\^##1{{\accent94 ##1}}} +% \end{macrocode} +% \end{macro}\end{macro} +% \begin{macro}{\Q} +% This gets us out of code mode, setting things back to normal. +% \begin{macrocode} +\def\Q{\rightskip=\z@ \sfcode`;=1500 \pretolerance 200 + \endcodehook} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\CD} \begin{macro}{\DC} +% Web text in "|"\dots"|" is woven into text surrounded by +% "\CD"\dots"\DC"\@. The original definition didn't bother with the +% grouping if not in math mode, but it's convenient now that the hooks +% need to be added. +% \begin{macrocode} +\def\DC{\endcodehook \egroup} +\def\CD{\relax + \ifmmode \hbox\fi \bgroup \startcodehook} +% \end{macrocode} +% \end{macro}\end{macro} +% \begin{macro}{\U} +% This provides a cross-reference for uses of sections. +% \begin{macrocode} +\newcommand{\U}{\note{This code is used in}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\X} +% This does modules which introduce the code. Note the usage: +% "\X"\meta{module number}":"\meta{module name}"\X". +% \begin{macrocode} +\def\X#1:#2\X{% + \ifmmode \gdef\XX{\null$\null}\else \gdef\XX{}\fi + \XX$\langle\,$#2{\footnotesize \kern.5em #1}$\,\rangle$\XX } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\XF} +% This is for a file module (from "@("): +% \begin{macrocode} +\def\XF#1:#2\XF{% + \ifmmode \gdef\XX{\null$\null}\else \gdef\XX{}\fi + \XX {\tt (#2{\footnotesize \kern.5em #1})}\XX} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\Y} \begin{macro}{\yskip} +% This does a vertical skip by "\yskip", used in "\note" and "\7". +% \begin{macrocode} +\newcommand{\Y}{\par\yskip} +\let\yskip=\smallskip +% \end{macrocode} +% \end{macro}\end{macro} +% +% \subsection{Definitions and formats} +% +% \begin{macro}{\D} \begin{macro}{\F} \begin{macro}{\defin} +% "\D" and "\F" deal with macro and format definitions from "@d" and +% "@f" respectively. +% \begin{macrocode} +\newcommand{\D}{\defin{define}} % macro definition +\newcommand{\F}{\defin{format}} % format definition +\newcommand{\defin}[1]{\global\advance\ind by 2 \1\res{#1 }} +% \end{macrocode} +% \end{macro}\end{macro}\end{macro} +% +% \subsection{Miscellaneous symbols} +% +% \begin{macro}{\DO} \begin{macro}{\G} \begin{macro}{\I} +% \begin{macro}{\K} \begin{macro}{\L} \begin{macro}{\R} +% \begin{macro}{\TI} \begin{macro}{\V} \begin{macro}{\W} +% Here are some miscellaneous symbols. I think these should really be +% defined in the \spider\ descriptions that need them, but they are +% assumed by the current webs. +% \begin{macrocode} +\newcommand{\DO}{\hbox{\sl\char'044}} % slant dollar sign (used by awkweb) +\let\G=\ge % greater than or equal sign +\let\I=\ne % unequal sign +\let\K=\gets % left arrow +\let\L=\le % less than or equal sign +\let\R=\lnot % logical not +\let\TI=\sim % tilde +\let\V=\lor % logical or +\let\W=\land % logical and +% \end{macrocode} +% \end{macro}\end{macro}\end{macro}\end{macro}\end{macro}\end{macro} +% \end{macro}\end{macro}\end{macro} +% \begin{macro}{\vert} \begin{macro}{\amp} \begin{macro}{\PP} +% \begin{macro}{\*} +% And some more: (n.b., the plain \TeX{} definitions of "\vert" +% and "\*" are over-written, as expected by spidery \weave---maybe this +% should be changed). +% \begin{macrocode} +\def\vert{|} \let\amp=\& \let\PP=\P \let\*=* +% \end{macrocode} +% \end{macro}\end{macro}\end{macro}\end{macro} +% \begin{macro}{\AT} +% This is the `at sign in control +% text'. In the plain version it says "\def\AT!{@}" which I presume +% is a mistake. +% \begin{macrocode} +\def\AT{@} +% \end{macrocode} +% \end{macro} +% +% \subsection{Indexing} +% +% \begin{macro}{\ch} +% This is used trivially at the start of the index in the case of +% changes: +% \begin{macrocode} +\def\ch{\note{The following sections were changed by the change file:} + \let\*=\relax} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\inx} \begin{macro}{\:} +% The index is set in two-column mode. +% Each item in each index is introduced by "\:". This is a \LaTeX{} +% macro but is unlikely to get used in the index and so is preserved +% from the original. +% \begin{macrocode} +\def\inx{% + \typeout{Index:} + \begin{multicols}{2} + \parskip \z@ plus .5pt + \parfillskip \z@ plus .6\hsize % try to avoid almost empty lines + \outer\def\:##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry + \rm \tolerance \@M \let\*=\lapstar + \hyphenpenalty \@M \parindent=\z@ } +% \end{macrocode} +% \end{macro}\end{macro} +% \begin{macro}{\fin} +% This finishes off the name index and starts off the module index. +% "\:" acts as in "\inx". The modules may be +% qualified with "\U", which cross-references section uses. The page +% header is changed appropriately. +% \begin{macrocode} +\def\fin{% + \end{multicols} \newpage + \parfillskip \z@ plus 1fil + \markboth{{\protect\small NAMES OF THE SECTIONS}\hfill + {\protect\small\@title}} + {{\protect\small\@title}\hfill + {\protect\small NAMES OF THE SECTIONS}} + \typeout{Section names:} + \def\note##1##2.{\quad{\footnotesize##1 ##2.}} + \def\U{\note{Used in}}% + \def\:{\par\hangindent 2em}\let\*=*} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\con} +% This finishes everything off, rather trivially. (It used to make +% the contents page.) +% \begin{macrocode} +\newcommand{\con}{\end{document}} +% \end{macrocode} +% \end{macro} +% +% \subsection{Including other files} +% +% \DescribeEnv{multicols} +% We need the {\tt multicols} environment to make a two-column index +% without a forced page break. +% \begin{macrocode} +\input{multicol.sty} +% \end{macrocode} +% \DescribeMacro{\webmacs} +% Finally we include the macros defined by \spider. Doing things this way +% means that \spider{} can override things done in this file for the +% \web{} system of a particular language (like the +% definition of "\res", for instance) and the limbo section can do +% further overriding for a particular web file. If we're using this +% file to document itself, "\webmacs" should have been defined in the +% driver file to be "null"! +% \begin{macrocode} +\input{\webmacs} +% \end{macrocode} +% "\webmacs" is no further use and we might as well save the space. +% \begin{macrocode} +\let\webmacs=\empty +% \end{macrocode} +% +% \appendix +% \section{Changes from the plain version}\label{changes} +% +% \begin{description} +% \item[{\tt \BS.}] becomes "\str"; +% \item[{\tt \BS\char`\^}] has been removed from the global +% definitions (where it was assumed by the "c.spider" translation for +% "^") and put in limbo in "weave.ch"; +% \item[{\tt \BS\%}, {\tt \BS\#} and {\tt \BS\$}] also removed from global +% definitions and put in "\startcodehook"; +% \item[{\tt \BS AT!}] becomes "\AT" on the assumption that +% the original was an error; +% \item[{\tt \BS\char`\~}] removed globally since it doesn't seem to be used; +% \item[{\tt \BS\BS} and {\tt \BS|}] become "\id" and "\ida" respectively; +% \item[{\tt \BS\&}] becomes "\res"; +% \item[{\tt \BS B} and {\tt \BS T}] (for controlled comments) removed +% since no controlled comments in \spider; +% \item[{\tt \BS)}] (string pool check sum) removed; +% \item[{\tt \BS]}] (sign for forced line break) appears not be be +% used, so removed; +% \item[{\tt \BS=}] becomes "\vstr"; +% \item[{\tt \BS H}] (hat) removed since it seems not to be used and +% clashes with \LaTeX; +% \item[{\tt \BS Z}] replaced by \LaTeX{} contents stuff; +% \item[{\tt \BS lheader} and {\tt \BS rheader}] replaced by \LaTeX{} marks; +% \item[output routine stuff] all gone; +% \item[{\tt \BS rhead}] no longer relevant---use the \LaTeX{} mark +% mechanism; +% \item[{\tt \BS title}] should be called as a macro with the title as +% its argument rather than "\def"ed; +% \item[{\tt \BS contentspagenumber}, {\tt \BS contentsfile} and {\tt +% \BS readcontents}] no longer relevant; +% \item[{\tt \BS pagewidth}, {\tt \BS pageheight} and {\tt \BS +% fullpageheight}] no longer relevant---use the \LaTeX\ equivalents; +% \item[{\tt \BS pageshift}] no longer relevant---use "twoside" option; +% \item[verbatim macros] no longer relevant; +% \item[{\tt \BS iftitle}] removed---use "\pagestyle{empty}" to +% suppress page header. +% \end{description} +% +% \begin{thebibliography}{1} +% \bibitem{spider} N. Ramsey, {\sl Comm. ACM}, {\bf 32} (1989) 1051 +% \end{thebibliography} diff --git a/web/spiderweb/fixes-to-be-applied/latex/web.sty b/web/spiderweb/fixes-to-be-applied/latex/web.sty new file mode 100644 index 0000000000..d30acf397e --- /dev/null +++ b/web/spiderweb/fixes-to-be-applied/latex/web.sty @@ -0,0 +1,271 @@ +%% +%% This is file `web.sty' generated +%% on <1991/3/25> with the docstrip utility (v1.1k). +%% +%% The original source file was `web.doc'. +%% +%% You are not allowed to distribute this file without the corresponding +%% `.doc' version containing the documentation. +%% +\iffalse + +%% Copyright D.Love, SERC Daresbury Laboratory, 1991 +%% The `doc' version of this style is re-distributable and usuable +%% under conditions of the GNU copyleft, but please mark any changes, +%% list them here and report any major enhancements to the author. + + +\fi + +\iffalse % hack RCS info into a sensible form: +\fi +\def\next$#1: #2/#3/#4 #5 ${\def\filedate{#4/#3/#2}\def\filetime{#5}} +\next$Date: 91/03/06 15:27:01 $ + +\def\next$#1: #2 ${\def\fileversion{#2}} +\next$Revision: 1.3 $ + + + +\typeout{Sub-style `web', version \fileversion\space of \filedate} +\parskip \z@ +\ifx\DocInput\undefined +\ifcase \@ptsize + \textheight = 53 \baselineskip +\or + \textheight = 47 \baselineskip +\or + \textheight = 43 \baselineskip +\fi \advance \textheight by \topskip +\textwidth=6.27in \oddsidemargin=\z@ \evensidemargin=\z@ +\fi +\pagestyle{myheadings} +\ifx\DocInput\undefined \sectionmark{1} \fi +\@ifundefined{selectfont}{% + \let\normal@font=\relax} % old scheme + {% new scheme + \def\normal@font{\series \mediumseriesdefault + \shape \normalshapedefault}} +\ifx\DocInput\undefined +\def\@maketitle{% + \newpage \thispagestyle{empty} \null + \begin{center} + {\LARGE \@title \par} \vskip 1.5em + {\large \lineskip .5em + \begin{tabular}[t]{c} \@author \end{tabular} \par} + \vskip 1em {\large \@date} + \end{center} + \par \vskip 1.5em + \topofcontents \tableofcontents \par \botofcontents \newpage } +\fi +\ifx\DocInput\undefined +\def\maketitle{% + \par \begingroup + \def\thefootnote{\fnsymbol{footnote}} + \def\@makefnmark{\hbox to \z@ {$^{\@thefnmark}$\hss}} + \if@twocolumn \twocolumn[\@maketitle] + \else \newpage \global\@topnum\z@ \@maketitle \fi + \@thanks + \endgroup + \setcounter{footnote}{0} \setcounter{page}{1} + \let\maketitle\relax \let\@maketitle\relax + \gdef\@thanks{}\let\thanks\relax} +\fi +\let\@title=\empty \let\@author=\empty +\def\tableofcontents{% + \noindent Section \hfill Page \par \@starttoc{toc}} +\def\topofcontents{} \def\botofcontents{} +\let\ttitlefont=\tt \let\titlefont=\rm +\newcommand{\id}[1]{\mbox{\idfont #1\/\kern.05em}} +\newcommand{\ida}[1]{\mbox{$ #1 $}} +\newcommand{\idfont}{\normal@font \it} +\newcommand{\reservedfont}{\normal@font \bf} +\newcommand{\res}[1]{\mbox{\reservedfont#1\/}} +\def\str#1{% + \ifmmode \gdef\@tempa{\null$\null}\else \gdef\@tempa{}\fi + \@tempa {% + \let\\=\BS \let\'=\RQ \let\`=\LQ \let\{=\LB \let\}=\RB + \let\~=\TL \let\ =\SP \let\&=\AM \def\^{{\tt \char`\^}}% + \leavevmode \normal@font\tt #1}\@tempa} +\chardef\AM=`\& % ampersand +\chardef\BS=`\\ % backslash +\chardef\LB=`\{ % left brace +\def\LQ{{\tt\char'22}} % left quote +\chardef\RB=`\} % right brace +\def\RQ{{\tt\char'23}} % right quote +\def\UL{{\tt\char`\_}} % underline character in a string +\def\TL{{\tt\char`\~}} % tilde +\newcommand{\SP}{\char`\ \discretionary{\hbox{\char`\\}}{}{}} +\newcommand{\vstr}[1]{\kern 2pt \fbox{\str{#1}}\kern 2pt} +\setlength{\fboxsep}{2pt} +\def\const#1{{% + \def\?{\kern.2em}% + \def\${\ell}% long + \def\_{\RealConstFormat{\aftergroup}}% power of ten + \def\~{\hbox{\rm \char'23\kern-.2em \it \aftergroup\?\aftergroup}}% octal + \def\^{\hbox{\rm "\tt \aftergroup}}% hex + #1}} % (\def{\const}) +\newcommand{\RealConstFormat}{\cdot 10^} +\newcount\ind +\newbox\bak \setbox\bak=\hbox to \m@ne em{} +\newbox\bakk \setbox\bakk=\hbox to -2em{} +\def\0{% + \ifmmode + \ifinner$\par\hangindent\ind em\noindent\kern\ind em\ignorespaces$\fi + \else + \par\hangindent\ind em\noindent \kern\ind em\ignorespaces + \fi} +\newcommand{\1}{\global\advance\ind by 1 \hangindent\ind em} +\newcommand{\2}{\global\advance\ind by \m@ne } +\newcommand{\3}[1]{\hfil \penalty#10 \hfilneg} +\newcommand{\4}{\copy\bak} +\newcommand{\5}{\hfil \penalty \m@ne \hfilneg \kern 2.5em \copy\bakk + \ignorespaces} +\def\6{\ifmmode \else \par + \hangindent\ind em\startline \ignorespaces \fi} +\def\startline{\noindent \count255=\ind \advance\count255 by -2 + \hskip\count255 em} +\newcommand{\7}{\Y\6} +\newcommand{\8}{\unskip} +\newcommand{\J}{\str{@\&}} +\def\C#1{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi + \XX \hfil \penalty \m@ne\hfilneg\quad % original spider + $\commentbegin\,$\endcodehook{#1}\startcodehook$\, + \commentend$\XX} +\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue \newif\ifon +\outer\def\M#1.{% + \MN#1.\ifon\vfil\penalty-100\vfilneg + \vskip12ptminus3pt \startsection \ignorespaces} +\def\startsection{\Q \noindent {\let\*=\lapstar \bf \modstar.\quad }} +\newcommand{\lapstar}{\rlap{*}} +\outer\def\N#1.#2.{% + \MN#1.\headcheck#2\headcheck + \typeout{*\modno} % progress report + \addcontentsline{toc}{\headcheck@type} + {\hbox to 2em{\modno\hfill} \quad \theopen \relax \themodtitle} + \markboth{% running headline + {\protect\small \qquad\uppercase{\ignorespaces\themodtitle}} + \hfill {\protect\small \@title}\qquad{\rm \old@S \modno}} + {\rm \old@S \modno\qquad {\protect\small \@title}\hfill + {\protect\small \uppercase{\ignorespaces\themodtitle\qquad}}} + \ifon\startsection {\bf \ignorespaces \themodtitle.\quad }\ignorespaces} +\def\MN#1.{% + \par {\xdef\modstar{#1}\let\*=\empty\xdef\modno{#1}}% + \ifx\modno\modstar \onmaybe \else \ontrue \fi + \sectionmark{\modno} \refstepcounter{section}} +\def\note#1#2.{\Y \noindent {\hangindent 2em \footnotesize + \baselineskip 10pt#1 #2.\par}} +\newcommand{\A}{\note{See also}} +\def\l@part{\addpenalty{\@secpenalty} + \addvspace{3pt plus 1pt} % space above part line + \@dottedtocline{0}{\z@ }{4em}} +\def\l@norm{\addpenalty{\@secpenalty} + \@dottedtocline{0}{\z@ }{4em}} +\def\l@num{\@dottedtocline{0}{0em}{4em}} +\newif\ifcancel \cancelfalse +\def\ifnextchar#1#2#3{% + \let\@tempe=#1\def\@tempa{#2}\def\@tempb{#3}\@ifnch} +\def\@ifnch{% + \ifx \@tempc \@tempe\let\@tempd\@tempa + \else \let\@tempd\@tempb + \fi + \@tempd} +\def\makethechar#1{\let\@tempc=#1} +\def\headcheck#1#2\headcheck{% + \makethechar{#1}% + \def\theskipper{\vfil\penalty-100 % skip before new module + \vfilneg\vskip12ptminus3pt}% + \def\theopen{}% opening skip in toc entry + \def\thetocskip{}% vertical skip before toc entry + \def\themodtitle{{#2}}% + \def\headcheck@type{num}% + \ifnextchar={% + \def\theskipper{\newpage} \canceltrue + \def\headcheck@type{part} \def\theopen{\bf}% + \def\thetocskip{\vskip 3pt plus 1in \penalty-100 + \vskip \z@ plus -1in}% + }{\ifnextchar1{% + \cancelfalse \def\theskipper{\newpage}% + \def\theopen{\hskip2em}% + }{\ifnextchar2{% + \cancelfalse \def\theopen{\hskip2em}% + }{\ifnextchar3{% + \cancelfalse \def\theskipper{\newpage}% + \def\theopen{\hskip4em}% + }{\ifnextchar4{% + \cancelfalse \def\theopen{\hskip4em}% + }{% else + \ifcancel\else \def\theskipper{\newpage}\fi + \cancelfalse \def\headcheck@type{norm}% + \def\themodtitle{#1{#2}}% + }}}}}% + \theskipper } +\newcommand{\code}{% + \rightskip=\z@ plus 100pt minus 10pt + \sfcode`;=3000 \pretolerance \@M + \hyphenpenalty 9999 \exhyphenpenalty \@M + \global\ind=2 \1 \startline + \startcodehook} % \def\code +\let\old@=\@ \let\old@S=\S \let\old@percent=\% +\let\old@hash=\# +\chardef\code@=`\@ +\def\tt@percent{\hbox{\tt\char`\%}} \def\tt@hash{\hbox{\tt\char`\#}} +\def\startcodehook{\let\@=\code@ \let\S=\equiv \let\%=\tt@percent + \let\#=\tt@hash \def\^{\hbox{\tt\char`\^}}} +\def\endcodehook{\let\@=\old@ \let\S=\old@S \let\%=\old@percent + \let\#=\old@hash \def\^##1{{\accent94 ##1}}} +\def\Q{\rightskip=\z@ \sfcode`;=1500 \pretolerance 200 + \endcodehook} +\def\DC{\endcodehook \egroup} +\def\CD{\relax + \ifmmode \hbox\fi \bgroup \startcodehook} +\newcommand{\U}{\note{This code is used in}} +\def\X#1:#2\X{% + \ifmmode \gdef\XX{\null$\null}\else \gdef\XX{}\fi + \XX$\langle\,$#2{\footnotesize \kern.5em #1}$\,\rangle$\XX } +\def\XF#1:#2\XF{% + \ifmmode \gdef\XX{\null$\null}\else \gdef\XX{}\fi + \XX {\tt (#2{\footnotesize \kern.5em #1})}\XX} +\newcommand{\Y}{\par\yskip} +\let\yskip=\smallskip +\newcommand{\D}{\defin{define}} % macro definition +\newcommand{\F}{\defin{format}} % format definition +\newcommand{\defin}[1]{\global\advance\ind by 2 \1\res{#1 }} +\newcommand{\DO}{\hbox{\sl\char'044}} % slant dollar sign (used by awkweb) +\let\G=\ge % greater than or equal sign +\let\I=\ne % unequal sign +\let\K=\gets % left arrow +\let\L=\le % less than or equal sign +\let\R=\lnot % logical not +\let\TI=\sim % tilde +\let\V=\lor % logical or +\let\W=\land % logical and +\def\vert{|} \let\amp=\& \let\PP=\P \let\*=* +\def\AT{@} +\def\ch{\note{The following sections were changed by the change file:} + \let\*=\relax} +\def\inx{% + \typeout{Index:} + \begin{multicols}{2} + \parskip \z@ plus .5pt + \parfillskip \z@ plus .6\hsize % try to avoid almost empty lines + \outer\def\:##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry + \rm \tolerance \@M \let\*=\lapstar + \hyphenpenalty \@M \parindent=\z@ } +\def\fin{% + \end{multicols} \newpage + \parfillskip \z@ plus 1fil + \markboth{{\protect\small NAMES OF THE SECTIONS}\hfill + {\protect\small\@title}} + {{\protect\small\@title}\hfill + {\protect\small NAMES OF THE SECTIONS}} + \typeout{Section names:} + \def\note##1##2.{\quad{\footnotesize##1 ##2.}} + \def\U{\note{Used in}}% + \def\:{\par\hangindent 2em}\let\*=*} +\newcommand{\con}{\end{document}} +\input{multicol.sty} +\input{\webmacs} +\let\webmacs=\empty + +%% \endinput diff --git a/web/spiderweb/mac/MPW_SpiderWEB_21Mar93.sit.bin b/web/spiderweb/mac/MPW_SpiderWEB_21Mar93.sit.bin new file mode 100644 index 0000000000..89be0ccde1 --- /dev/null +++ b/web/spiderweb/mac/MPW_SpiderWEB_21Mar93.sit.bin @@ -0,0 +1,1796 @@ +MPW_SpiderWEB_21Mar93.sitSITDSIT!1?F€€P€€€S€€€B€SIT!1?rLau1 SpiderWEB €ourcG€ +€€€Q€€Q€ €UN!!untitled folder1Mar93.sit@€-d0€_€€€Q€€Qpɛ SpiderWEB€€UYf€€€€€€g€€Ce
I€K€€€ ada.unix(€€,_€€€€€€€€h€€j€H*€€€
+ada.spider€f +WfTEXTMPS €m5 +€m5 +!€€€€
€O€@€€lڹ€q€;2€zk€€€p€s€E€0<',€€s€ſ€€€n€€€€€€€O€€Z€€€€€€&€€€&€€9ٔ€*€e€#ϵ€€€€€/~€€€€€y€Nx€€€>€Ɵ'€€€€Dpí²gI€<€S€8€€b€€D€l€4€9$€t€€0s€|€Pi€d€€€RE€,€Me €€7€€ɋ€_z€€ +s-€€€R/Uzc€˩€0€W€€€HR€€WBG<€ş'€€,€3€€€€€€TD €d€€€€€7€€E€w€*?Ͼ€€H€ X€€)€>8€€€€O€€1€yr:€c&"€E€] #€€€€*1€7€€€€€€MS6€€˜p€€[c€€€€€€€€€€)K5€€€€€F{c€9€D€€9€€Iՙ€€€€5FC3r9€€€€€|>€e€€'€-€1s.AH€€€€<^€e1rʬ€8€€€$"€
€pE€zPu€€€'€?_fi€~/JX€€~Y€€H€s€q]€/{T€T߀q)€Xb€n€€fe€*e€€€€Nc€u€w€*N€€€G2€€l€€€=i€[€€:y€€<€&1€
€€€:€x<€€€€d€€€JV €€H€€€`€e€s€w\k€€€€€€€A€€vpqpp€€€€פ|=&€U€€€ۻ,€O€(l€OK€g€-€$`€€€|€a/{€h
[€p9|"€b€€,€à €€D€€oM.€€€€€;KX€€€>€^mPb€nm€€€8€€€€m€ZT €€/€A€v€Ih€€_޺€:S€0€€€€€B€€S&€3B€ 䙨€ Ia€Ç€€Dl€€V^€€l€V +€A)€n€Zs€p€X3 €€+€€€(€/€Z€[G€ބZ€€hU€€€€5€^€€€€€€€$A€€€X€d€€€€€cU€D`G€€Z9€€rÚ¨m€w€L€Po€/€q7€€!€y+€€€€
€€4€€€T€z&"€€Gr€֨Uj€€9€ h€oWG€c€I€LH€J€€|&:€€@€€G-~€€p€1€€€€€€8R&QWҬ߶€€Jib€t€€ۖ€n €m€
€€/[€€€5€€۽k€€€€ӷ€€<€gv€v5€vv€€€€\€€€i€J€€Շ€€€
€c€€ZK3m€€ê·Â€Â€\€€€i€€€S€€d€€€c€€&€<€ZLy€m(€i€Pe€€+€)^€@€€€i<c^K€€€€C€€;€€€€L`€Pk€€€[€ש*h{€,€7p€[€€PJ€€€֨€€€o€.€€€d43€b4m€€€]{€€c{€Z€€~L€ VQZ€d€.€
ٔ€ޣ€€STў€€€e€€'€€€Cl€€cX€€€€ʛ,€€V€€ +[E €0:;€€F€€€8Ei€I€ V€ {"€e€^OR€8U€€a€b€€<€pP€qo-€€dfѳz€B€E€€yby€6€€h0€,ZL€C€€€l€v4€r€€€€€U€€0@v€€€O€€€€ €€8`€€P€€€€5€€€.€*€€€s€€€dw€{mr|t€€i'€€5€=€8~€w€Jc^O€Si?€€4.^>€€€4삋€e€i€V€€€€k~P`€€€)€€€€€€^€€€(€I€€@G€p86Onz
iPv;€€€*€W€S€l€k&"k€CG€Ū0€ZV +€Z€La€'Ԙ€'#€€€f~V€t€€€ wLx€T嬙n€€Q€ڢ€4^TՖ€€[€€€€+€&€{€€eRUu€n€€Xf€€€€ €y€€8€I€€€q€€W€n€Y0€€€7q€€€D€€€"G?€yukw€s€€€€_€€}9@€€€€l€€€'8d@ΒҟC€€۶A_€,b€€vL€€€piO\€€R
€}|_€€€Q€q€€k€€5€Q€A{€€€€€€€€€W"€vS€€8€€P€E€X€[d€4€€€€ €€€JÝ€€€7F€ܯմP€:}€€:€p€]
€ +€VBcc]"€€7€-N€5€€€€,€€€:€€:€€Ӭ€€i€€K-|m€T€̈́€€€€€dd€Q€€n€€=/S€N€€€׷<.€kO}?^*€€€€_€€€€b=̪~€€^g}€ĵ€€F€€€,€€D€€€€n>#7€)€€€=Ğ{J€(€9,€€€tfC€€€€HE'€\€NzK€N€iL€L€7€*€€€€€c€€€:s€€<l€€bF€€=€€€u/€€€:€X榞€€׻€,_€€ޣp€€€+€g'€€K€€€€@Y€€€€
makespider€€€0fTEXTMPS €m5 €m5 €i€ÐQ€j*€€!€'€y€0€6p|€€€€ı):€Ò$€€€>€wtpuq€€€€€f}€€€€€ѥ€€€€€€n€efN€€€9€€€€€4€€`t€w=€€€>jK€€
+new.spider€€ +W€fTEXTMPS €m5 +€m5'( +I€~€)
N9y€Bo€M€R€€€q€€l€Jh7an€€€€&€€€€€€^€€€€u€s€$€G,pß Â€Â€Â€Â€y€u€mr€€~r€l2€d€€V€Iv€€{€€€€i€€€€€€€€€g€/-(€E€w€ǵ*€m5€€€€mo€€€)€@€€*)€€~Ì·i€}€€€€€^€XÅ>€€4€ꃚU€n€€o€€wvj€€ڣ€J€€R€€o€€€€€€B{) +€N€ش6€+€nW€WJk€JsI€g€€7€do^€~W€o[€€#k€j=€Q€,€ݪݿ€€nm€ 4Õ»UtesuW€€€€@1€€an>L~޺€`€V€€€€۬€p"o€Q€7€€ ok$O€€€€-%€fY&K€€{€€€ 컔€€€w!M€HH7j6€8l>€€€€<^€}€€!€>€€€U€O€$=Z€S€۵j€V€€€u+€€v€Z-€€€b1€€€Ο€6€8€w€€@;€0$a$€€q]Q܉z€€.€|€PA1€5€'€€a€W$5€€€2€€TH€}`€€€d~€€€€P%€!€0€9T€`€x€}€zG!€€G€*€€€ƒHO€€:€€€Kx%%€>€;Rr€A%пḣTS€X$$A$.€€€w€€€€צ€GB€lKJq€€€~€€€^€z€€€€~€& =\€hØ=W&M€€A€u€€iH}
€!€€€€€€Av"€€€.€€2€€€€€!ȳ€€wh€h:DUԟ€€M€€€̧€#€€Ò€6€iǼqv€C\€€€€€ €€#€.€U€l€€k.-€=$rC +€KW€7€Z€s€ä€}€ +€1€1€€U4€!€=ȋ€€€<€€ИÍ€΂IÉŠy€€€€^Ú‚c_€h€8€H9€€€+SU€€gË¥a€€-€KNGYZ€Ϩ€<c 1í·™Â€Â€y€€R€M€€e€€ed<€€€€€l€X€[˵ۀ,€€€€€n€€€€K€€€Ē€B€5€€`k€c€€<ycG/Ud@l€M€€€€L€€l€!€€€hzÌ€b€˽@€ '€w€y€€€OJ;i€€"3%€ufY€€v+€\+R>€ f €€€€S€F€9k€I€€€II€ €€5!{9'kN€^/Ț€€€.€P7€€5€bd€€€#J€€€€ +€€€+bKh€xeC€€6€€C€[A€$€9€-€u€€€U$$Cc9o;€€z€€/i]y€€KB€€ +X`€€"€€=֔€]vL€`€€0Ƀj€40Ä€€
€€d€€€ + +€QP€_ € P€.i€Б€8€ST€h€€€z€ª€€}€ח€€]€€Pp€V€݅€€€z,€€€€F1€qÔ€T,€&`€-€q€€U€€€€€€٠f€&?-€l€€€€F€€€€€€Q€ +fk8€h€xL€€ (€€GG€c€I"€€3€€|&:S€.€)€€€!€€jnj€€^€g\Mc€€D]@€Ŵ€€€€€!v[b>€x46€€c€ٺo Hϛ€=€ €€€뷒€€ԉ€€;(€€€T€€ؚ0T7aRi€J€7€,€€€}sia$Ì€€V€ѹ/€Oa€€€€€€€2IM€XpD€€€%€D€|€ +vT€X€€€€€V=€k€j€y =I$€€€€€W€J€&€€{ϺA~Ѱ€€€l};€A€€& +5O€As€ +€€€5€€pC€ZS6€dßµV€€€ը€.lR€+-€w>€€€€€ٔυF€k€€€.€E€W€2€5lw€ջ€e€鵬€€j€€UÞ¥"€€€€κط€F.x€€IK€€IQh€t.€€披ނ€€3€_€€%f€€Ø€€€[#Rn23€Y€€D€
€ςÏ€|€6€€€€hδ€,€€€Jkx1)>€hŖ€
€€PhRZNZ€€) +Հ€k.€€
€2n€€b€€€'€€€ueE/€$€U{€ú%€deezm€€{€f]V€€sy€€€Pb€€7m5€€s=€€€€a€€ܨx€€L€€a€5€ӧ€€h꽗O€€€CF€0J€n€€B€€€L`<€€?€€€€€]qV*-sr€€Q0-g€.€€-|O!?€SV5a€'€€2'Azi9€€e€€€U€€ġB€>ѷ +i€€Q#%€€€€'+
sV€;D€T€€ZR€€xZUK€_
€€€€€€€d€@€&ꀀNx:F€1€€/€D€y€*A€J€€*€€€€.€L9€€€4q€w#'€€"€€~M€€€€€€2€*€w€€%j:€!J€€€€`\€ €3€€Cz€}€6€€wc€€GNg€€c€2^q€UG€jh€€Çi{^5€€€€€€S€Ki€€R€?u€€€:#r8€€J€I€€€ա(€€j.€o€=€1f€F€€€=€"€€€B€€€€€ Px€0€O€€g€€cSt€€€H(d€HG€€€€€€€=€€V€b|€MN3&Ku€)"}€iFy€Oc€€K|g€€j€S>€€€[2€€ Í¡[&Ǽ'e*€)*=_€[€۱€V}?o*€€€€_€€€C€€€a€€Y\g€D€R€`"€8*€€€€J1€o€|6#t€€€€+I€€ɤ+P€€t€€Ig&€_€€€)€€C_'Hß’Lb€€S€€< +€;€6€€€€€y€€f€a€€€€€€+€/€|l/€€2€€l€€€]Yq€n|{€€˵€+€€€'€€€P_t€Y€k_~€€9t|8c€}"!A{+p€p€G€€.€€^€XM}€€>€€_ +)€^O}€€€€[€€€€€q€€e$€€N€€ߺ8"€€€€\-€]€Q}€ϸ€X€af€€k!€€Q7€zxȀڬ€€ߺ€<€€J€J€€€7€€€€
+old.spider*80fTEXTMPS €m5€m5€€€€ͯ€O€@€€pzɩqŸ€€€€G €€ӎ€€p€€€€X=€€P€€€€€€€ήo€'m€Uz€G€€€qr€ɀ€1#|%€ +d€€!€"K>:N€€|€
€ÉB€4"G4Tl€E€c€S€J€€€)%<N€€y*Ȁ€T1€€$2€ĩ€€b€€(€€B2€#€€4€"€"€12€#€€€€€€€€€€'€1#1€,J€€%€!€N@€QJG€€€€€ӄE +,€Sǡ€€G€€qB€€€€gCqm€€$L€€€>vO€€v6`#€€€€:€€?}€"€D€u€#€€ԓB€€€€rQqv€& €v€€yF€€htm€€€ek€_om€€8€€€ABI#`Ho€€€€Rd€rq€"€}p͇€I€A€F€€€€€€Ң4€$m€r̜€€€By€€€€LÆ‚N€€+€€€€b!€€€+€€*€€€=r%€€,K€=x€&€€}Z€H€sZs]€/€(`"€€Vv€€y,€L€Yz€€€ +Y +€J€n€€€€[k]'ݯ€€t[3€K€€/e;€u€€_&o>€€k]S€€P€€g€€€€€R6 €T€€6€!€a€X€€0)€B€€w€y€€J)^€6€€€€oW€€a€g€€€9o€€€bF€€@y€€YPw€€€;€€€€€ƿLm;X€zأ€[€f4€:`A>€€b€a€Ҝ!a€€&gHÓ»:€€N€Y€"€€s€€XAM€zrGb}€WC€{X€6F€€:€$:€t€€U€€˔
€qt€€€€€Ò€ €€ "_€€M€ +€€€€J€y,6€X +€Q€€w€€`%€€h)€€€RR€o€X3 (€s€)€Z€_*€€W€< +€Ik€€J+"€P(×—l€y€z€€o€<h' ℮€|Ä“U€|€J€J€(€€€€31Vj€F€_+ݦ€€g€z7€]€€€Z€W€€Ǖw€4€rS€€€€€€€[€€€G€€&€€]y€€€&€6o€€€g€€€
ly€€J-€u̺j€€1€€€€€@%&UͲ€€v€ +3€€€€€€Wr€€D€ +7€€}Úºp,€(\€€X€W0t€o5Ax€O€€mJ€€&l€AC€€€C}€&€€S€W€€€€oe-I€Y4oÕ¯ k€€@G€€€€€d€€zm€t€€€€Ä*Xq€<€M#€6k€]€€€e€€C€€2€Ϙ€€י%€€€€€;0€ތ`€PjOíª›Â€×™Â€Â€Â€Â€Y€o€€7i€W€9EJKT€G€:!"*€€Ȁ€€€€?€wmv€€€€jVe€1i€€€z7'€vQ€€€e€.5"c€€€Ƈ€vG<€€i€W€€€€€€0€MÛ¶L€Þ€€-k€-G!'€€-I#€€o€€€Ȳ
€% €€i€ja€b€€\€€Iˤ8€4Aެ€€€€̼g€<€@Vޓ€̿ݢ€€a'׀€1T€€€€kL;1€0€€€\€g€q€IȀB^€ē!€€€u€€)W$€€ €€€€€d}€yr€€€aw €€1€>e8|€€€€€\c€7€Cn?>97.€€€}€;€?€€a €€€€iF͞H8N^€H€z#w€P€€€j$JmJ1€5€€€€€€+€S€/ҳ€
€|3}@r€EO[05€€8xY€€ +€€d€€€R€T€lB€ |Ô€€€€ϪfN€€
€€ ω€9€€;U€€€€€h}€€€d€€h€€€€_.޳€€L볃€€&€€€€€€€
€€€['Nq€€Ce€€j€€€V€̙€г€€>H€€CS€€o5€f€.A€€QÖ€s€€€fC€KS€?08€ €€3U€s€}€/€೹E€€3U<€]Ú³Ó¯>j€€n€€7y_€g€!€€빲Do€m€v€€x€_€€€€h=!4€€€D€€€€ei€€€€<€€€1[lç«™O€€PcÔµ^h€M€ʴ€it>€(€€€€€€€€€€j€€€€d4€€Z€y;Cbvʆ1€BT€e€€CMqP)€ό볙p€sӂ€x€€Fi^€v€€€.[CÂ€ç¶ eq€Y€€€€€€&e€X€bZ/]€͢}€1/€€k€€$d€ާ%€€€@€€€*€fL€<a1€€€€7€"€€g€€a?€Q€=€€墛\#̧[`!€O€€'W€a€€Lx€ؾ€€€€€€o€€€v€G&€€€c€€7€€
+stacks.webGE€+€fTEXTMPS €m5 +€m5 +'€
}=€€
N)y€N€€0€GO€qr€赲MoS€€)€€€"€#\€{€€-€€€€€€€^€€O €€€7賳€/€€}€w€€M~€€€€€mF6€U=€€€zoF€€€g€ڦ€€.€€€€€3€?€d€n€€U€Yu€€€$ɋ€€N€€€tZlPLln&€€€€€€€[€€€u€w]€D€€ËA€hj€€€€{€€€€€€[€€€s€!€v4)t€%}€€ܴ€€€€€6q€€€€€Ð€€€€n4&ϳ€H\H€ّ€€M€m_? +€€L€P€\€Ã€€o€€c€€€€€€v€ib'€|[€t@/€9T€€ €l€W€€€y€€€€VO€€€€~k€€X€ܸ€€Y€V€i~[ͬ.€€p€€c€5!€®~j€n8€Y€7€€)€€^6€k€!€€Y +€€=€&€€€€€4€ +€€€T€€f2i€%*Y€€@mz€€€€€a€€U.^€€€J€1€\€b)L€€€N€€439d#cU/EW€Ir;€9€O€9-B+Tۊ€€K&€€0̰€€€$Ѧ€;€M€€SdQ€C€€€€'€z€.€EvNC€
€€m€€
€€ €€{€€€€rmJ
€€€€€0€}]€'I6€$€W€€G€I@€0€€
s€0WAKW€&i6€€)9€€€*€€€0MB€€€9€Q€r€B>€
€€<€ȸ׫€8€z€5€B€€y!UR€Œ€€€\€g€€R€€a€M€[:{1€€ѯ=€€€€q€€$€I|€€n%€K€€€D€€€€ ڃ€€bX[}€€€?€@?€@E6€€Y/q#6€GL€h€€;€€T€"T€PQ€1u€€C€4I€€F€I*N€9€r€A€/€€2€€rk +,K€N!W€€fqZU€OQF€#€,€A€Y:€€€H]€€ +,€€€€€r)€}K€&€€e€Z€dH +x4#€ +/BR€(2€ރ€€€w€X€€|€:HSNn€€ ZnE▽,K€Ia€€€€€I€S:€€€1€€E#€zBb€Q€€Ԅ"7€€€€€€݃:€%€1[m€€
;€€;€n€hÛº@y€O€€};%e1€V=€€€N€a€T€B3(€€€€(4€€€€Â]€€€2M€€€x€€o?€\0€6€€?`€€r€€€Ok€+9€,t€T€X€€€€X€€^c秨€€<L]Å<€m€cP€€'€,€6€9M€[€UZ€x+MW€€/$€€FR€€€€€N€Wm€€€€€€?€h €8€@)€(i€x€€A/€F€ËA€€X=€f€€l€€í£@8€/<×» :€?(€€€€e€'€R€€€
€g**€€4ۋ€Bm%cPQ€€€>€K€^QiU3o?€€€€€G€?,€G€؎U|€€€-Y€€jɦ|€€€€€cj€8t*Z€€€€€:M3q€€€€€8UcB€€Èu€€O€I€-€ € €€{€€€€ €€€€Q€€"€€€J€€€9€߾€q-V€€?€€y€&€€€i€AZ€//{€ +e1,€€€)E€֓|d~€ +P!&€DR€g5[Oj€€€€€^€€
^€5€Z€W€€€*€2 €€$v€:dgc€({=€€€E&W(\€R€ +YT€€€€€YE€€Lb@,A€€€€€€2]€€€€ß€€-€€*C
b;€€b€g€h€€€{j(#€-€€€}gY€€€€#€;€FR85U€€q€ 52j7€2€gQo{H:€J€€€Ǥ€f€tLT€3€v€€€$;€€.7B€€€€X€€Z€€2€VI€€*P€H,S €€^€€€€P?^ €u€S€€.L€€€f€€€/€€€Щ€€w€B€ Z€bw=P=;ri|€€Z€RS€€€€€ci€€€l?€\ ޅ"m€=€€dog€€8 ++€XE€.eQ€€A€€2A^€€€€€#€(#H&€\€€€,€€u€€€€ID€
€€€€€z€€€W€€8+C^€€€L€`€€l]€€€€€€ €PP=€ =€€,..^€€i€€k€€)~C€€€ݻ€ʇl€€€n'&€€'2€q;Q€€€+N*Q€€€€ €€€e€j€]€lw€7€€€8€€€€€le€€O€kZ€%L:€€1.Gz€P€€€€€ T€€Cq€|€DZ-€€€€51€:€€€@3K#€ט€€<€އM_€T€*.€Η8|fF€€€5€€€€@€Ā€€€€€`€€:Nn])€€€s/€€€€€-ky€NZ€Ŕ€ز€,v@^`€r€7&t€€€€€N€E€€>€€c€€
€I€€€€€B€€l(r€o€(€'€€€4€€H€€/\Ԕ€€@€/€$€€3eT€;€e€*€€`€Ǒ€+#€€€€€€€€E€@ozЛrRy"€€€x€"€y€u€€w+€€€€)1v€d€€6ƒ€€clMK€y€€gÌ)€}t]x€€n€8M€N€€€Y€k€€€€k^
M€€32}€€€ <*€4€€~€€;€€€ߞo€€]€|€€~€j€€€a€}€€oZpm€'€6€€,{0/€€ι€€Y€V +x{€<€g€ +€p€€€€?€€€a#€€€Gi +€*€1€€{€c€€£€z=€ +p€"€€q€3Bè€.€€X€ D/e€ IU⤇€suBG€n€'H*w€Ԝ&€js€{€€NϺ)$€+@U*2b5CÌ€JZ€{€€r€RJÏ€€T€€€|s€:B9€€€€X€z{€%c€€1€€€V)€€?Y€[€}kW€˷ZhT€'€1€€;€€Uq€K€,I€€€€U€€hx-€-€6€,€|h€5€'P>€Q€€€€€=[M€€']P:2o€€€G}v21hD€J€€~€€@€pA€م€€7€€0E*%€€€€€€E$t€< +€A€€(#b€M€€/ €€€P=€€€˜€ +E€€5€€€q
W%€w€<€€-€r€m€=13Oa€'€€|-€*€€€t€dD3>€qܸ€hd`EHȅ€J€€€€.q€€~€€xKv€@€€€0€Û€4€o@€€€€€€I€i€€€d€€€!h€n€€€€€€2€"€€€€X€(€⥪a€€A€€J€€ƣ€€(F€D4€/KU€€Q$€rH€W€0€c€V€€Jf.€E€{s€QP€€€€ +DO,€q'€€(x€lgÜ€€`n€€€€k€_€€€€1€€X€€(t%(€/|D€€€€AL€^?€€c€i€€G8€€N€€Ւ€€€€€>P€#twÉ„%"L€€€€g€€'€+€€€~]€>€€€u^€€L@.2€߶;F€Z\€€€d€€ϫ€S[8€€u€€v€J€W€7€€€€€ˈ~#€€€€€:€p€€€€€Bh€!€€€QG/€t
€q$"€€=€€Y€€s€[K€=€FzP€R€€€9€€E)y€€މU€TX€€€h€€z€R€G€S€C€€Ԯ_TR +Hé¿‹Z€€K€!€€€R€€€€F€3€€oÑ–8€€€*i€+€€hWW~€€1 +€ǽ€$€€€€Ï^€^€€P߀€A€Bd~€€€9€%€Y€€(Y9GR€4€#Us€€€€F€€€E^/€j€€H€2€6t2€€€1t$€€l€€ €€Ȍ€(€JL€Z€&€€€20c~;v€€€€ +€-€€e o€m€€€S€€€
€N€€u€€ƚ€€w€Z,€#€€ԑ€7n֦q€€Vg€n€€n€€€€€€S€€S€5€€€t€€€ +,-p€v€g"`€€z€#2€;€€1M€2/I€€#P-€€!€5T€Qn&ҫ€€IlwN]€€6€€€€€4€h€!! SpiderWEB €ourcG€ +f€€€Q€€Q€H*€6€ ansic{d.€€fAE€,€€€€€€CC€€€C€9€v€*
c.spider Files€Y,_<E,_@TEXTMPS €CC€€Z€44E
€ή€8€€€CW€p€r€[€€€€€€€€€€(€:€€j€r€€2€€0€q>-€g€b€Zj2€€€€Z€~
€n'k F%€€€€€q2€€€t€z{€€d€AL€ք1.1II€QۄÌ8€2€€€€€€€€4€€2€fJ€³€Î€€€8JE.2h€€€€€€L€+€€^€Shf&L2€€N€€u€€|€€q€zJ=€iY&&€V1€!€Qu€€€€-€(s€€=*€"€€€J€c€€#€`€Q3x€%€~€H +€"
r:€€€€€ O€Y€}€.€P€I€€@ÙLy€€t€€€tH €€€(€€€€Øs€b€€J€€€€m€hÇ€€ݧ€
N9€€'€`?o€€"<2€€€m ۞O6€€dK6ax%x€€/€€t€€€€{€6A?Z€€]€
€k`O8€€~InKn€}€€€ߔlJ€
:€V€5gqP€w€€}€7€T6€R€4€r€!w€9>€€2€Q€€€\uâ¨y€*€)€'E€ˮ€€Ld€dTf#€€\€4€€#€€*€"N€3€€X€"€R€€D€;€€€€€€€€€/€€€(€i!€q&;€€€A€€2€€J€€€€ :A€y€OÂ€ï‚ Â€Â€C"Ý“}€€Z€€€€#d€ŧ€+;AЕ€€L +QdQ€'€€€€#`€ €y.€€4(Ô¾LE܅€€€Lt€u€<€2€J€€^€C€<€ €S€€,€q
€1€i€ώ!€€€€€\€€€€%€Jf2€>'€€€[b€0qkx^^-€:€€+S€€ũh€5t€:€b€~€€,0ȉ,€€€GQG€W0€€€[€€Tq ê¾”x +qc€Ȼ€€uUa@[€€€€s€€I€€ħ€϶瑟€Q2€€AJd€€€L€\\€^ik'_€€€67O\€€lrC€€€c@€€€wC€€p€?]€?€yND=€€W€€K€k€€2'€a{g€€ι€€%€jM€€€R]y3!€€;€€Jm€€M>X:€€myZ5€€€5€€$€3€€€;{€€€€j€di€d€€€0*ǵ+€pII€€€g€6*€€€9€F€r>€j€€Aݬ$n€€7Q€h€€<q€€M68€z€€q]€^€€€^€€€#€€\;G\wϹ€€€>>€€zu€€€€€.€€x€€F€XLÉ…a;Gdw/ȶ€€€€bl67€\";€€@Fݥ€IRd€€T€!;&€;w&!H€€€€€€€C€€€n[€G€€C=y€(€u'ׯ;T€u€q=|€€€m€€€ڞ€€G€€€€€l'€€cqx€Vxe€€€U€€(/€€€€€€W€JH€€€L€pä€+€ԡ0{€0Af€@€)€€€o€€€€b1€w2 €€€_V€€Lr€vx;€ņ€€Vzc€€(o;€nD> Å¡](`Λ€6€€€A€€c
€r7€€€€€ €Ui^€€g€j}G3€€/|€€€€ €Eɳ€€:{sd€€84]s €"gn€Ҹ<€€T5b|€€€€€b€A\t€i|1I€€€€€. +€ €^/{€€/*€y4€€€{€W0
€{0A.€€k'€€€€€€qZ^€€€€€K3€5€€CS€€Z €€E€€J`€]€j€.>€€<C€x€t/Q€xDM€k€o<€€€€€€Xo€ +€€€€N4€3€(€;Qr€^€€€S€€€€(€€GV€€y€€€v€€j{V€{€s!€€'€€€Z€€€d€_€ov€&€€€g(SZ€KT€€€b-p€x +=Pu>|4€€€(zQ€€€2(€€%€€,€€€>€€>€s€€h€€Fk€€[€QB€€€V€L;:`€€€M€€€€€€u€€€€€€€€+€€Uы€€%\@€€€€€w€y'€Fh€v€€€@€n€F€€
€€L9€€^J€йbU`<€Q€sE€_€€?€€Ç€=€/€€€€€€€€€8Q€€*€cZ€4)€&€€$P€€Rf€€fW~€€n`#€€Q€€4€€A:z€D€6€€2Ñž*ZN@€h€€€€€o€€)aÖ¸[#€J?DK€9S€€€€€€€€pK€€€€€€Z!€p€€€B`€€,inm +€€
a€€€€*$A€u€€4,[€p +k€€€€E
€€€UӤz€€i€€9k€Y€€K€n)€€O€€
F€€€1€€&€€Գ€€€€J€*s€ +$c€M€€b€€€]g€
>€p-€]€
€€-€i|€€R +Z€€3€€€€k€€€?€g€to€€w<€€€€w0€€€-€€€€Ä*€5€€€4H€(€V€€€ +€8€€€€(€€€S€"€€€B€G8€p€€[€z€nj€^€€j.l€€̞!X€tXI€͓€+€€€]€|€yH€€€Z€sÒµA€mC€€€G€ygD€€\€€€€@O€^@3{€҈$v=6ZAE€BjA€GÐ…/€gȃ€€€€~€€}€€,#7€€-N€€#€€€Lw8€€շt€€nb€€€=€Y)1€8€€€3N€€€€~€\b€ͺ€?€~24/3€€€€€€0€,€R€1OH€€:R€i€€=€€P€€€€D<D€€€V€€A]€L€€T€m?<z€h]€P0:J#Ò±*€a€€JKw€€€€W€+-g˔€€€㖆_u€€€€UpY€€/U-€€߼n€˿e\j €B€€X€€€B€€€P€)€sު€€:€€€€f +€ԥ3€#€R€€V +€J€D€€cHw€€€9K^€€k€*€€#€€ȳ.E€€Xf€ڑ€€€€BӴ€Yå´®i€DÏ…&€7l€€€݆X€mu€€48fD$€€€g-8phV€I€€G-
P_ERL€f^{€€`#։€>€€€Hh€€Ô€˥€J>#9Y€6€'S€b€T߰€€€€€|F€€GM€]€އ€€]€Dl?W€€€;G€€€_€ϒ€q€€€z€/€.€€T€€€G€€N"€€~€f€Ly
€>֨-$I=$€R€€€~.oU&€5€
/*V€n€€€_,,€€€GR€P€€€n€=r€€D1€€€€-€yuv€€?\}zÛ˜b€€€Ð€A8€|€շ€€?€ë Cw!€Ka€:€€8€$%€€€€ʖ=tÈDc€€€1
<€#€€sm€c€€fo€&3€c(I€€€c;ޜQ€€γ€€€4{€f"€€ϣs€€€€,j:€€€€hc€-ȋ€€-€㈋€W€/D€€€€€€€€€€9 €€€rɀX€€€ݹk€€€"€€€O€€€A€)J€q€€H€u€J$Y*€€€eשԓެ
-ҹ0€-€€'€n€B€%€€2€€)?܌€Pؒ€F7€[€€€uIsd-€?U€ϓ€jla€˻€€\.€€R€q9i€.€r€€€€€€L€€@€%//ؙ€+(€Uk€2€wS€€s/€€€LeQM€r€€€€+KSɃ€€k€f*€€€&€U4w€€_5I€€4Ɍ;W€€ܰյ€Ϭ€r€U€v€c)J€[7€€€€€4݆€ F€p'2€E)9€€€€€€E€€€b€€€P€€€€@€
€€6€€€€ވ€R*€€€€€uQuu€€o€,<€€€€€€v€x$€1€€r€€W͒q4g€€$x3€€€v€j€,€1€€
z +~R`8€€p4u€€`€€+u5Sn€!°€€€a€bY€y/T€€€€€ݒ€-By=.€€€€€€b€€€€Һ€o?€€3€ɛ€€ѬLZx€€_€_€€/€€€€€€(€~-[
v€€/fg€€p€€€)€,€€€€€€€€€€€€)&€}€,€€v€€€€>€€€%€-AwC|€€W€=€r(€€'€F€:K3€€3€o€A€K€)€R8E/€4€€A€S€€ѵL€€€€€ַ€Hp€›jsFl€€€€€'H€<|Q€€€b€€€€9K€7S€
€If€€v€|€Lg€t€E7n€=€€4€8€\+{€€€n €€w€€€€y€cr€€95€€i€€€j€|€)€€q€€b€€€€€"bN`€>€€€€,€€=€€У;€€€L?€F€€€€vE€€mܫ€€€sܛRb€€€оY€^€€[uJ€€Q€:€€]=€VI€A€€ޕC€m€?<€`€]*€€€D€€€€
€)€€€9€€€€#€€=)€€%V€€i^a:€€'€a€€}m€€O Y]n€D€€CV€`€€e€€pd€€:€€&€€€€€Ä€€€€Q€'-€s€0€€
local.guideles€,€= +,_€TEXTMPS €CC€€CC€lU`"€Q€€€€€!€€^3€zA€x!€€}(Ý€Y21€CQ€0€\z€€~€Y7€€H€€€€€a€fÍš5€€<D€€݈D€d€~
makel.guidelesa<E?,_TEXTMPS €CC€€I€q€€€<€€)U€vbU€€vL€€0
bq€[FY€r;€€€(€x€ąЫdlHGy€(-€g€b€€`€€5K€€€€Ö_u€S€€hl€€j:€U.w€€€R9€€^€€€€€;7€N۩€€~K€€ݷ€u؉]€!€q€€D€J€€€zd€€Ì€ݷ0€w€€GUnYr8t€ؒm Gp'€l*€*€€€€ʙAs9€€%T€€9#)B €m;%5K€T€€Nq€]R€€€€I€b€)T@z€€€€k€ؖN€2€zWck€€{}€€ €€hÜ€B
€€ 9b€€f€€S€€€€€Q>A؇AΡ€O€€{}(9€€AX€€ €€Vy€3€V€€c€v€€€1€€€€€€$€€€]:[k€€€€C€|p€<5€:€€€€€,Ι€€€l€I€u€7rg€€€€€€€€€€r?€g€€€€ unix*€= +@€,_?€4@€G(€€9~Iރ
makele.c.origs"?@e?TEXTMPS €CC€€CC€~iR€KAQ€j*€€!€'€y€0€6p|€€€€ı):€Ò$€€€>€wtpuq€€€€€f}€€€€€ѥ€€€€y|>€efN€€€9€€€€€4€€`t6€$€Y€ׇ@m€p?!! SpiderWEB €ourcG€ +?€?€€€Q€€Qz€€€
!! SpiderWEB €ourcG€ +?,_€€€Q€€Qz€€~€ awk€€,_K
€A€€€€€€€j€€Cw€ X€€
+awk.spiderrigsDAEHAETEXTMPS €m5€m5€€€€3N€€ €€ǽh€€€#n€€ Ë€€€€€&€N8€€€€P@(€€(€GMB€€€€AgGt€aIؑ€F€N€Ȕ{€€€€6~"€€dр€|€€'xGÈŒp€G2E'xw0Q€€€€€D€#€X)3€€Bm€/p€€B€N€IJ€€€̅€ +€N€€ę€3€€h&€V€℥?€€巽€€€A€€€€€H€50Ic-€€€2€€€€€k€X€d|€€=Å†Â€Â€Ä ?€0ÎŒI€t€M@€€0OD9S€€€H€€U1S€€)<2€%€€!Ôq€€€€€P,€€DÓ§C€j€€n€€€€€tl@(#€€€QIDi'Q€€€c€H€/4€€€v€+9Ç¥C€€Mn€Z]€€)R€€$\€€Lxs€€€W#N€€('€€€r€`€%€JCi€P&˙€€Y€#€E@€€,€:€€L€€€sE€€€)€€`€ӡ€bI€€€b€H€€€€€€D€'€P€€cw€€}€Eî¥7€€€n-€€J€y%€^€€Y€€(€ڂ€;أ€€€I€€€b€€€€€v€€€€}F€€H€€€€Z€o€P€€€Z€€€r€€=€R€˲€w€0Na€€€?€d'€F€I€ø€€u"i_€€€€.€€Q€€€5€1€€€Q€€ꘑ€M5€€€€3€C€€B€€€€€(]$ 3€~€r€€€,€0_€€ϔ{fQ€Ë:€€€€}€$€€Il€V€€€€€€ݥ€]€€ +^ €ͤ€€€y€9€(€€{€pY/€2ד€s€K€O+l€c€€X€€W€GK_c_€€€o;,€€€.€€V€€Ô€€A_€_ϱeÇ Â€Â€1^€€p€€盌€Þ€€f:€€l€R€€€€€Tm€€€{ Ƽ€€q.€€€nF,€n€K?€4#€1€x€Iر;$8ϟ€€€€է€€l.€€FÂ€Ø b€€€€€RvP︆€ÌC€€€€g[€;xA€g;O€€€K€€X€€f4UtN1€€€€., €€€Q€€€€27€8€>€€€G€:3€[€2€{€€{֔˯€7W'7ru€wq%€M€€|V€u€€€R>€€€€Ѣ€€\€€>w|€€S€~->€7€T€JK€a€€€X8€m8"€€€S݆€€Kebg€z€€€€€J€€€J€w€€}€]R]€a]€€ P€€€
&(€#s€;Ӻ!€€€€)It€€N€t1€a-€€€€€€€7
€1x€.s$€k€GAËPA8€€€€{€€p€\i€€OA€P€r€€6€€€a€W€D€€3>t'ˬP€N€€€4€€€0I€€՞LG€W€S€
.€0€€l€€U쎛T€€€$M€~€3qD€ €€€j€€6\€,€€n0€K€€p€-€€€avELb
5€€€€Ҝ}€€6€€a€N€^]€v
€,YI=6€€€€6S€€ €K€€€ޛAs€D€€€€€€+@Ñš9€L€€ˇ€0u)݉ʪ€€€€€€\€\€:̹Xr€=K€{€€€€g€+€rO€(€€ €€á˜w +€€€€/€€@}€€ +€9€€€€€;/€4€€€€€€s€'/u€䥞&€ypë‚›Rf€€S€€€!,H\Jm*hl€%€|X5€€€4€~€€€€g€Ei€€€
makespiderrigs€5A€I€AETEXTMPS €€8V€€@€€€€€€{o€€€€vb@€9#,"€€€<€€!9(#P€c€md €€€ZRO€dR€€€€fi€€€R€€€€€€h€€T€€Ħ}€)€€€€!p€€€-€€€€€z€€€} :€ӽs;3I€€3€¡FܸqÉ”T4€A€€€€;#€{!'€@S€€€4€€€R€;€€%3Ѹ#(=?€€b€ڊ€€Z€€€€€!'@€€€/-:€q€€€m€[Q>A؇AΡ€w4f€^J€r|€€€VG€A.€a€€D@€€€f€€؇€€|€|€€} i€0I€€6F€€€€blFlw(€€bb€S€€cNv€sGr€€4f€€€€€€ +`€Ã€Y>€€€€k€y€p|A€ȳ€€
make.unixrrigs
€HJ€AETEXTMPS €m5€m5raj{o€Q€tH€€€€<$'€€>€€€K€€€€€€€€€€€al€€€r8€€€€.€6F€€€€bl€€€;€I8€95€:€D&>w€€f€€€€€0€€€€-€!! SpiderWEB €ourcG€ +I€AE€€€Q€€Q+B€€;{
BUGS.unixrrigs€AER€€€€€€TEXTMPS €m5€€C€€
]€
€p€vb€T€R€€f€V€~€€€M€RH&€€€€€tv€&€€€€
€€€BI=C€@#P€cٰ€>€Y€}€r€€€€>Z5€€?"2€Mⶊ€€,€€>Q)€5€€6€ч€p€€€€€€€+€ۜ€€A.€€€8€DIJD€tH +€an€€UiB€€c€€€st0Dz%€)€€€i2X€h€€h€*MF8€\U€d€€€€sFR8llʅ€u&C-€€=€b =€i6€€€sV€€€J€OAgb}€€ ~T€78 +u4p€&€€1S€€
?€hAhpfnNW€+A0ar€ښ€€Jh€€KB#€'€,%€€€€€;€t€>j€3€~€U]2#4 'N€12€Q€_O`€€՞€€u^;?r€€€€]1€€w€#€r€€~X{€€€€€:M€\Q€&€€e€\\€.C|<zw€€ €Mp€jÊŒ}€){€'€€€R6€€€DZ €€&€&€€ttS[€€€€(0€€€€€|€Æc€p€€Tլ€6q;€€€+€{€>U€F€@Ҝ€RY€imeu€€€€3€:]^€5€€€J€€€€€€UyË£6€}o€Y€{pp€€^6€€€€€€O€ZÊšQ€9$€€q€€€€.€€+€€UE€€He€€€VMXZFQy €€€€€€€€€€€€€€€]€€LÉ·o€€T}5hx€*/{€€€€€€€€ܲ€J€6!z€5Q`y-h2e€|TUD€€€yW€€!€€Mm8?€}€uqr€€€LlÒŽC€€€H€€€€hQbWP€€X€+K€€0€€We€R€€€WcU€€bYIi.€\€€€€Do€€€)€€€€G{W€i€QE€ A|1€JW<
€) +€€€€HU7€NL gB )€sL€€€€*7pe€€R€ޅ€B5€€C€os€W{j€€€L€€€5€€€€€€€€€&9O*j"€€€€€€
€€€yaA€€;€€€E>Ì«}8€T€€€}-rTֳ€€€*n€o%F€]€€D/€€2€€o€Z€€€tY%€€HO€€g\€€€€€;€€€€i€€€Ko€€€€€€"€P€ €€m€€5€€€=€€€Q" 5€€Ո€쬅..€€€?€€*€€€€€ +iz€€^€€Mc€‘€`P+€€€€€€€Z$V€€€b€€€&€€;.€€€€€E€V€B€€Ga]€€R€€ܹW5€h€€#€ j€€€kE€.€9d€€d€€€<e€9€€&]€€>o€ }^1Un͟€€ p€U€-Z€€€€t1€ZR €€p\n€€€.€€€€€€€ܟ€G€U΀€"€€Tn€€€€Lt€€€€FN€€G€€€€€&€€t^/W€.€՜€€5€€€QRU€5€6€Cu8m€€€zr€€€Թ€€€߃€€{ewQÙ€€NkL€€€€€€5D€j€Z!V€€$€€I€°$€€{p€9€€€{€€]€MÊŒI'€ev8€€R€e€E€€€K€€€€'€ +€c€>€g€J!5q€€€
€Y€€€€C€€€€ƣ€€€€rElQ€䓀€€€€€€
€€d~€o€v€€€B +
€€€<€(€#€€7Ӏ€H€€€:€€smԩ€€Ғ€_BilY`Bl€€BX€€€P3|u€Y€€É€€€5Z€€€€€€€C€€€6€€€€w.8€€€€8€X€€€l€€€€€€€;€N€`€€€h€α€2€€qh€€g$€KR€0F`8€f€O€ߟ€€"MZS6`€€p€€€€e€LÖ¥g€Q)ezـB€€€w€€%€u€€€x€e€€>€H€€€"G€w€4€/WLÂ€Â€Â€Â€ç ²Â€f€}€€€€[€€Я=Û€€β€€,€€>^Nm€€€€ŎǢ€T&€€;€M€A€€x€j€€€xP*R€€y;pV? q€s'J€€€2€yſ€€€R€€€;͗€€€€€V€€Iz,_€€€D€€lc€€€DA(S€€ +€€"€F€^€L€>d€€'€
Fᗎ€HkI$€=:€|€€€€€€D€;ϳO€M€€r*Æ´ss€4€,ç r€€€t€€k€€€1€€€h€€H€€€€Y\€€€€ c++.unixdYK
cQ€SW€€€€€€p€€p2Q€€€
+c++.spiderrigs€R€bR€TEXTMPS €m5€m51€A€{I
N9€€'€`?€€€6€#€=€/ €}€€<¢dK6€x~€€3€€%€€o€€€€€ €€ +€5€ؕo€€> '€€€€O~€1#€*€w~€€`]€W€Q€€€€€€€;€€€H|€€A€€g€@€іx€i<€gR€(€€€€€*N€BjЋ€€$€DvDW€"€q€|€EI*v€€{€€€€€D€۲S€€~€€ʞ€€Gq€€€€€€[€€€€9€€D[€R[i€€?,€€€R€€#€|€@€R$xQ€€lKh)E7I€€€€€ߞ=z€pxQ€€F€€ +€Ir*i€€ʨ*LO~]€LC€€€ €€€€2€^€j0 ޶€A€€€͛k{Bf€ɣ4€dtd7*€By€€€€ v€€ €€€I€€€Pf"€@€
v€€€€N€€€€€A{€Cg<f€x€A4€JM€€gɇZ€u€€ €'B€€`_€\€€€k{A#(€oØ‚$K€€AA€€€oT€€L€€$SCm€€^?€€Gq|€c0t7+€€*,h€€€€E€U€^.€€[€n€_€Q€€Oe€€€\€ +€H*€€ZK€X€al€€7Ó6€€€G~€W€}F€€'€r€€€"&{5>€€](€;Q€U)5!-€[€€Vz€T€*ÝrGu€Նd€€'€j€€4€€ €HO€QѪ€t€ܬPq€€aa€€€}qNv€P€€J2r€z€i;€OXÊ“%€€€€'\[€j€€hN€€w€€€€€ܢnO€~€o78€€€€€€^2€€{€€€€j€~€€€€纲€@€€]eg€€€€ko€€`ŵ€€€t€u€€€€€K€/€€€€j![4[r9€€%ÙƒK€€€€֜€M0€€\i|€€€R€C€;€}|€€€€€>€w€€xӣ€>5(€w€o€€€€€€€z€€€j€<€€jU\*TX({P€€€+{€€€n'€€€p€€€0҅€7s€€€=€€J€€€|o*f0€€'5p€(€È";€€
€
€€€€X€€€0€€e€€T€7k€€a7€€'a€€2ֈ€€€€€]€€ǡpO€€€€€€(S€n~€€€x9qF€€dU€€€A>=Iz3€€ M€Z€ €E_1Cv€h€s$AmJ€€€€€€P €t€€€kpYь@€€A_F€€b>42s> €€€Kը4 €/€2n€€€%E€o€b|€O€B€`h€€€€>€€u€kUr€s€s€€€kp€Vd€,€€€€ɚW`€\b€\h€€€€€F€25\e€XQ€Ē€€T€€€3€~€j€Y€Y\€Fmv>€-€zK€€€-€u€Vc€b€h€DuS€V€€։€€<€€€€€€쎟€E€5€€/$€€炀€@€€€]@᥌t.[!€€e€j9€s€c+V€€€s€€j€€\€€ilX€$^€sk€}€€ˢ€€|J€€W€b€€€3S%o€rJ€€€€HM€0€*{Txڲպ€ha€u€€ʌRƥ€}/€€€€€$/€خ€*Y€€d`j€€08$C€€T€T€%1€D€R +€€€€€€q€€€€€€€€€€€€€H€€M€€€F€€bNPq€€€€€3>q€.8@€€vww€€€FsQ€€€€Iϧ€4€Y€€€€€€p€€ +€€|g€6N10^=€mh€d€\n€€€W0H€€(A€6l%€€h€+D-`}€€€A€p͙E€\A€%Ԥ+€T€€B€€€6C€€€ l€T€5=€J 9i€Xy€ca€€8€q
QĶP€9€;ʸ;#!€€[P+:€€€;[G€€G€€CA€€^0€€€€€€`€€'€\€€/€€€ѧbt€€€€€€€:€ G€Й€€€€s#e:€€f*o€z€i`€ho#€(€[€A}€€€€€1Y€e*€6V€€+PƇ€) €€€€€f€Ԯ$€€€Clp€7€€€bB8€2m€€€waP/x€€€_2Ux€s€P€€€C7€ +€2E1/€h€l€€Nd€€€5€v €h€}T€€sj€`/€€X€€€€(€€€€H€Qjd€t€B€*6€R€T€@€€J\€A€€€wA€S€ϘR€&€€€il€7f€€€g€€€yƜUڹM€€€€Od€€€€€;€€G-% ~€€p€O€"€€€Qv€0€€ +ip€€€€EU?i\S`€€h€q€t€m>)4€6€€T€]h€ʌ€€R€?€€-ݢ€zF€€€F€D@€4€€€€€€€€t€€l1€;€€€H€\ǬU€€€h€€€ܘMsLNel€b_€@ȆgqNg€m€`€€S#€€_€D€O€€€€_T&l|€€€v.€€€€€€o3€€]€d€€~€€s€€€€OX€€€Г€rG)€kU€@a€ €€Z€mQ€+9'€(€€vQ€€
€\'€€€Ř<=€€`€
€H€[dm€€€€yj]€j*_€€€€1€€€€EM€€{XN€€gDvk€j€V€€€€€€*2#€€€z€~ݱl€f€€=1€F€€€€_€€€;€2T€LS€€Z
€̓€€#>€Z€`€€T֪€€€€€E€€€€Q"€€ҙ€(€€A€€€(6lu€€€€€€€#€€€E€L€硾@ĥ€5y8€`€€€€€*€€€€Ŏ€o€!€€gw€V€R€d€BWT€€€HÅ©<€€ӊ䥗;{H#BÖ Â€u€€€pAi€+€€€rÜ‹R€i(€S€7€€g€€€€I*u-€€u€ఽ7a€b G€(€€€Y€̆€€e€vм€,ψ€jD€b#€€Qi€€€€b€€m€MO3]s?j*"€wG€=€ Ó®Z€€€€€€€ߵ€47O€U€€€v€p€Uݹ€€€t~۲€架€<€6€D3֓€€3€[€€€€€€In(€€€R
Q€€g€€\€Ө/€€€€O€P€̦€]}vw€p€?Xv€.€r€Yf&€ۼ€XxCX€ €€3$€€!€€€ɹ€€!)€19€€q€€6jk€€€€€€€€€€€€s€€€€{e€Da֑€,€j€€8€ܮ€&W€€€o€zβ€L€Ç{€€\€€€€d:€[€'6S;u€J€CÌ›n€€€h€d€€٦€€€Der€€€W€€_3 ֞€€"€€_.ÑŽ4Qz€€q€7€€I$6€€€€'€€€=€€€#€'€€€€›ڙ€€€€u€€€xM3(€[€h"ÍŒm€G+€€€€€€?€€€€n€€Ñ']W0Ý–@€)€€€€1q€€%]€€xM€€K€€€€€;~+€€B€T€-(i€E€€€0G[6€€_€€cG€5€>e€2€€Y€b€€€OV€€€€Jn€4w3B@€€HG€tAs€€€W€€€}€v€€H€€€ g€€€[€€{L}13€€€€€n€€€_€z€€>€G€e€€€€€€,€€#€ZNQ€€I€"t€€5颉€!€€€Z2Iw€€€€V|v;€3€H5M/€€€€;€€n€€a€€€€6€,(€€-;
€€W€€€€€|J€ʜ`l€Å€€Y€%*€5QL‰w€]*E[€p€+\>h,€|€€Ք€lM0%€ȡ,0dfs\4t€€3Þ¶h€€€X€KA€U€IÑ™2€€€€€i6ӵ€€€€?€€Ol€€€€T€e2€€€€€Q€€€€€k{€(€€€^gA€j+>;,€Z€€1€€r€I€7€€€H€€€i€€]€UT3€€€€€w:#€w#€ƚ&wV€€
uY€€t|t€€€3€*€\€€g؟€\€#€€#€z€=8f€€€€€3€€€;(€€€R€€0€t>TB€* €€€Y€S(€€€€}€€€v€€€P€€€c€€€S€€0€€€dxK<€€$€
€€€€k€<€€
€€٘~€€€Ɩ€fN€€€s€aYҡ€€€€€€hF€S;€T€Z:]V€€o€T€€[)€€{€€€n6Q€N8€ +A#€^Q€5€€€€€Xw€Z€{€2€€€€Y€€T€&€h€€€9]€P3€r€€z€€€€kWXs€€€?€?
makespiderrigs€5SWb€R€TEXTMPS €m5€m5€ig0€€Q€j*€€!€'€y€0€6p|€€€€ı):€Ò$€€€>€wtpuq€€€€€f}€€€€€ѥ€€€€y€€€€P&€`€Ԩ€€€€€Hs€
F'€ì€€C€€T€!! SpiderWEB €ourcG€ +bR€€€€Q€€Qk€€€€ c.unixY€R€s`€c€€€€€€€m€€€€/f€€
c.spidererrigs3€cQq6cQ€€€€TEXTMPS €m5€m5,€
€,ͧ
N9€O€€<~€ڥExd€€[€€€€€'€MK€%€0<?J€€€€OW€0€€€k€€€k€5i€O €O8€Gn€'€€ €€M €3/€€x€F€<€J€€€€|*€€€ʇQ&^F€B€w€€€€€€x)€€@|V*N€R€€x€ġU!€€€r€[€Q€€T!€€t€€€\€$€0*€€€BJ€KR)<€€€€>z€(R€€\f€€&€€K€€€4€€U€€€ߖ2+ @€A€E€€€€ V€!€€>Tt6€lo€€u€€}gc?€€Ui)€<ʊ€g :€€€d€(€3
Ju$3€t!%€%21f€€D€Gs2͕U€Æ€(.x€q€d€Y€€Fc€i6€}C>*d€U€&€D€€{€€0€e}K€€n€€I€0€(€%€€%€€€€€€L€€I€F€€€}]€b€}C€0r*K%:€(€e{.
6?€€€€J€€Q€€€€S€;€F€/€€J€xPJ€€€;'€€O€%Ϟ€€€TQ€€#€€WFy€€gS€€€h€$€€€^€h€=€€?f€Y€&_=€A4€͟L€€p€€^€€€€€€€€€K€€€€€€€o*YÒ°}€b€h€wsE€€P€(€T7€€ɾ€xX€€€#€€€C:ږ€U#iǹ€Qq€8c`€/Ⱦ€$€€€O6€IF€€wz€c€ʓ%-NÇ•7\;€j€€hA€€€Ü€̓€A€m€€ʷ€9€€u/^8a€y08€z€€q€€[€€€.wD€€€ɚk€€€€€k€€€€5€͛+€/€v€t€€€5W!b钫€ퟒ=€"€tN]sf€`Ź*t\B€€€€€IHQ€qrwr€€€€€€<€Y€€5€€C€x€Q*€Nn€v€€€€€z€€s€€Us€=€C€ +Keak€~xc€€€<€€Nx€cq€jqaT€N_3€€#{€€*TȀ€€L€p€€€k€€Q€!€€€^8€Nc€'€0€
€€e€ʴ€ր€^bO<a€€0ֈ€€€€€}€(&€8€{€ɺ2ic€€€$€vK!€€€.7€€$+Ю€Ӄ€€€€*€€hfB€h,€€%€€€@&=ơpZ€`$€€€`€€€€R-€h€Ɨy/€€A€€€`€g€€€H€Y€€ꩂ€€€€
€€€B€€x€CQr€x҃ r€E€~€)V€²€€€l
׳2nkp€! +€K€dy€€uPcay€€€€Ƣ€€€]€€€*€c:â€lօG€€q€€l€€€€€\€€€\€D€€€b5TkxY€ўM€@€Zkֻ€€€n€€%€L€&€Ŧ€€€€€€€4€/>€7{€ €€€€€Vܕ€ +mo?#S]€G€m€€€€3W€€>$C€6E1U&I€€(€€€€j€$€€€€€€€€€vo€€ں'€ $€H€€[€*€yA€Q€n€€/€
€.€8€: {{{€N€k!€y€€.k€:€€€€,€/€/`T€E€G#t1€b€c E7W#€m ?€h(€€€)jI€€c€c€€
A€&€ğ€?€€ +€īG€€0)€€€€€oU -lrJw€€€€j{€H€€€L€€€€€'f€€}D€€rVP€€-y€€1%Ê€€U€€UURJ[S€€€€€u€~N €€(€P€!Z\yL]i€%€9€€€:jT€?€g€yh€€€1C€J۳€€€€B4~C€q{|€€9
€€9@€€Na#€K~-jw€B€€€0€sj€€€0 L€F€€€,N€€€€@€€€€€€-€€֌M€€ɋZT.€n~€€.9€€ϔ€€zP€€W€€€€<cG€H7{€€9€€{€V€€1€€#€€`€€€€€QK € +€n2€€€€€€(€U€€€ +ip€€k€r€€€Ojb8€€\€€[8@2,^|€€ӫ€^X€J€_€ĵ€€€j€€4€H2€q€q>€,€€+€w;€xl€€€€li€€€]QR€€€€€T €a.€9€€€€~€;,E*ł€€€]$€€€4€4G€"n€t€pH8€p€€m€€€€€=€YER€QNi'0H)€€Q€€]€;k€€yg\€€€Z~Ջ€|q€€€€€€€rG`~€€#€€i€€aI€p7L€€€€€U?DA€0€€€g€^€T€€b[€>€m€€3€I"ұ€naa€tE[mCg/Yl\n€€€€€&€€€€€}:€€€z€€:€€€€€_€€d€ p=7€€(Â€Â€å® Â€Â€Â€(֘€Lx€€8€(€*uDk€T€€€€!!a€€l€€€€u€3€€ш€€if]ʂ€e€€ +x"3E9€iZ€Jn€T +€€}€$~€€€€&f€€g€ €€€€€4$-€€€€,9p7T%i
€€€P€BRL€:€€:€j€MN€€€€€€€€Z€3€#€€C€K˺€В€€€€$h€€}M!u€1M€V€€CM€€<€z|5%s€€€€€/zW€€oĵ€O€€wov€€€gE2€B€€$K^€€_€%€lX€*€€3D€€€€Zcg€€€c€€ 8€€€NWu]€€
€>I€)€.€€€€€€€€ wZ€#€F€€G€€8L€€€€€€€ܣ€€3~€€€€€f(F€̀€€8€m€h€€GQ€€€€. +4&€:(€€]€€Ŧ€€€9fi€ +ɛ€>W€€V€o"*€uH7U€i€)7€$[W€€€€€€AڸLf€gP
€fllÝ€qX;€€€€s€
€c€َn€~Ì¿X€€€€3€€€€€ /€A€iÑŸN€€€=€D€€>€€€_t2uջh€€€€Z€H€€H€€L€€€˾€UQ€G€B/#€€U&p€o@€ڗ]€r€\€l€#x€€R€€\`P5A€_X\€#Ä€G9€€€ä`Z€\€C5Tc{iPtA€GZ+€€€€€€4€s€ 0€€]f€€Yjָ€€€€9[S,€€^+€m
Θt€ŗ€2€€]€€€€€€€€B2梅€€€€Õ-€€2€€€€€ +Q8€€€x€€€;,B_€PB€߆(€€Y)€€`T€€€€B-_€P€€€€€›€D`gLs€#€€۪3€€.h€zsEp€€%€k€€w€Ȳ€AΟ€€]€o€€€€€l€%+€`€€€Ե€€€#°€€€T€,€€€q΀T.€# €E膣€s€2€€
AM<|m2€b€€ۯ€|Æz3€48€U˙€€€;€€7€0€€€ܺX€ޯe€€.€€bv€€€€€€€z9€ĸ€.nL€ΚO€j€bU€€)t€€O€€^Ew€Ԝ€€
^MXJ€€ +€CY€ɴsl4€€f€i€€Û&hx€"@Ñ–aRt]JWkz?"fs]€€€€~€€|€€GÅ€j€€€€?€€l€€€€€롫€n€€t8+€kW€€w€Y€€.bc>?/€']6ЕGs€Çy€€q€7O5€€€3€€pg32x€€€ir€€€P/j€€€€7€€J1W€od0S€ €"€€€€7€Ӈ€܅)€€€7+€€c€€̂€C€€/€€!€€p€€[4€IoJ€€€€€€€€o€€N€F€€€€€€L-9€Q2€X€€€ӹ€€RA€€$BGx€E5€€€€€€P€"€€€€€ߢZ=c>Et€φ<€€€€|!_€€€€4D€€+€\€€͋€€?€€€€€€$€€'€B€ +N€€€€€€€€|€€€€
makeidererrigs€Cc€r€cQ€€€€TEXTMPS €€8V€€8d€€€€€k€€€€vb@€9#,"€€€<€€!9(#P€c€md €€€ZRO€dR€m€€Y€g€€€԰€C€rZ€v€j<€ش€;€€!3€Լ€€C€€€Y€€€€/A€y€wng&€€€sFR8€€€7€ €€€€=h?€3ug$€b/€€h +Ѓ€f€8۱={G€;€€€S€-Ư€€H(p€€P}yl€€ €Lї€€тP€€€Q>A؇AΡ€O€€{}(9€€AX€€ €€Vy€3€V€€c€v€€€1€€€€€€$€€€]:[k€€€€C€|€€€uIr€sGr€€3f€€€̓€+n€€€A>4_]€€€€ €~ €^[!! SpiderWEB €ourcG€ +q6cQ€€€Q€€Q€e€-
clean.makeoutsBcQt-€TEXTMPS €€Ce€€Chx]€_i€Qi>€€TaD€€!€€€;€{€€&y€€€€e€€A@€€€€€€ɢk€6x€>w€€€€B_€+€€€>€€lp€`€€w,€€A@€€H€
COPYRIGHTeouts€s`v€€€€€€TEXTMPS €m5€m5€9€XN€Q.€€0G€€€!€x€€€€er€_(€€€€€€€€w€+D>€?€€?€€~ʉƾ€Ï<`9€°/`(€-\€€C€E0€Q€O((€|€€/€€€`0€€cV€€€€|€€c€€€r\€€€€ܞ0h€€€;(tp€€#€€€€€!.Fh€C€;(i€~€F€€€I}€/R€€€mi€T€€€$~~€€ €€c€!/€€x €€€€!€€)€ca€fY€7u€€€.€€rGTH5#€0
!€€€[rfH€(l€€€y€Ĝ€=€€iS€€i€€€ǔ€€€;€€€€{€€€È€€Y€€€€{ܹvQF€n€€3@6€@€"€dnG€FmiB€€€€ 3€E€?M€܉€TFd?€€€€€€€]ÊW;€ݚlM€€HW~€€€€€nL(rS€€$€ +€€dzT€€€K€~@€€€€€€h€&t€ +€7€ƴD€€`€€€,#€€v€€$DY€p€€¾la€€ǺΊY0€%€€A€€€y|€$"
€€€€€:€€€P€€l€(hKrn6HQ7l€@€$n€€€€4T€€€ +€€€+€|XB€%'€>/'€ cp/€t-€G€wF€€€€€CC€€€C€?€Ш
cp.spiderFiles€€v€€v€TEXTMPS €CC€€€5€€;%€i€7}j[€vb€€€€€€#€€€€€€€?€€€LoJԗ€€€€8N-€g€b€{€€{_€֯4€€i}zÂ€Â€Û Â€Â€Â€Â€Â€O€€€€€܎6€t€€€P€€އ€€€€w€A€d:'FH:Ou€YP€€€€€h€€€€"€€2€X€I€€3€€'df€€€43€<€<€€a€rB,€a€€3x€€€€€0)€€2%}€SЙX€€jH€€O: +Õ—Ç®&€€1S€€€€O5ZÚŽ9€
N9€€'€`?€€o€€€€€€%a€O€D¢dK6a+? €X_B€€€€vLN75NÐV€€IG€4€€€€p¯#€#€#€€€'€€M U€€€Z€€5€˓n€€€x€
€€€€g€a€€roU|€€€€ J-€€€€€V€$.€€€€v€Id[tT.ZW€€€€€€ݸ-I€Ǝ€€€.€b}7Ñu€.€€y€W€€eW\€€€€€€€€€€w€€€9€€DS€R[i€€?(€€€R€€{€y€€ʥH2€€€"Q٪€R€N€Jq€€~x€€€m€EÑ“b€2+D;€e€P€^€€Y€€€€€€€€€€4$€€ €€€€N€€x3€Z€€'ަ€B€€µk[Bfm€€€4€d€e'.€By€€€€ 6V€F€ˤ€bjGf"iC€
v€€€€N€€€€€€~€€!€3€@€€€€a€€€e€Z€m€X€~RM€€~ɾ€h€2€?_؊"A€}€$Y€p]€Z`€€&5€+3€7€L
,t€)t€:€€€€`€€€€*,h#€R€Ӣ€€€K|€-p3€ge€€€€S€)€<W€p€&€€B€€€€qK€a€€€ÃNf€hl€€ü€b€€F€x€O€€O1!/€ޫ€)€€T€€Z€g€Ԅ€l€M€^€€]€R-€T€€€€€€
€d€O€Q€€[;€ѽ)€GzÚ¥@€Òs9€Z)€€€=€죙C€€}py€۟`a-€€€€€€'€`J K€s\€ՔM€1€j€q€€€€€€-€F€ €€|c€€€€ܹ€€!6}€€x€€€€ϸ€€s]ڜ€ኧƲ1€zoε5€€;€ڜq}4€€|y€€€€€€\€s€!^L€€|`[3€€€d€€9_€€€:€€V€€'€€T€ۤq0n€J€€5€ +€€
+€H€€7€o8€€#€€C€S€yԃ€€€€իUq]€\€€€€€<€€Z\w€Q(€[€€€€€€€n€qi€€€+q€X^_=€€kv€€€h'(=€€€€€€?€€C€€€€7R€L
€h€b
€€€€7€4cy€€I€€/+ƆL€|€€€€$€€ Vz,c€€(o€€ݲ€€€€,€€騬€€€€l€€2€_.€Ëst/€€e
6€Cx€€;€--€€NՎ€€€=Fȶb
s€$€€€€€`a,Z€1F&€10€\VLFpj€+[̇bg€#u€€&*
€€€€lM€€€€&E€7€3€€E/€Su€€€€
$€q€€€z,€€€˟€€€u_€€X€K€+€€h€
p€€0Aα€€4€Ph3€€2\e€€S€Ē€<W€€€3€~€*€Y€Y5€l€};€€C€€UXؖ€:K€€(Cs€€'€:€€€+@€mm€2O€4=€€*€€Gk€t€€€€;€SA@€!QitÏ Â€RF:€
HD€<Fg<_N€D€؊€x€n€€€'O€€€€rU€€€€€`€€€€#€k,€€€\€]€#r€€<€#€€Om€j;€#r€֧.k€€€€`€€€€]€€€€€dʌ"ȹ€g€€.€lvO€€@+<G+J8€€€D%s]€=G€€G€€d€€q€€€*€€€€D€R +j€€€-€r€€;€€€`yi€€w€AH{(€€a€Sf-N_0€ty]|€W€€€€^€€€€€€€€0`€.€ +€$€€4€,€€€=€€€x0€M€u>€€E€ €€<€€2~"ׅ€€€€
€+€R4*€€€f4Í¡b€p€€r €D€€a€€€#y"€ щ*€Y.€€B€€X7C€€€ l€T€€9nM€i €€Yy€€€8=y€[y<@€€€Î€]È Q,^€Z€€€€^€€VL€+€`<"€€v€{q€uI€_€€?€և\€€/€}€€Gbt€x€€€p€uB!€l€=j€€V€.€€Ù€2S€€€€€€€6F€€€Jԣ€1€€€€€-M€LE€€ +Q€€€€€fu>Q€D?€€Y6€/ f(€K€3€yò€ G\€€€P€b€
€1€€€K€ +€€]bn +€;t€€€*S€ +€€€1m€€€?€€Z6_€Q8s€€€N€€€€[€GF€q€#€€€€2€GÛ§h€z€€W€€€€>€€€I€J˶K€F€I€€€€~Ų€6€€k€€€p€D€ €€?€c€€j€€$€ǃ€€€G€€€Gl>c€*mß Â€Â€yì©Ž'2€€€_9€€G%%"~\€€a€€K€Ԋ€+€€=VH€c<p€Q€P€€'€€l€9î¼®p€H +€€€€:€ +€€*€4€Iiy€€€g€YaLL:€€A€€€€€G€€h€€ €€f,€€U€=€ ]€t21€YD|€€€0€$€€€€b€€g€€€€€€&€€bÏ€€€5$m€€&`€rxRb1q)€€i dɳ€€1€%€4€H*&€*€s€€€Ȋ)€M€€€€OB23€_@%€€F€q€€€AI€m'€€+€UW߬-€€ǔ€d j€À6€€€M
cAe€J/€Y(.€ZB€€ݒ€t€€M€\€€Oye€I+d€€€6€€B€C€€€ +€€+€€@Pm;j€W/T€€NA]€Y€dhf\a€€Ԙ€kf"3q€€O€€€A€€€€"€€C€깎j€€4<€€€€€H€(_P€€€35€k€€€4s€€€€€€€€€€€€€^Q*€<€€ht^L€{€€€€€zʶ€€z€O€€€€8€€u€T€U€D€CYAOp€€6€U€EZ€T51€€€zd[€€q€€€siprov8€(€€€C€K€uQ<€€+€8$<A}€€Z3Uj€€€P€K€u$€€R9€##€ؓfA€VLw€F€€A3kS'€€ €€g€%€€Αi(€S€;€€UC€{€$€€]€€€€l%€E€€wÄ™;Â€Â€Â€Õ Â€ n€€$m€€xÖ€€$ņ=€#h€€€€€v<€€€q€ +€pU€y€-€€€;¯ѓ8€ڹi€€€>{€€`s
€€Fm c€[€S]€€€:|€€s€€€Hۘ€eW€€H€؂ +€\rA€<F€H5€-€€qÙˆ8o€E3€{b€€7€.€M?޽€€€L€€y€*€ +€€e€Yf&Õ·q€1€€0€ €€7:€"€€€ə€!)€r9V€i€€&€ +€L €Ş=€€€€€M€u€€FD€€€ €YG&€€#€€;€r-Ì¿2>3"vݑ€€€€,€€€~€€~Y€€|€€L€€U{€u€€€8€€€€F€€{€E€Y€ +€De⎽€s|€O^0 €€€€€€"PY€€5€=~€€5u€€€€&€€€t7€€€y€%3€I€€€€€m€€€I€€)€€€碌Ls€>€€x€\€€€Ì€1€;€p€iq€!€€€"9€€€€€€€b:€€€€€gT€€y6€Z€€€€€rh€X@€K€€€€€@€€€€v€€aH€€€w'.&P€€€%€d€8€.€Ag3€>€€͡F€ͣj€€M%€&4<+€€>ʑͬ€€o{€€6€8€€d€€€€H€Õi€ĕrWB€€€€j€r€€-€4€€V€52E€€x|€€(€'€€x€=€<€"n€€€`€€P€K€@€U€€WY€€:€:̼€G
p1€tLV€A€€G +€,€€€€*€€3!|3+€€€€€U€Uaf€€€ݜ<€€ €#€€_€U€€r€x~T`_€9€€€€^v€€€_€€€€€€€€n€{S€Y€€H4€ܵP€€€€€ЉlǔM€V€9€€€€€K€T€€€€Â>€€ƙL>:,€&3€.€K€€€|€a€€€r€€g€`€N€3€€1€A€3k>€xn€/'€€€€ì€)
:ȥ€€€m€€€€9€€WF€E€€€C€ €Ʊ5€€€A€CYd€€€€hXgi€€w€ۋ€€€€zY€Wd€=€B€€€€H€4)3€o€€€?€€€YO€f2€€€€ë"€€V€^&€ì¡Â€n€{6€)€€€€€€€€اj€€;€<€€-€W€€t`€€q€FO€€€зC€ь,Þ€X€€NÊ€€€!€€€€x€*WT€€-€€4^€KBHf€€ɺ€Ʈ7S€€-?3zb€u€€€€€€€*=€€W€€ݶF€3.€€ÎB +UU€̵€}|€.€€€)€u€€€g%€€€€€dp]€=€{€€X€e€A€€€C€'€€Do€€O€ah€€m€€y€€ €av€€€€7€o€5N€yP€@ơ€€q€p^€i€€J€€€€€<€teȈ€€€€€ |E€7y€z*t€u/]TwϘ€u€€€Q€7€T1€D€€/€€€~€n€T€€€h€€€€i€€€€9€€?€€?
makepiderFiles€€wF€v€TEXTMPS €CC€€N€€€€€€Fdau€€vbU€€vL€€0
bq€[FY€r;€€€(€x€ąЫdlHGy€(-€g€bG2:l>I€€€z€k€€U€€€€>[€€€€s€Ë|2€TΧ€W€€€€9f€Î€€v€€€€R9g€€€FvbWu€v\€s>Ѳ€nsv€€7€€€F€-€€ݲC€Q€[€€ €d€܉=€ʣ€€|"€rfA€\€€l €~€H +€PBr€NI€R(€€€€Sj€€#)€{€€XFz€€€€K>€
'€lfo훟b€o]t9-6o€Q€€€s5!'@€€€Ԭ<~€т€ã±Q>A؇AΡ€f€^J€r|€€€VG€A.€a€€D@€€€f€€؇€€|€|€€} i€0I€€6F€€€€bl€a€;€€'g€S€€#€€€ܑ€A€a6€$€€€€€€€|D€€€€€$€€€r?€g€Ʊ€ unix*€€€€v€€€€N€ħ€9€€I€€
makele.c.bakesa€€g€TEXTMPS €CC€€CC€€ig06;Q€j*€€!€'€y€0€6p|€€€€ı):€Ò$€€€>€wtpuq€€€€€f}€€€€€ѥ€€€€y€€€€P&€`€Ԩ€€€€€Hs€
F'€ì€€C€€T€!! SpiderWEB €ourcG€ +€€€€€€Q€€Q€€€,€!! SpiderWEB €ourcG€ +€v€€€€Q€€Q€€€€ +
dijkstra.unixޫv€€$€€€€€€€€€q€€q6€mk
+binary.webnixsb€€G€€€GTEXTMPS €m5€m5!€Y/€o
Ny€N6€€€Y€€€}dF€6€G€€€€d{d€#€)a{€€(€€€€€€€:€2€€€€@W€u}×¹=€€€&€€€>€€B€€M€€€€€€€[dZT€€€EmV€€€€€O€€.€€/€*s];ctQy€€€Vwq€]€€€V€€j;€€€€^͋€TZ€€€€€F€ɳ€É^€,/€€h[€zit€€€€p*€r€b€€t€]€€j€€q€m€s€€ G€€z€€Y€€€\€€€^4€/€€)u€€g€b€€€€c€yã´½|if€€k,€_,*€€+€€y€€Ko€l€€€X€Y€€^APlRW€k€€¸€€6€kk€Z€v€€]€€€^€€[€5€,€€€8€€k€€€€]€€ε3€€y<=€W€€W€v€S€ˬZ4€g€|€€l€UV€€qr€}ihGsS`€j&c€€y€€€€Y€€€€l€9Y€Փb€ۺ€k€S`€A€z€m=€?€€€€€`Xf€€€€€G€€€€r€€€€€7+€€*GG€(€€€v8€€)€€€n€m€€€€x;.[=€€mÙŽ~€€w€Q€
O\|€ڷv€€€€uC?€CM€}<=€i€Nyߪ€€>(dO€1€4+€€.K{€|€€€€7€€YfW3Vfui€_km׌€€€€€\m<€sj;€€z%)
€€ZMM€€:€3H€€€€€€.r€3€# +,€€놉K€*ˬ€€€€#€€€z2€€€v/;€N&€I€€Ӯc€€OZ€€1΀€MT_€zs4ɇ2€€€€€1€i€€€€3/c€€€r€€€/€s€=k€€SLFg|S +k€€€V€K€A€,€v€9€€ƨLW€:n€Ի^X€-)D€€€=€€p廉vxşsd%D€ڛ€€L€€€d€€€z€9€y6€K€!€a€€צ€€b€YTB€|€l€n€€*+€€mKf€€6%4ʙ€k€k€‚r€7€mg€€€>€€P€D€X_g€_€€€€K€€h€n$€f̈€/~€€€€Dgwx€€€€€€ӽ€k}€-€€g€՛€
2€€_€€o5€€]€Үq€X€_..z|€#`N€€€ӧ€€`/€#€IR€)€€€"!€
0€€€]#€y€€b€€b€€€c"€€9R€{€w€b€€€€у€€"Z`€HB€N!€€8€.3,R0€kT€€n€€R܎nF€€h€€-€5€€€€J€€D€€f€l€€0€€vF€ €39{m€€€GԋN€H€€€Hz€€€r:€ +€Y]g€€€c€€€€€9C€r:€€€{€€BV!€qD4€€^Zx€Yh€€€€€€ugϚ2s€ԢF€€ɩA€Q€€€ !€N€g€Z"@€o€F.Sڟk€€S:$€€7€A4€€W€€€i€F€€€`K€%€€Ew h +}@€€_D€{PN `Ffk€€€QX8€#„}€€m€€z€€ €~]€€€€€H€€€+€€(€_€€k€]€€€€
^0€Fb€€m#Y€€0ߩ€€€p€c€ġ€@€;€=€b F|%RVTﺔ_€€€€€l€€1€€nD€€€€^€4m€`€€€€€€€€"€4€€€4€b€`€€|w€€€€"€7€s8 €;$T䔔€D€€lt^.
€€€YpK€€€€*%€€O€k!2€K€€__€€\dZ #V&A€`€a€@9Ʒ(€€€ €€€€@€x€€,z€€Z€"€€€€"
€_o€&Ev Q-`€€l€€,R€=€€€dG1lY R€%iecn€€€€€cx€€€€€4X€p[€*€Y€)QD€J€\€>6 +5gV€€€ÌE€€NѸ-b ER€€+E0€FaGf=€E€@u"2h_$€zVf*ʸ€T€z!=(€€€€€TC~ӆ؄w4')€j€D€€€I!}ia\€y€@€€{€Ħ +F€|€€€D€€Cu€+€€l€€€së žÂ€Â€a€O€€@a?€€€)0€€M"€€߱zBl @2€N€T{X€€7P,€€€|
8€€€H€yf€S.€€€ 6衟€€ԓ?€€€€q"€C€€y€l€€"€D?€€I`2/g€€€k€€kb€4'€€€(Q€€€V]}k€€X€~Ww(€n€z\€€€K€@C7€€Th€B€€M€€€€vW$€Ë€w9€€w€€€€a;€X€€€€Ƥ€€璫€
€€n€€€$€׶€C€(€€ €zХ€Yt€*€M €€€>Į€8€€_+€€2&€€€€€z€VKQ"€ +A€}€€€-7€S 3€Wś€T€6€€€9߀€;E€8C
+7Ʈ€€7€@6!€`€€€b€C€)YK߈€koO'€€R€€€€€b€€+€€Լ€€€€Cl€€7€R-€€ᨀ(8c€3wق€E!€€BX€c€€€ߦ€M€
e%M|€lKi€>9A€€€j€€€將€€#z€€P8€€=€D€€€€Mg€€iv€K€€pP1v€€R€aX-€€€0€€H€&€a€ْbp3U€€B€Ԅ5 ;€x€€P)€€W€b€€€5€+€€@€€€F*\S€€€@y€f€Dz€GS[F€€€€€€Ô€€O€€€O€Q€8#€€Rg8€€€C{!TN€R€e<L€*€0€€€>€9€' +0€€€€:,B!€E<€€
Ky[€+€€€u€9Ù«T€i/]€H!€€SOπO€€|€€€€€SO€€€p€>B€€vttÞ€V€€€€r;€€o€,ӟ€€^€€€€€€gT€,€V}€qÑ€OO€ +%4€ €€ɔ5R,€c€€0€€c*v€€F +*È£ €€_€"Ï€sO€€€€€/QB€€€u€€€%_€€€€€€€€-€>€AS€€S{€:€€O€M€€€Ad%a€~€g%€ux€V€^1%l)MfQɺx€€€€€€F€€€"€€B€ô
==€€O€€8yYT Â€Â€ê ¿Â€o'€€€€€€iHÈ·x€€.€€AN€€$lH!
L€€€€€@O€x€€#w€€,€€p€€Ev€;€P€-Y;1L€?ԫA€€J'BR€4_J€€W€€€j€€
€€€#v|Ev۸z€€M#€Hʚ€Mi1€ +€€€Z€_€qY1A€€€ǃ€€4€€7€N€ݿǫ€€€0€€€€H!_€F€;€€b}_€€€ZW€€K€€€€€I€o*j€€3Zr€s€磇€bw€€N€3x€€€€ܬ-€xD>€ €€€€]0IB€(€€€/€€E€€€!K,n€€€r}ҷ€I9€)1€ӕCd€€€U֬€€8€€G€€€D³€€l+€P€!€?€€z€€€g€d}€Nz€€s€f-€9e€~*H€€13€€}€"d2€€€€x€€4€€{€€€€€08j€€€{€-$€€F€€P`H€€€€€C0 +)?0@€r€q€A€€€gϫ€€0 +€
d.spiderebnixsvT€€€€€GTEXTMPS €m5€m5€€n€€€€O€@OF€€€T~€€W€>?€€Β%€"€K€axF(XO`|€)@^€:z€dM€~€7hB€€@N€€}€F8€p€€€[€A€€t€€d€€G€€LF3€R€€ +r@
€€*€i€@@U€)y€€3€€:€€$# €€€€RU@€\€R€&R€r€P€H€ €$4cR€
@bÆ_€€€€€€?€F=ɦ@R€@d$b +Æ™T€€S1€€€S€€€€
€j6€€ €$1€L€@o€€9 ""€€3AALs€Í}€€Lb*@k2€8€L€ ,B+,f€€c€€}€Y€K€€€€Q€08ۇ+€V€€ΰNg!
€€TC€C
€\دw€ €Q€€0€€ʆ€€€€Կ€\€͈ €zi€V€]I€wkYo-€e€€€۵l€€-{€€€;€E€v€v€u€€0Kg€€@q!€€€'c8oQI;=€€€€€-€€€€J%S^€€Z€€R€9€€€€]€€€;€€qy/€o€€p€€€):..V€E€j€€a9€^€€XM€€Ɵo€E€€U€€A X€Cx€"€hB:[=€€€€€€€c'€€€7ؾ€»+쯷!
.€€€€€€€\€€€€€M€{€€€l€Ͱ€c5€€[€€€X€€Ndw<€fj€\€€r€€)=B€€€ދ€6€€€M€€'€x€€C€U€€*
€€~€€€€€€€€€€%€€€€I€7€€€\€;€D€=€€TIK€a€€Zթ€۫€hz€€€kh8Oi8Qx€€€DŽ9Ż€b0€€€€€O€€$€ +w€"y€€v/A€W€€€<Ü—bb€9lgN€9:%€8[€q€{€€€€€H€k€)Â€Ç Â€1|6M€€w€€bQ(€K€€UrȰ€a€€€€€€€€€s'€#Yh€€€<dq€w>€PC€Ԃa€<pQk?€X+€7 +€S€^€rv€<f€V€V€ 0OB€€NLjx€€€€yx€€€€'€Jͳ€͙€z€€€€€€.€]€b€€€€€*=ԑ€cj€€0€9€2-€6;€m"€q€€t€JG#I€X€3Sg€sm€ڵ|€2€hc€€Y€€T€€t
€n*Åh€€€W€K_€€ €4€€Ue€rÆÚ'€€&p:€q2 I€€}€lH5€R€€X€€X/6€€U€RCvo€`€€D@€€p€̚€€€uC€K@7ݲdg€%€€€Gjl8€O€=€ٗ4€€€·{8€€€H€€€€'€sh€€€8€€€€€̶ǣ€€e€€€|€|x€A€€-€€€€€€€€€€V€5P€W€W0+v€€€{€U€:€€€€€€€[a€ ~\>Ka€€5€l€{{hOtCd€k€€€h€W€y€q€;€€m€?
makeiderebnixs@€€€€€GTEXTMPS €m5€m5m]€€€1Q€tH€€€€<$'€€>€€€K€€€€€€€€€€€al€€€r8€€€݅€€€€€€Z[€ͼ€€$L€uI`€sG| €a6€ͼ€a€€€!P[*€
READMEerebnixse_€€€€€GTEXTMPS €m5€m5€€#€€5Q.€¬€€C €€€€€€€'€€]/€€P&€€€€€!€€€€€€€!oۇz €;€F|(dB€M€€€€€/€@3n€€€€€`€+€€cAÔ€Kӛ€Dc€|a_€€€€B"€€n"և€€p€€¾0€4€€L_8€A€€€€%€ß}€d€~
sp.weberebnixs€€€€€€GTEXTMPS €m5€m5€€"~4Q-€€@#w€03a_Ö€d€==€€\8€
0€Q7y€€`€€@€`&D~€d8€<€<€B.€^€0€€€/€€,€€P€€€!aKNزi€€€€n\€€€€€€€€€€]d@€€€@€€€€€€[6z€Ezm3€€D؉Ԅ€€€€0€y€N€;€€€'€€€€0)€ع€€m€€g2€€€K9€€[b(€F~wkI/X€1€19€-Bj€_€€€o€€€€;€€€€@€Hm€€/q€€€W€ +€ +}€€€€ €€k€rJ/ɛ$€lj€{€r€4D|€€€€EO€ +€V-€€/€€!€€€A_N€Bc6€ɪ€€d€€P2 >~€v€€M€€wl€€䒰€€0€[€<€͵Aǩ^&S9ϟ€)€|€€€c€€<€ €W(l)5€€€~€B!€€€%!! SpiderWEB €ourcG€ +€€€G€€€Q€€QĜ€€€ doc€C€G€€€€€€€€€€€q€€{'z#€€€
abstracts.texs€€€$€€€$€€€€TEXTMPS €m5€m5€€€€Q€=€€€€?€€€€€>:€}€^€€€u*€d€C€;|Â€Ø Â€ +F€€€f| €€€L€€€€ç¾Â€Â€Â€Â€Â€c:[
€€0€e€€€;€€
€€Lt€29w€/Yh€€€{€?€€€€€!€€`€rY b?€€€€€u€€{€€2€>€}R€je€A_8W="€!€ €€^€sÖ©VVZ€€4a€X€€@€€.€€E],€€€€c€&F€s€€4€€€"3€€&€z€€€€€€€p€ϒ€|€€€€€rųq€€N€€€4€ +€P€€r€|8€€€€)€/F€t€TZa€g; €€O€€€€€€_€€€€f€€Bw€څ8Ì€O€€€~€`Y€,H*I€r€e€b€6$-€'€€€€€H€€g€%w€€€{H€€€4€,hB73€ܯ[€3€€㈹P\€€€8€|€€€wu€€€ YN€€€][€`€r€&€A€€€€€€<9_3€Tf€€8€€n-€€%HF(€#€€€€y0€2€€
cacm.auxs.texs.€€€€€€$€€€€TEXTMPS €m5€m5€}s€€-QÝ‘/€€€€=~€€~€€Ya_€€€€€€€€€2- €H€€€€€€W€È}€€o@f€=€€}€C€€€€?€€f€€€€€€o1#€€€}h)€B€~f"_N€€€€€€€;€€€8toi€ABd€qÌ€J€€€€€A€€€
€€}€€P€C€O€"€€€€€+€€€€AoNs€p€€ €€€€€[
€€@€€€ܙ>€YB€\_Vf/€€e€€Ⱦl€€€€ev€€A0€">&€ldcY#rgfOl€"€/"€€v€E>€€Y"€€~Oz€t€p€l@>6;h@€€€€€w-€= +q€€€)vc€€E0€|€9kx€€€€7€€g€€€r€Am/A€hí±O€`×–`€~9;s"7лK€v$€
B€5h@G€J€€€€€€€
cacm.texs.texs€b€€€€€$€€€€TEXTMPS €m5€m5_€#€oT€€€O€€€maw}N-?€€'崫€<€€€Rr|e€€KO9€€€€€u€|€€€@€€}€s€~€Y€€d!€€€B&€€l2€da€)€€€駽€0L€€€€€€€€€x1
€"€€€€€Q€€O€QÜ€S?€€€€88
€€I?€€#)€i€(€o2€€ 9˧€Q€gaYo€
€€€€a€€€4€€,€€Qâ°Â€ß€€ €€>€€€€€C?€€G€€0NG<€€?¬á±j€€ҤȂ^€'€a€zw}{}€€€€n6€€€€{€€l€€€€b€f€/€l$€W€0'€Σ€[€^€€€Gc,€€€0é…ΗY€€€4€€N€€a€G€(€YƜ€`€e€'€€q€|€{€€gvl€€w€^5€/€s€3€'€€€€€€€€€€<€Or€€ʀ€€€€€E€€<€€€€€t€€€€€€,Lf€N/€/€^?<€€€_€~7}€€€ߘv^€€Ŵ3€€q€€o/å·³0K€€7ny>€€g€€:€€€lf_€t<€€€E€߬>€€€ӻ€€#€€e€0€€p?€y%€€Ar €r€9I€"I€€Չ +€7€qr~N€€€e€r€€C`6J€Q€€€€o &€€̸0_€C€݇$;€
€€€€€6€4pT€€[€ii€€€€Ǥ_€G,€€€
W€€G47€€€|65P|€€~€€€€V:14D€€V:€€€e€N7€€V€`€08E€x€a"J€$€c€€E€€€=€€€p-€€;%T(€
Gq€
€"͂€€€€Q€€"M€€?I3€ke
X8:€€€~?€FYz€€€/:=L€€€p€€WI€i€€€€€€€€€e€€€lS€€€:€€€t€€€/€afA€f
€|€€9M€€C€v€/Q€€qn€YLF8M€€€€qo€€€€{€2?€˸D<€cf€€€yT€M€€€)~ +Ty€€€>w€2,€{€€w€F€€€'€M€H€kZ€€r'€€€x€€64Wi +nZ€H€o€€€€€€
†܇\@=)€€€€€€€A€€(€Ga/:€pX^d€^1€p2 *€€€€€€€€$€xv€€[1V^l€€b/xDqÐq€€€€€8h€€€M€€€UÛœd€€€{€3€€G€€v €€€€$€€€S€€€€€^€€€3€GQ€2J€'€€ vMUnA/J. ؀€;€€€€a€(€n!€vx>€€ +€m€€€y€€A€w€8 € 6€€}€S'f€ی€W#0€Hn€6€~€{F4€€@€7LI€€0l€€€€@€€€[ބ€€XR€[€@6€€y€€€€3€ci€€(@}€Ņ9€!€#q€€d3\?€€O€€€€€€G€ÂA^€€€d{€I€€€R €€€€G€@€sr€^Þ°8€ €.€€€ɉs€€%€€€€@€€€€C4*€}€€A/€€€€A}
2€Q +€p€€€€$€ X€€€€pOd€ї€€€€2€€w€€U'A^-€l€€€=$y€€€€€€€€yhV&€€€](€€p€i€€€€ǵ€h€11€@A€€€€€€VO)n€€*€|-(€7`q
|€vm€ܘ€H€O€O€g€€(€€D€.€s €€€d€ €ao€€?>€€F€€€€mA€pHT8ҌJ€€B€3€€Y4€€€€U€U€€€: +€€A$€€c€€q€€O€€B€€GK€S`€@|€€}P€$€)w€zZx€€€€JO€ 7]_€€€{V"€⯕,€\Y+€
!5€D€€>e8€€G7o8€b€,j€0 +2`€h€o'€€b€=T€€€y€€γ€€€h€J>€*r0€@€9€"€
€€#€~€€h€4:€Ƽ€€t2%€<&$va€QFe€€€f€€€€€+€=!€€€MU€v€€€@€G`€< +€ϛ€rq^0€€€€€€X`d)7€€`€€Um€%€N]€€H€7d€€a6€€f8I 2€€€-[€€€€€p2!<€sNNpsz€€€闊9€€€!1 +€@€€q€<on€y€<€!€€€iz€€6€n€J€+€"€ f€€{뀀€€Fss}
~v€u€Ǯn€7€€€5z€g!l)LX_€6~1€€5€€€€€e€"€&€ag€€2€.€]_€€)€€€€+€ٿ€0€€€e€[
€%€VÛ€€€€֖{€€€€*7€€€€n€€€ͻo€(€Wî›Â€1€C6€€[|~€]€€PB€ö€€t€ed€€€e€€€}_€€}a€#€€€€€€€€N€€€€€€€跗8# +€LgC;€&€,€(Y%nÇ…Z~€€€;€€]K€€C8€u €F~€\]a€€x\€
N€€{€×€uT€€€€W€€$Vr[AC€€C€<€D8€N€€gNYWb€V€€€€!€€TQ7v5+€€4€€€€E۵€€{P"9_&\Ty€Q3_'€€G߃€€€€€:€ף€€rrҫ€D1Wj€6€0':€z€€€€Y€z&€5€€?€N€€€€€n€6?p €ÄQ€M{€€_Uz€€€R\€€~€O€W€€€€€&X€€€€€V€:€€€-!€€€€€€€ql€OZ"1&€€^€€L€lÖº}[€€T6tp€fe0,€€€s€€€!€hU€€$s\€^Ѕ€€€€€Ї€€yFE`er€€€G<]€w€?€N€X€€.€€€p€€_€n€€€06%€€€$f€€€+<€€€€€r€€ç2P€`E^€p€€KS€€3€€€I€€?/'^€5€:€€€€ €R€€€€€G€#'€€
€€€€€#€4€JH€'€€€€n:.€€€€€€€€€€€a€8MND(€Dk<€8
1IZd€_€ё\€€:N8€1vpb%!€*DÆ£Q€€€ \>€{C€€r€€Xt<)€7€g€-€€€€a€Њ=tr{s}€BG[€€?ڿ€;€8€)A€C~€€€€4€~€k€€€nX€3€€€€€€€+€€A€€€㵤€}A?+Ɋ€FÙ!€Z`e€€€€m€€€€s€€*O€|€€,2€E€€€6`€€[kb +mmU&Y{€€H€N€UD?YX€€9Bc€yiN€€l€o€€€NcELPE€€€€€€€€צ€r€€€M€€€PC€ꊅP€]S€€€s€/€€cr9€6€h€€€€0€u:F€f€|€€€€€jÂ€Â€Â€Ô [€D€[?w(€€€€v*qD€€24€71sç©$€'!̹{Z.?€€€4€€]_€€€€€€P€v8m?"€ €€€€)€€€€b€€€€€€;€lT€€5€€€€/W€€€€€'e:€ +€r€€€f€€€nn€€+€€u€€€-€€͵)€€֕^oG€€\b€w_€A€€?€n<SB6€€€.€€€}€€€€€(x€?-#N€֛X€€Xи€€~€€€€€€€€€€]€€€r€8€?€€2-€_Ia€g[€€¦€?€€€€q€?€€€€v^€o€€€€1tUEe€K3q!€@€g€ߥ€gb€€~€9€&R€E€€~€a7<€CJ€N€!d<+€.Ư35€M€1€L.€€q +€b€€"€
€o€ €)€(€R8€€#€ x€€\€€€n€€€f}1€€€ꘅ€ ƚ€€րDL.€e8€{€y€ 9}7jB€ CA38(€̇AA€M
€2€€€€€€X€D
{;*€AY€€W€€]€€€X€€x€€ִ^1^€€€€€€w€€€D~ji€€€8€ /5€l€€F>€€€€€€€€€€€€€€2€V€eÈ°Ä€€:€A€€€h€v5 +fr€Óq€r|\€€€<<`Qd€\€€€€€€sC"H|€€'€€E€€?:8<€€I€€Ү€Ԙ!9Ag€€€€|€€€€Κ€€€E€PVDž€,i€OHjG€€=€S€€a€×z€€s€m€P`d€€Nb€€rG8€ +€#`€€€@€€ .€!c!€}€ţǟ~€€Q€OO=€€™^€V:€€€.€€V€HR€€!€€€p€-€E€€€€CM€%€7No<Z̀€A€€€;€€€€€a€€€€D€€Ίt€b'c@€c8€>€€ €€€"U€~_%M€p€G€XR€0a2h€€l€GB€€yIө€€€9#z€€$€5L€[€z€€€€€%h€€€€l{?4|R€€€R€€€€€€ +€€€$€€!€ao€€€€€€0€€2€oV€€u€€nlm€€;w€\1N€j/€€€€€-€U€€€r€j苽€€€€€€€€€€€;z€jS\€€(T€€0€Q€&f( €Д7€€€_€x€€5€€€€C€€€€€:€€€'€€.[I€i€,€x(€€b€_k*ؖ€€Ćuޕ€-3€Km€€į4€€€:€€)H +€Z€pu€€€€4€€€i€m€€>€f€P€ {"€€€€€q(€J€€|€f€€Y€P€€r`€€Pvn€€€,OE0\RX ch@€€€€3U€€€uf9€€Q0c€D€€W€€IvT€€&€#n1}€ Ô›0€€€y€JtD€€I€€€€€€X€€ul€)
AK€#|€€€ P2€ql€_-€€U]O€Y€€€G8€6€XS U€#€€bL€€€€€4
ت€1€€M€H€("€€€€€˵€R€u€€c€€}hW€€A?#€"J€8|%€S€€$€H€€B€€?D€€("bO€€N^€.6G€€€j1ۇ€o€€€[€n=€€€+i"3Y|€J€6!€€F€€€E€*€€€€<€€€€wxwdiî“»H€€A€S€€€vQ€€"%€€ €)€€€€€v€€a€€€U€€ +€€€€€€a!€€€4€€R€\y€L€€€€dr€)~1€€P€€r€€€$H€[€[€€ +u€€€X€P"UÛ…X 'A(h€k CJåšštW€Çn€S€x€€/, €-€C€€€€€O#L%€S€€€(29M€€€ €€€€€€]€$T€F<A€€O!Op€49€-€€€€zʈD€y]€&€d1€#Ԏ€€€<D
€ y\'€h +:aN€€Ñ€€cc%=€J€C€Sz€1€N€€€Z€€2u!€™qx€Qf€€ A€Utr€€TE/€€j€W€J€€ €€€}€€U€"Z€?c€#€i€€€;Q€€lW€€R€€p(/A€LhN€€á†Â€Â€Ö…6@€Yy€,(€€€€\€p%%€€€ʫh€2k€r€€€>€ €+,^€€˾€€€]€€€€€T€€*3€5D%` /=€€Q€€Jk€Ҹ€B€C€X€€+€Ĝ>K€€D€€hY€X€€FGdn{€€Ѕ€€Cpۀ2!3\,x €d€€€_)YAe€>`€€€€€Z€`M€€€D€G€Q€€€:E€€€V€T€€€€€-=€€[€€Ï4+n€€€]€€€€`€€€X€*s.€R€€+€€€€/жt€{8€a€€YsOy~玴€€€€=S€ €v€€€o€j€€€€Ƽ€)€€ €€€_€€I€Z€€€cV€#H€€€€s€o€Z€€€yoo€3O€€€u€6€€*€o€€s)€€An€€3€|F€€€ɷ€2€b€ €‰:$€vO€:G€€
a€€€€P€€0€3€)$b€€€€qkC€€€t>€֘€DR€€€ħW.€€€€€(#€€_€€€;=|€€€€H€€€>|€€9€<€0€(~k€€G|€#JV^€S€H2_4€€bO€V+9Z+m€2€€€€v€€€€ܶ3€€€€]€€€R€€~€€ €€*€€.€€€€€I€U€F€€€€€GXJ€€(=T€€n€€F)-A$€Htj*€€ +€€€?X\o€€2(ەTZ>@o€€s€€€€'N€h€bْ€l€€€f巌 %ކ€}\€€€€4{i{€\D€€€9Āto€€€€€L€~€ޞ€/€ N€+€€Ԩ€y€€€B€Q€€$€€€ .€ €€€M€€o€€kY€P€v€c:€V3:€ +€R.€.(v€€edj€€\€g€€€j€€€€€€D€€ €€€€€ €zKoi€€€hl#Y€H€€€€€€€€€N€€€€<€€,MX€u[€T€€h9I;ۛ$€€€e{€€€8"€0D攖Z€3.D€€€h€€D€€ż€$vl€z]€u\€€€*]€€€€€€€)R€`(1I%€Ҍ€N€€#P€€€L€€€b€#v8€Hs€4=X6€€€X|ׅa€€A.€/€Ԩ€€Zqf€X=kKQ€€€myoV7rFM)q€J|ʅ€nHU€€&€aP€_€J€€V!9€bcKT€€€€38I +€€€bxƄ_€€5m€€E&`V 7€p +€€"-€Ë}
€XnuAR"!.€fj€€+f€€F1€€a€€€ğ€c€€95€SN6€T€€x$Tr€d9€€€€€€0Ȓ€€€€€91€r€)Yx€€`€@€€iQ!€€Y|€B€ +€€}/€€€D Zՙ€h€]€d€b€€Cc€3J$€%U(]€?c€Z€4€={€Ya€90€f
€€€e€€€U/8€X\*=d0€i€€€<G~Y€€€i€"€fOe/€2'€/€€W€Y€r€vĀT;€€€v€-€9>F">€€€€;€ €€€€€ٷZ€^!€€€U€€"€`€€€0€€W€€€r€€€3€€€€€€€}X€€€€€T€b,€^€€aU€€T€€-}|€€!l€€f€5€€€€֚M€€€€^€=(€€€€KN€"€€€€€€58€€0€€€€R(€zH€[€19 T€0€C\€€ކ€~=@€ҵ€€5€}.€(€€K>SS€€A*K
€€€@€€0€€€€"P€€€t€H€E€€~/€8.G:€ރU1T€ߚ€€€€€€€X +€€Y€K|€€€€ly€€€€(T:E€€€€#W6tY%€€W?€€a€€€€€€€t)R€€€>€t,€e",w/€€nkNM€T$€t€6(€€kO{!€€€€€€c€ +€ao@€`+€€!h€€t.€€€€€l(b€I4y€€€s€<N€€(€u€€€;€=€€€€€U€€W#+€d?€€€"=DÊ”M€€;€%Ï©o€϶F€}*€€4€[€]€-+:€€€*€E; €M€N€,€€LtAz +,€h/€€ʅ€+d!/Z€'74f€€€ W€€G€€/ջ€Ⱦ€€3€T€K9J€€€€^€€k€[€o€€€€.2€€R%ӌ€I€€€e6%€$€F€€n€€€€€€KpM€€S€€6+€Q1 +X02€€4€€-€€€,I€Q€€€€F€g~[8äš…U€€€4€€u€€e€€€4q{€€€€Æ€6€9D!h€€k|€B€S€=€k1€€€€€€€m€€v€€€̤€€€x€{€55€€€15€h⢺Q€€5<IR€€€€,€€.Ì‹!É„Aj&€€€KV€€K€]€€€(T€€,€7€€€€?P€€€C9€€c€€q&€jHD€€2€€€€I€€e€G€cK츨€Df€Fr€x€O€P€€_5€€I€€_Ý¨Â€á …G€N€Ҕ€€͉)|3~߂€€€P=€6€€?€H€ii€ly€j€€€PeÕ¬*U€ռ€€€€€€Yx€h->M z€€ 2€P€€€€&€nx€€X€€yl€€^xn!=€0€€O 0ql€<€€€+ӊ€€ €€.€C€€€€€€€<k€€lo€€€s€+€€\€r€€~ €t€€j€€€€€Z€€3€q€aQq€)j€€Q.€g]€€€&€€€€p€€6€€V€(wxu€€€€€€@€(Ȣ֪€ €]11"€a$€ྨprb€€€Ój:D29€€€€€€PQ€€%_€€€€€€ti8دR€€€€€`E€J€@\~€8Ö_Io€€u1€€€'€€€€ϰ€€€€͜n€€€€3€#€+€[€€€x€€-€\€€~c\€€€€t$T€<92e.*€€€€€[bV]k\€€zV€^B€€>€€f€߲R€€3€[d€€Ge€€;t€Ҧ€€
Ro€€Cï–L>H€€€J€,€&?€N€€R€€V€G[}€L€.H€\<#€€ʽ/€€q€€€€€q€€Z$€rN€€€XbC€^€a€ +~m€3€€ €€W€=`{€€d€€Ж|€€(€€€-€U€€€€€€€€/qc€€:€€€€! €€꫰€ײ€L€\_N€ު€€&t8€€€[€۶7€€V€zuN€€j€€k€€%€A€€€.€€zn€;€€ Â€Â€Â€Â€í·¾Â€Â€Â€Ó£7€~&€{€c,I€€€€ܧ€L€a2€ÍaV;€€€VV€€7u⦂{ €X€€€'€`€€bI8bKq€€€€€€Oaծ€€q!€u€.b€€y€w€m€€N€€d€[(=€€t€T€€
€GM€€%x€6C€1͖)S€€€€E€€"€#€f€€€€xg €€(€€LB€€|€L3€€€€ly€7€I€/L6€d€jW4€&€z -?€l
Q€€€l>q1€o€lq€€5FC€€-€)E€[€€ €MBHI7€ +)€.&Mj€Ch€€€€€j€€Kp,€E0€€|€%>€ +€b(€€8€d[w`S?VxknB€€
€h€€Z€€nJ€e€&€l€€T€€;>v€€€؅K€k€K)'d1€€8€€5€€€l€€ +D€Ϳv€€€I €P€€€€€{Q€g,u€م€#€€@€€€n€€€€€U€€€€!q€€ÐU€P€Gx€€6€)v>€(€; €v€9,-€€}€M,USb€5 +!€€7G €€€€ ey€€J€0€€€EfMZY"€9E€€2^€€5 €€€€€€?€Y$€})€€€€€F€€€€T܎€5ֆ€cX};.€€h€€Zw@€€9Op€€€5€6€€P€€ +6€€€€i`€o9B€€€€€€€8€f€$€€€€€S|€€<Q€€ +€€€W_€P#w8€/ϯͱ}€€o?Y€€l+€]HY€+€;\€€€bж2w€€y5€€#€€€€€€€F<€vٰ€€€€.?€€|€€€€z-€€M*€€€y€ +€qJ€K6€Q€2€€€€_€€€@x€)t€€€€€€nKsg€€(€€6€.ZC€€h:tZ€+~€€€€€€W$€1(€)€€€S€€€y`€€q€ŤMl€€_€€€K€€€j€yی€€!€€€€p€"K$krf>€€U€P2'€d€€€T€€€€€€l€@V€oЂ€€€€8€€€ k€€€€€:€u€€N€g€€€€€€€q[€4 $Ù°`!€!l€€jR€1P-€€TlcR€G€€€Y€=€€C€eノ€T>€#€{8€&mjU ]€5^-€~€*F€p€˞UÜ Â€WĎ€€€e€\€grq€€}:€p€&€€€€€€€€S€€€f€g€€I€7€€€€€/y€b€€€€€€€eˇ€f€?€|€wO€€€€[HuL€€]€H|€€€l6€n€€p€€Æ€€na€l€k7Q€~=€^zÀ€3€€k€€Y€€€3€€€€T<€K$€€%€)€€׻}€€€€9˽€
|€€€€M€€€f€ݮ€Az€ع€€€€€€9€x€;€#j-~€>Y€€}€4!eD4€k|€€O€€(9€€n[€€€€€€4€v
-€€Y€c€€€:€L€€€s€€€€/€€€s$x€€M€) +€€)tXy}€€mno)€ €[€€]€€€€€€!€R}€€6€_G€@+€~€€€O$€€B€€€€€x€J€|'Ч€ €€€B€]#€€@}AX€ €?JO€s&Gu€€€#€€m6Öˆ{€€?€€€€ |{/€w€4E€€`€€>~€€€€€€!?3€€€€€€€€€€b€@€y€€€fs€€€€1€€€1€€^€€ѳ€Ð€䯷€M[€%€€€€S€€
DESCRIPTIONexso€€€`€$€€€€TEXTMPS €m5€m5M-H€€XN)y€r€<€€ѓw€l2€d€€M€[€€€c€€€(€G6y€z€€ğ€:€€€-A?Z€€€+N€<r€€€ddm€^€€€Ϯ€€6€€n€€€`u€ݤ^€I€~€l€€&€€€~€€h€€Z€€€D€€€%O€€c>\&€€;o:€Ƥ€~€q€€ou +€€C€9€€-ߨ€Ў€€y€ҳ€€m€j€€=€T€€€fp€€€€tp€ޙ6i€Z€€€J€-F1€€€{€€€3~?€€€€€€€I€8M)€€€€€€€€€3€H€€re€€€'݄€€f?R€€€H(>Q€vt]€$7€]€zÝšk}{€€_€P€/.€€J€֦€>€toi€A€€€p/ë£Â€z]€€€q€€vV€€ԇ1€]€€i:'d€€ €€€k€€€€'Gů$€€€$€U€~€L/O€€AR€€Æ€€€€€€€7€€o€z0€€€qG$j€€g€€x꫋€^X€8€€€(€G4€€€€€€ €Q5ap6]^€€_,.!€€€y€€5j㺣€€'€€-6€&€€€8I%4€€€&€€€UK_€;J€€kFZ€€€a€€€€q€(€€€ھ?€1eØ¢;€€X€n€0fgM#<€€€ _qH€€n€}?X$€ŕQi-€€ >h2*g褿b%€U€O€€€€
J€€;€€x€€€€€€€>€€€€€€€Q€g?v€Q€€u€z€€A€€D€€0€€S€^€€Uu€T +€.>KZ€€׾€Ɩ1€€U€€5€9€j
€€M>h€C)g<€O€€€€f€€&€4€C€Je€€%&h€sH}@€/€$€€TU:€< €€dd€€Ww€€E€€€€€€€V€€€O€€-€€f€€V€€M€<€J€A7 €)€)€"€€€|€n€€F]€V€€`t€X|€€€€€€€€۟Pa(€B€̊h%\€?€€b%YW€€ROl|€6€€AD)€€;€8 €V!do֛€€]€tJ€€C@€Nh/€€0Y€€xf€€€€€€Gn€5€€X€€€k€v€€V"
€D€pn;M€€]€5 V"p€P.~€u€L€yn€€[€€t ۉx€|%€7cr€€m€€€P€ȄE:€~€€€€€ +M€i€8€Pk€㻠€:€m€'Nޤ<€PX€Y]€Z5€)€;'g!B€€€z€_€€裉€扦€€€€€€€ +€'/€`P€Z€€!X€x€€€Wf€R€€€€Е3>€€D€€DY€€€Eqo&€€€€€€€€"h€7€X€zs@h[|€€€y!(€#j€ e%#€#€6U€€ҽ{€€€rY€4K€:€q€€%€Qߋյb€ë€__1~b"8&€i€€g€€(~€€ˮ€7€€(DN€€€€€€F€4k€€€tb€€€%U€€JB€€€€€N€€€6€KղRR<€̯y€Ӄ^w€€€t€€!€€€€;€€€€&€€€Np€,O€D€r€€€A€xFlRl€€@i^P0€€€€d€?€€y즥€€޼€o€€ݼu€€;€€€€€€€r€a<O€_€T€€€€€ͶE€@€€€€Mn€€€|
€Kǰ€X"€)€GA€K€€ +Õ€€
H€i€€€g€ADhǽ€v€IH€€@€€€€l€50€ B€€Kp€€o€òJ€€€€%€nR×€KI€W€€*Y€€€€€ϫeW€€T€xfE
€€9€,`€€ +,M€€€€€€€€€'€€~N€€t€€,=€sԞ€€€€R€D€€u€i8€Ӆ€qۚ€€%€€€€€€€=-€c€€€€r.J€Up€€Q€ €€[TΜ)€€€€€€€€€€el
XZ€€€SX)ƪ€3€€#>N€xq€E{tE€€€€€€€€€€$€Ou€t€€€€9€€€€s€8€Ù€€sT€<€€VN€ €€€€€€€€Ǥ<-€2q1€€€€€̥si€b€€€€l;^3Ydu€.|1€€/€€9€€ +t€€€€L€€T€ €€€€
sZˀ€-€22€€d€€€€€€€€J=€*e\€€ԙ€sI€€€"€X€€€€€€^€Sq fe€€P€b€A€qȨ€
€S€C8€€€?€€€! €€€€€€[x€€€€TY€@€p€~s€€_6e(€€€€H€€€
,
€v€Q_€_€€€€/€€D€€ve€€j:€€IΓ€€€€b€€€q€€Y€€€€.€d€€€2€Ixb€€ €2y+€`;€€€b€€=€€J€€?>WN~€x{€-J€N€€MakefileIONexs +€€€€€€$€€€€TEXTMPS €m5€m5P€€€clean:
-rm -f *.dvi *.log *~
overview.auxxs]€€`€\€$€€€€TEXTMPS €m5€m5€€۞€DQÝ‘/€€€€=~€€~€€€€/[de€HT€0kВ€€€mÐ}È}r€L€€€€€2€R_$[€€€€I€+QDh€?€€€gЀ€a€€€ĕ€!_€0€€€€€€€€€€€!€€€€]+€€€8€€1€|a3@€€€P6H€€ǀ€€V€
P€€iz €€€€€€€€€€€€€d%M€ʽ}€€€€A€
€€€€€@€h €{€{܎€€€7€€gk|l!€€€T>€€ݡ€€€€Z€€;€<A.Ln|€€
overview.texxs€3€€€€€$€€€€TEXTMPS €m5€m5€ +€€n€S€€ €€&€€€€z*;;€LV€€€h€. €€"€F€€€€0€o€€€€d€€€@]€u]€b[€€€h€€A€€;0€o€€Ö3€E€€€€c9m€3€JU€€€€ȟ€€€€B{€\€€c€mfT€^|#_Z9ղ€:€3€€€€Ô€€€^Úªhq€{|\Z€€€p€T€€j €€rf +-'?=€€€€€?€€€2,€€€€U€€q:ÖµB\€6kJ|€C[€_G€:€Y+LVè¸&z=€€
Z€€m€T€€+iʺ€t€5K;€€€€€G68€€€€n}€€€€ߞ€f€€€O€€€J€€€:d€€€vk€€€)s]€€f€€o€zn€ug>(Õ¥f€€j€XM}p*€€g P€€Î*KS€€ByD+€f€€€€€ +€€)2€_€€-˦2€€€€€€€€€€€"€€€Gݞ€ [€N +k€͞}&€€N€€€.(€S€€?}€)b&`€)€-€ r€€fM€€ +V€2€€€|2>€t€=€€€ѹ^€€€€L^bhϟ€>|€b3€€€A*€V9€€€€3u€ou€€BU€F€!€€€€€€v€€€€a€€€€]€€€FŜ€J€h/€&€€€M€€€€€€€-$€€Ue€€%m€€9€ v6xN€8W9€€€l€€D0€€D€Gcn€X€€€€RS€k€-J€€T|3{€lcG€BI€€J€€€j€€/P€€B€€€€€€i€€€q#€J€€€€€;€€€Rr€€€]]€€dH€B[_€ԿlȾ€Ð€€€T€t€w%€€?€€€F€[NMá©ž(vQåžÂ€Â€Â€Â€Â€\+€€9€LV€%1Qu€€~"N€€€Vi€o€VS€AF\€Ý€€€€а€P€LTVz;+€€k€€\w-b€€€
€€$}j€€€ +,s8€€€X+€€€€€€#€€X€€€€€@€€Q0N€%€ +€€€€Ʀ€Py€€€1;E€.5€his33H#€€€€€\P€ӥ]€€D€€€ +G€]€'€€€€\€/4{5*R€€9€€€q€€_€ O>€.€€mD,€€r€€€€#xySʼnSP€€€€€L€m€2
€9€h.$;u€Vvr€+ʃ€aE€W>&€€W%'W€*€€€r>€€€€€€t€N€w€vFW€€E€*€}`"€€€"U€€€€€€_€E^"4r\€m1,€€€-K|€€c€y€€u€5€€ɕ€j|P=€€€C€€Y'd€€ޢ€€8€5€=~ €tOQ€(Y€2€€2O€€€D;9€8(@M€[€$€€€€€MBE€G€K€-€K4€€s€€€w +u€€9[ʲ)€!€€€xy€€E€€(€€DHcjQ€2!€€r€߫%u€x€€qDY€€€b€l€r€G€D€x€€€€€h€€G
€$,€ƽ€t€b€€>M€ܟ€€€€€€€T>€=€o>E€)U€SD€"€€ReΒ{€€w€€J€9€€€y€qh€"&€€ޤ€ €=€qaP€€€€v€€w€€:€€€€€€D8€+%_=;€%.-€€€€1Q#$€* +q€
€€r:y€€ +€O€t€h€-€RU`Z€Q€€뽡!€I€]€zư€€€€€€%Ji>€o.€Q€€q€€€FoBtkv2€€f€€€€€€€4€€ €<$€€€€€€&€2€.€",#€€€yJ€E€ 7D€q €€€€P€€€€€€€€\€LFXcpa€XI€€€(0€€€V€ܹ€5
€€c€€€€a-€€€€€u^€ :hʃ,PKkhJa€€D > +€€€€€€=1&~€€h€A€€€€I$€€€u€T€€P€€v€€- k€€*s€"Xq€€Po€RH€Ff€.ƀO€€€€€€ I€€ufJ€€P€€€7€€€w[.H€/B€y€M€€]g€€€€€€px€uu)K@€y€7T€B€֦€R€kC+ 寅
€5€€€€5€G.€kH€h€€€g€€€N?€€€€€0€€€€0H+€254*sb]€Y€m€€=€w€q€€:€€-€x€>_€0€t€€€!I.€Q€€p€TA€QÚ“ +€C€€€€<pb€€èœza€d<€fG€€€%€€ €"€d&0B[;@7€€K€wn€`J=€€hx馾€˫€€F€~B€€8€l'€€€€€€ޡә€AKpYGߒ€\€L€i€€€(€€~W(6O€;BOԷ€€€€{?€€€€T€€vƒ+3DnS€€1€€e€€)€€GK€€€€]`€€bD€K€€W€€DO€E€€B€€瘺€c€{ì°ˆhJ€€€€-`€&oS€€jxo€€<41€€€€8#€F€€€€TAQL};Xe€€Q€O3⻄€€1j#€xg€€S€€BS€€€€€B€1€€€-€€fAD€:;€"€8lwi&.€:€<€yQ)€€€€\€R€€€v€v€"fe€€€ykbiT€f€€€€,€l€€Q€@€u€€€€UͿ€€€vP€Ь<€€€€€i€€€€x€€
€o€E
K}G€€€j#V)€€. <€@*€-$€Q€€6€€8€€Ü€€€ӻ +€€€^<@€€)€€PUD€,€byx€€ttÖ¡c€]€€€Hoa8A€Ή€1J€(€1€b€€Z€L€]€€€€€7:€4€L\€€@€€€€گ4€E€R€BM
€€_
|N€k€_€€NW€C€€kk҉€bU@€€€€€€)€/m€€l€b0$€^€€€Ϫ€z€^^€=dD€S~}€]€€{O€O€€=€>€€~{€€€c+DA޺€n€€}}€€(Lg€€€ɽ€€€T€€.€>0€€€€€€€€€n€€G€€ȓ€€ݕ€€€pxpt€€€??€::x€€'"€[€G{€€ +€€?€€€€€€ €€€€€ Š€€€d€€€€G€€€€p8€v€€{ut€f€€A€€]€€m€€$Ѵ€Ƨ>€0Oe€S€€€€V€€€€Qt€€€€€€Dt€&€g`b€p K[€€'{2€;€K€€€€Ci€Q&C€€€+# +€C€N9ծ;5€€߇{€€€€}l)€}€}_€
spiderman.auxsQ€€\€z€$€€€€TEXTMPS €m5€m5€A€€€e€€d€€4€€€w€ sÒ€p€p€€ՓǓ€€€/B€b€€x€'€G,P€€8€€€€€E€€!'CN耓cyk€€;€d€€€#-€€N€ €€€>6eok€€@+€€€€y€L€*€N€€xB€ţ€€=MH€€ ɓ€€É€d€4€€€M€€€2€€ d€€€P€€€x€M€€g€r€u€€€€€NÂœb€€€;r€€T⾩ז(ZaS€ʋ€T ]€€-~b'b€T€0€€`€ǃFH€€~}€€€€3<€D€€€€:€|v€MU,5€€€<€UF€o€€m€€€/=$D}X 8€€€€€€€U€€V€€d€/Û½[€€€o€€%D€€€ +€c€_+€€h€sf?€€€@€€)€{6€€y[ #Ö±`€€€)€€5€/G€9i€nWP€>€€€N(€€€ҟ€`€€ӈ€B€€׎F$€2Q€€^€€€€`p,€GÂ€È S€i€b|€wO€€QU€€]€nG€€€<€!3jJ€s€y€)sKP3r9€)V9#Z€ +€u€>Q€"1€€Jo€€€€XL:6^€W%€€€€P}€€€€T€&̻€3€V€€s€,€=[Ís€€€)€€€€€oH€€I6€5-<n"€€1@-€€€€f\€€j€€€r€€€}€€q€€€FnU€a%€€L€€€€€n{ €€}a+|€ +€J€0€€€Ϫ;€XKp€€€€€%€"€t€€€El€iTfY_€€6€€0€€fdV€~F€o€€Y)3€E€€€^H>€€lA€€‚€fP€C€€z}€3b€€€€€呶r€€M€€€NE}€€€6(€€€<€€€p€Xp€<€ €€ԡ[€€€
€O+€€€
`A€J€y€€€€€q€ћ€4€€€O€€"€=€ط€?€-€C€m-€qce6ٯ€€?€5?Aa€t€~(€€ckZ€€XC€2K€€€D€4.}€€7rF€o€]]|<€v€€€€€N€€(p€>N€~€ʖ€(CD\€]€X€€c€?€~}:L€€€s€€€YmW€t€N€€ت€WXP€]΄v€ +€p€€€@#5Ÿ
T€€€€€.H:€t€v€#ld€C%€€€E$€o
€€€€E€:€Z€]€ͯo€€}0{W€€b€b\5€z[<€€€€€€N€4€€€<€€€€€€€€€€
spiderman.texsw€€8€$€€€€TEXTMPS €m5€m5€Q)€€
[N)y<A€BO€z€€c€€€8€n€ݦ€€r€O€Zۅ/O7=|€>€€€4€P€€O €€ +€u]_€€G+r€#€€,Gn2\€€t€_ 2V€u€Es€€€Ygo֥€€e€[qr€€€]€€€€j€M¢€€€€}€]v
\€€€H€dC2€€%Tu€€€€€€8Q€A&Z€k€€3:€€8€€€?€€€€8€o€T€I0€i€€g2u€-:R€€슞NDR€€'€Ne*t€Q€€x€€)T€:€~€t€*R)EO€Rl}€€€€ Þ€€€€€(]€€ €€€A€Xu%€g-€W€b€€€€c€€B€€Z€3€€]€4r€€€!Z€f€P€o€€€t€'€ +BY8^*€@€Q&€I*€(ve€
€€S€ݓ€@€€€€K€Q€_€[€o€€W€€€Q?€ހ€€JC€€€€^¯^,n€€Ot7dZ€€/^lL€€B€q€]€€€€Ԫ€€n€€€F2€,F^0€€€€€ѵs€€D€.€€O€=€f€€€ØC€€r€)&mÞœc€.€I=€9>€€I€
t2€€€[޶€€€€€u'b7α'€v€dH€;Bw2ӑx€K€€*€€M\€G€€€€oI7€€€€n€M1€xY&€€1€€.€*€€k€z€€€€€€1€€€€^€€€㱳€#?€€o#€mܕ€2€1€E€6N€i&€4:€*%(m€€€?€€€Z€€€€€€~€ +€€€€€€€&{€€&€p€€:n:f€c€€€gB€€€€C€€.€a€€€€;<€€XP<€€€E*€€€€f0€]€€/€R€€Ǝq€ͩ€€qWUz€3€ܧ{€=€G€)\€€1:€ί9{€Y€€€0e€h€€€8€€XI€*.€o6€[€oˡMWfg€€u€b)|€€G€€€€€&€&€€2€hU€€€€۰€"S€€Ď€ْ€€€€}i€€5r€c€֪€€3€€€€l€ +€€€q=€€€i€€^6€€M€8€8D-€m€€€€Nv1€@N€€€€z€K€€U€V€€€_€€€€D€ڞ€$,€
n€ƪ3€9€€_.€n€€€€€€Y€A€W€€€€€€gEq>€{ +€€)€W€€€@€%5€€€0u€€€ Aws€€C?€ˬ:f€j€€X€#€w€€u€€€ ]€€p€B@f€€* €€€\€€€)€€€€€€€ow€€>9€~€NĦL€D€<:€€r^€€€Nu€€O€8€ܰɼej-€€€pFe[k€ygV=€9[€4Ml€€€p€€€€€|+€€/€˫X&€6€€l€€]1€OGT&€€o€}€€€^€€€#Gb€IOqf?$t€€€€€€L€€! €€€=€f€l€€c€€p€akN€N€€@+€€€>c;j€-€d€€[€[€#€ΨBa€N€€€ €€€€`}€b€€|€€€€ڲ€€€€}?€€€Q€€€06q€i€鯊€sT€€G€e\€€i9v€Y€€7€m€€z€v€y€p='؃€€€Ql€O€v€€€C#€€€€€.6€[€€€u€€Pݘ6€yH€r€<@€€L€R[qp€€<€€E€€s€vxZ€€€€€€`ZbE€6ʆ€€uŪ:`€€€a€u@€€€€€€A€)€€=€€€€<O€€€. €€yp€€€|€€€|€€R€P€€€|€€R€€l€ F€9€5€;€:l€€0€G€®€ma€€€€€U€€N:^€€€€r€F€€€`€€€d€€€€ɔ€:2€rt? puG€€€e{€x[€€>€€vW€N€ʨ€+8(DU(€€€€.<d€€€€'ķ€yV=v€i€V€€€y`€€€#Y€\D€8€€S€€€@!€€
d€bI5@€€!€€"€€6€€€€}€/€€n€€lx€(.€a€€€y€Z(`€€€KQ€*€€!]#€5€v€€€)€€€€C€€]@€h€€€8vþbsƪn]€cqQ€}dc€Ap€€€€€€€nc€)`t +@3q\r]€€€€3€J€€€€€€t€€f^€YA€c€g€N}€S€€€/6€W€Y€€€<%<9€ΰ_l€€€gE€€W€€€m€€€.J€€€Xo€K4€t€€Fy€€€+€€;5G€b€l,€€_p(€€n]€€€blu€O€QXXȫ7€€
lC€#1"€iX€€AB€€€Ųng3Q€€€:€e€€€Lwp,G€€8€€€ڵ€€€€u€€5€€€€€€€€€€_(L'€.€8SC€€€|nJ€Ů€€€z}€\€L€€€€€}0€1€€v€€& Q€€€€NGRp{€F€=4y×°hk€€€€€t}wè’‡q€€L€€o€C€€ €r€/d€r€$€ N€P€)€N!v€Se€Wv#J€€W€{l €٨€eP'€?ro€㼀/9^O€€ؚ<2€z€€ +b €4H€€h݉€€:IÈ€"<€€ +$€)-€7€;€`8€€<€:$X]€€#€€€_€€?€€€€r€w€€€€x<€8n\€€%߀€€€~~!hY€€ €/€€~€€€1!€€5€'K/€5ř€Ϸ€€T€]€€hmr€€€€%€3Ù¼-Ë›/€e[€€€€€€y6€€~@O€lp#8€L€€8y€ +€€€€€}€'€€nyXP €€ €€$`o €€€͌$?€9€€€ € X[€€"€€€€€1€+~8€(g€4€v€0€@`€€€€>€L€FUޗ€€€ˡ3?*7"€€€#€82€€X€€?€€`Xpk€'€€W€€eJpO€(^l€€€l€€xp€€€(€`€N€y}€€Õ€€€f€|€€Ve^€56€€ɽ:P€$I€$`€v€€€€€€؂=0€€€€Pp€#>€€€€€€ټ€€6R€jD€ +$5€!n€V|€8j€<\MpHb€€[!€€€+€€€€q!v:(€r€bU€lÔ騎€€JÒF߸€W€P€e€€/€€Z€€€€V€€XM€.€PIJ€€6€Ţ\€ € ws€'2€#€€€a;d€.€e€"€€€E€€€€€::€Ԙ1-€€€€€ܟ€€->~Ø‹@,€l8€€|€s"€hf^7_$€8€€]€€>?€r_š€€6€A] +`€>HM€€€`€€
5Q€€€€€€-!6€aM€%G€€Æ$/ͦ€W€g€J#p€€ts€S€k€ǡ+(D€4j$uH€l€€ʓ€€€Yoq€6p2G€€€€€5€€€€֧ƮT€€UTFV€€€q€:€€Qٜ€€€eg+:€u€€1a€˺Ó€e€€+€8€I€€0€€?b~€€F€€€€C€€6€€g7€PS€V€7R€€€€€y€€"`D€,@MX+€ۂ+€€€%€€mT]ST€€€P€S€v€€`€€['i7€u€€€€€8€€!q€€€^M!€€|F€.€€
?%€€€"€€[Sa[]G€€€&l€€1€#h.€€k€&€6'^€A€€It€€a€€€€€€A€€j€€㩸€D€€€€x`€M(e_€€%€€|Q€ǃ:{
€€€0x€ԢT€€€ËR +€1€*K€€€€`Ó~T#€K€€I€H€€(€S€t€€<€.o€€ЇK€€€s€€€$*€€€€t/€€\F$D`€Zi€€€€`€€n€q9€€€6,Â€Â€Â€Â€Â€Â€Ö Â€Â€!€€€€€€q?y€8€€?€LhV€€€F,s&€€J€€XeK€^\0& '€€€,€€M€C€€קDu.W€€1€zB(€6DmrS€€€€J€@㨷[€€€€€€ĮNx€’€€+€€J€€Ú€€6Ph€€{€{€€RÜ Â€9€€€M€
€<bQ6€€€(i܂€g0€o€€€hx€ +<€dɔ=@€€K€€€€€[€€Y€€€€€@f€€h[€8€€zoT€€le€n€ O;€S€:€#€€q9K!2€4€n€€P
€$,€ bB
#€jr€N€€€€5g_€K@€H€€€^E,€M€c€€€N€€*2[€€ڻ€€L€€hv?€O€€€€€oO€M€N@I€€€ۢ煲€*t^U'€-€L€€ny|€#€qh€ýŲ€€?€c^€€€€€€?b€D€€w€ޘ€Ö€K€€€]€€€xW€€€T€e€€€ +{€_€€Ҵ€€€€Z€€:€€€€€Z€€R€€]×€€€€$€]€U€Ԩu<€u0€€ʇ€€o€€€^€p€€€ۯj€€q€€l€€׺€P€€_€€€€€ֈ€€€OY\€€Z€u0<ŋ€
€€u€X€€€€€6,€€€€[€€€'1$Т:€&€?y€€€€9€ 晼05€€U4_€$|1€)@U€€€J€lE/w€5hf0€€o€€€€?€p(
|€>1Nu2b€^H€دaBFhC€o€€€$€€(p€8€"€€€|€F€0€u0/m€€J€)GrƉ€Yla€XZN€)€`€€€€€€€]€l€€Qh+%[€g€€$n€€w%NŞJ€€ܰ8 €3sq€€€Hp€€€€g€8G!€u€ez€b€:€Xʑ{Ф€;€ŋ€€o€€€T鉓€&€€€€€€€€€€€€€#€€ +1 +u€€V€"BOe€€7WC€€eL€€€€€uG€€5€N€€n€t€€9€q&€€€€@-€€"€€€€@€cjZ;T€S€b€:€R~@€$€
c!X€+€wÛ%€ €]€€9€€U€t€$€=8n<€;yp€I€Jm€Š€|€ Q€€€€€l€\€\€€€FE€|U9€€b€B€uW€yj€`€€)-/f€iNF€-€€€gu€€t€€{€0y€ipTb€€闳r7€€n
4€Z}€€Ihn€4<R€€M€#E€)9Ùƒ/€€qQ€€}€/3H€pT€€€9h€7€cHS1`1@€€d€&€d€!€I€ٟ1€€R8H€3€€€ǵ€€å¦gϼ€€I€€iTkBv€yC€€€-.@€] 2€`C€€>'€F$€€ZBJ.€QǪ€€6o€€^€€€€^€ȋ€€Z€) €€;e:€ €r€€€€E€€u€€€€€€€{?h€€s€q@X€€A€SÙŸTe!h€€€~}6€€€€€€#€N€€€'C€€€Iv[€q€€€y?}€m€€€Ś€€€€€€€€W€)IP€€ƿ€E(€€€^€߹€€r€€€j,,€Pn€€€R€l9ߟ8˺€€€.€€^€dÈ€2雺€rc€E€€€€K€€l€L]€€€€+€€f€x€€V€€€€€g€`€€*u€qͷ€X@€€€<€€W€€€€P +
{P€€€IT4€f€Co€Y;.€-ʋe€€E}€j€€ל€q€€{€€€€€ۢ€
€t؟€x€ǫ€@Ri\/@€d€˼€8€SJ@€€ {€[!€]€
*€€€E€dXK; €%€€O€€€€3€€ €€6€€AmX€m€t€ b€6€,$€p€тã€Han2€Qj€zÀK€€€€€€ +€€€֘6€€\€Yu€3€€n7{€ .*H€€€[M!€M€ˢ€€€€L€€:€ €€€€€C1€€€YU€K€€ i89€€-€€€€€X7€€€€o)€E€72€€ݹ1#I€t€ˈ€€€€D€+€(:€Cw€Y8% +€Q€7$€€€YW€ €U€€€€€K2r€€Up€r!j
€€`b€[!(€b€ˀ"UG€"'€\€}€z€Q0#€T€'~NR€€,d€€(!€j€€4€do|€Ԫ€€L€€€€a€2k<€m€€Ţ^€€€hæeCw!€€Y€z€€U€|€$ V€ly€€,w€\H€€_H€€q€p8Q3€€€mЪ€{€\
€B8
×°U€=€€€݆€S€\R€M>X€S€€ +€u€5€€x€j7B/€€€!€€嵶€€p̱€O€€ʄ€ٸ€@C3€€€*H€€€€€4€€€ €€廻€€Y<€_Lg€ft€Vj€€€€€(€€&M€€€€k€€u(ɾï¯Â€%€€)€€P€€€x€€€6(kN€6€p-€J€€|}7
6€€€$€€q€€{€€-t€€€€迡;€€€O€ȻD€€€J€o€^gA,€l€€€€@`2€ю€€€S€€5€€-n€€2€U €fh€€e€U\l€W
\€€Xv€€€Q€€"€uI@%€
p€€-{€Ne?CV€6€€F€ €Q:€ɪ7$,€€Ø€@iuM€€€1€€€€€U€€ΒX€€€€P€€oDI€/Z€(Xk€c€ €Z€€e,z €%€€€Kq€p,TT5€y]I€]<€z03`9€bZ€€€m€€€€I€/G€+hx0@H€€€€L€€€&€W€v€€8€[gv€@:Qç„Š_€e`€€m€€֯U[€8€:€k-€€H:€€;€|€8€K€V€d€r€! +€€€€AÒŒQ€€}LJW+€+€Z€h2+€€€%⟷€€^€€€/b€_€€ކ€"&€a?]€€S€Z€iT€€@€€x€'|€g€hÛ€€ €€
€ +
#<s€€b€€b€sèžœb€*€€]€€€8€.x2€5€€&y€€€€Toa€€€€N~€€€G65€=i€€€v€n€-$E€€€€€E#`*€\Y€^r€~€€€_Z€4€€€ €[gpS€d€ܢڎ€€€€€Մ€€€€%€xYr€€€€~LO€"1=5€;€€ +€2ؕ€iA)€m*€€€:K,}1<_F9€-€(€€€€2€€€€€€qD€0€Y֚€A€€[{>€€€€8€€i;€3€€b€E€€ '3€€@( €€€€€€€€6n€#€b€D€€€d€v€BS™€€€€€]€€€€&$X>€€w€€:€i€€"€ €؅ €€€AR€(1دS|'0€€B€€50j6€€#€W1w̹V€^€k€€0s,€St`€<H푾)€_€`€€_(€€€옥€+€#€{sko€P€@€€€sO€€u`v"€6=:€€€}€pW€€q5€€€€8€€}€€€SyF€€ €;€€y9€l€|€€u€!yY€g€ ++€€€9€€€c€`\€€+%w€€€€€€€{€Y_€€ +€€€€€€_€r€ B€€3€€€€€€6€€€€6q€و€€kOc€z€€€€€€€€€N€l€€U€^€m€|5€w€€€۪€€€€€%€€€%€€€€€Q€€€)€€€*%€€€.$€€€€€€€€K€€€*'b€-€Ã€€2€€v;€_Y!y€€€-€33,€€|€<Mje€€€u3€€te€?€K€B$ES!*!€!Q€€ €€€2€<€€€a€€0€5€8t€@p€ҹϕ€€€-€`€V€€ǯV^VT%%€€€e€€M€pN=€€6€R€0€?€B&$g;eK€€€€F€€5€€4€€€8-€uO€\€<€€ۑ€FaZ€8€P€€€€€€EL€€€€€G=€0iz€€€u€$/€f€y€€f€A€PX€c€€z€<€€Zk€z€f.!€-VB&€'€[€€w€€a€QtUo-€€r€€Ⱥ€Shh€€XHR€€€V€€O%€€$€hi3€$K4€€4€€€\€Y€€sM€G€;@i'g€€
€€€Q€€B€W( €€B€€€Õ€8E&|€€€€K€€C€€€€S€x€€€[€€€€3lJ+;Úœ{€d@€{€6€$€€€€C€u€Cy0i€€€€€cш€ߨ€R€h€€ q€€€*€€H|€€€W€?€€U€€€a€‹+8 +!t€@zʬ€€@l€R3€€"=Ŝ€LוC€J€WO#P€€€y€€€€W€€€€:q€€€€€J€eN€ʼԡ€+Cǎ€€A€€w!€€€+€€U€<81€€F"€€E€€6€刴€€€݅N€w y€€Z€g€€€V€3g€€€sQ€-Õ€ Nkŷ€%€%OX€€Tr€=
yB€8€€€Fe8W€$€E€Q€€€X€ŎO€€€0T€€u/T묱&q'+€€€€o€€0GKT€!(r€I+€a€€;@€€l€€>:€f€;<€€€h€€I€€€€AZ€߅€€~€R€€ +0€€s3€@€€€n€€,€€€o€€€8€€€wj€QF€€/€€MȲ€c>ۈ 4[€Fk^€؃€d*s€€€€€w€t€€€€~€w€€€€=€\Äp€Qpi€3?€€^€€iMpЀ€€=€D€€Ѱ*€A€/€Jch€o€€€E€€€€€€€B'€\Z€€€€€€€€Qb4€€K
M€€o€€s€€€]€€2 €€€€€€€€ugItB€€€I+€3€bdGc%^€_jwG 3.+€溌€€€€;=€€€4€&€€€€ã %€l?~7€E€€€€€x€ڈËͧ?€€€€€€i€€€€5€€€€€?€~€o€ĩ€€U€`€F€5€ԥT-€ĩ€€€€o€€€鮞ً€,$D€g,Ö <m<6€g€Q c4€€€€2!u€M€lS3t€€€€€€G€€
TGc
ήP€€;;3_€6?€a€B4dfR€€G€+€€Iyn€3€€:v€€€€€?3€0€€F€^€^6Ѐ€€/€n€€€È7€€>€€p€ӎ€€€€€]€€rs€t€€#v€€ )9g€UKK_€X€|€Dt7s€,a€/ €X€JJ€J€6€€(€€GJ€€€;7€\@^€€€€8€€€€iQ€€€y,€4Q€IA€€ +€~,€€€k|3€ Y€:€€€%€€€s8€€€€€=NO€€€T€€€€F€€€
i*€i,€.gq€€€خ€€€Y€q€€€ W€b€N€ €6S€€€€rXk€€€ +,€G€C€€wM€8€P€#€€ɚ€I€€€K€;v€€-€€(=BH`M0€at€€W€€€*T:€€€G m-5€€d2€-:By€f€yTu€(€uf€(L€h€Åb
м8۵L€0S€€€L€-v]C€€€5{€€p€€€€j€€€€€V€,Tӂ€?€C€€x€€€€€€€2€wn€N€\€€€<€€%|€l6€€2€€€€78.€€€€~!r9€€1Ǯ;zġ€T€F€€C€E€I€n0€<€€ +oGss@,€€€€pƑ€€]/{€,€€€'(€€€*€pD€p1€G€€+m€WM€€€M€‹j€€€&#€€3€€SwT€$€€9W€J€Kް(l€*€€€W€€vy€€Myb€€€€D€€'M€z€€1€€€€€EZl€cx€%6€&f€8€€<€€€€€€€-€€€!5)Rq€|€W€€"t€€IN€€€€€€4€HJq€€€;€€a{H€€m €€Q€.P;€€€€W€FB0€7€€Ym€
o€€€S.w?€€€€€€a€"€5y€XH>sg€€€)€€@{J€€€W€€2KD€€K:WOڗ€
e4€q0€L€Ќ€€ €€€q€tR€€€€`w(€Uo€ +€B€€€€€€]€€€<€€:E;Z_€d€€2€€h€€R€RÉ®W€€nsL€€6-R€f€€€€3€€€tm"€€޸@ØžTk€€€X€A€ €€€pH€€/€Μ8€O€zN€€8+#€€€€€€€l€Cv(€w~€O€€Cmّ€€€BN€QmÚ€€ҵGSI=€My<€ €{<€љ^v9€€€€`€€€€€€€Ap5€€P€=€€€<€gP€O/1€[€h€€€~€O€=€*€c€€€€€cm!€׬€€€A€€€€€€€€€€:Ì Â€Â€_€€€bQZ€€€€€ZF€€nF8€€0A€e[guf€€~<i€5€€€€t€+€fO +€€~€€W€P€€Xq€€€€7u€€+\o2€€€*€@%€€€€g€eY€€€?€y#€x€
€Q€€=;€Ъ€€[€€@€yT"g'戜€€79LB€C8€€ +€r>€€€€€$h€C€f€U€nOS壣T€Ncm€€Y€z̰€€6+€X€€b€€B€€Bѥ€8€q€0ml€B€€>&%3r€€D€€€€€y€€]+9€€€€p€€P€y€€j€
€W€€g€Z€€€€e܀8~€ln!g\€€yrN€€€€
;뜃)X€?€€ +ɧ€€'€€װ/€€€#o€n!"€€€€m[€€€k€€BÖ€n€y€Z€'€€€u4€?€€€€-K€DjY~7€€€€_ €€E4€Xx"€€{O_€€€q] +>H€€€€€;€€€€PKN€'€€#5€[[;€&€€鬨€€
€/2€€€€WzG€˨€qr€€€€€€`€€SYB€rN€€4T +53
€ywr€€€ €€3/€A€2B8[)€€%?Ke€€€c{€hL€€<EO€p€.€1€€%€6€€h€uz€Q€u€Hs4W€XdUC8(€€XD€€€€{€€[€€+w€:€BD€
c\€{€€€€€€€uu€F9`€CK€€Hgx€€gLh€[€€%€W€€y +-€J€F€<€/€I€rxSJ€€x €€;;€€f€?€€€€€4€e€€€€fP€Ex€)€€g€€~€€€2`€i€!€ +€-€€I€€€€U€€2€F{7€€%|l<
€€Yj€^€€!"€y€€€€€*€D€]€€wW.€€€R€€y4+ +€€6€)€GpF€€€,_€€veA7€5€€ݫ€,I€€Ϯ€€);€€€€pI5D@ÜŽ.€€)€€N,€CM€T€Z€€€€€€€z€vg€)CM€u€€{ׄe€€kW!6€€€L€€C€€€$€YD€€/qpL&€M€pQ€g€€Da-€$€€v€o€@8=€€€€€€ڒx€€D€€€Ö€€3d&€%€cR€6&€(>Ú¨J"€3€!Y€€€'€€€Í€cSH€€+m€€€€€€€֥€€cÜ¿0@/Y€€N4€Cã°†!€€_€pg'c{|;€&€Ke€.€€€€,U€€I€€€tS€€€[€#I€"€€Yw€T€?€€€^€€€=€:€€-⼤XU€€o,ʆ'€s€"°B€ە1€€€€)M€f€4€€€€)jE.p€€q]€€R€Ȏ€R€Ec(€F!€€Y€V€€r€.€€$2(€€€C2S%Rm%k€j€€m€€€€f[ZBUp€€,Fva€nf€zQ€Η1€{€€€T0
€€S€€€4s+c-€#.€g%€€€€€lU)+rΡr€3€E€€.€€€€€€€Z€!€/€9€2?€/€€€{ +€V€€b9€€1€78v€a €€€€€o€€€t€€i€€B€C€8€€1€€76L\€O`q~€€^E€€X€€J€ +y €+€hC€?%€€ €€€€€€E^BM€k€€0w€€€K€"|f&H|?€/Ɖ _€€€q€€€€€€€а€€vݯ.€D€OOz=t€>€g€H€=€€€€^€€€y€#€€€l€€€y66È€€I5€Y€€€ϜJR€l€p&€€€J€ؤ€w€€€€€=M€t€ÛhV%r€j€ 1€jo€€"€€'€!€:€€€€Ȱ€€&€€B W8w€/€C€€2€^€:× Â€Â€//Ч€€€6€€€x€1€aG@-€¿€pU€
€€€€€€€€€dpDV€€€€€€€W€[1VzÄ€0j€n}€\_€~€€€b=€v€3S€붸€€<€!ī€€P€€€*Cdo€€€"€€€f€€'U€@€U€€.€$|€%º@)#€H€f"
€@HNY€p€ +wD€u€Ƙ€"n€€g€QSraڑޫ€€RڔEL€Z€€€€b€€ƾ?ݿ€!€)N€€p€€€€€€'€€€€€€0€ +B<€W€h9&€u€€/W6Z€€€€€$€€]€Lڸes€€€€€€3€€€0€/€!€€,€€ZH€€€뜽k€€z?]€€b€
€r€€k€€Ͷy€(€#€€€[F €€€ã¸Â€Â€Â€Â€xun€€€€€€8€,@€€y€|€4€€€€0V|
€V€(€B€/€v€€dء€ҩ€€B€RR€s`m€7kH€€€€€S aY\`1€$€€€€ +)€"€VO€€€€Ҽb€€\€c€!€€.€TF€ +7u€g0€€\€€0€€F€€Ǝ€A€€m€€€€€€€€ˎ€€€€€€jsB€€€€€c8`@<mC€€€€€*€€€€U€€i€$8/€r_€}€€€€€€;€'€(€3€€€€5\Ø &€€€Ί€v€c€€;S€€jp€C>)u€€IÔ¹W)휧=€€€su€O€€_€g€~E0€1@€G^€€oRO€€€€z33Ë€€€G€k€€yN€:€;€€IfY€v€€Ԁ€',m=€€1€7j€€€E€€&2r.€)g€F&9_€€ +€IK#Å·Ë›^€€€€E)N7€Z!k€f€€€€€S€.EK€XA€H)€€€΅€}€g€€DWk€€2€€2€€-B€x€€R +€€C@€€€€xo€xk€€"KvS€€G€g€€€€€rI€ €y. €_€d€b€.K€€€ +5z€€\€-9€j7€=Ɖ^€€€€OE*Q0Wt€Y€i)Ü€€€L7€€€€€UՒ€/J€<€i"€d0€€,€aÞ€J€JKOI€€€€€9€o\)2;€€ıפ€€
7€t€€6€€€ɣ8MKܶ€WD€L€Y€<€€z7 x4O€€€€€,€€€]€n +%€m?Am€€7€~€듥p€X8€4€N€€1'+€€€-,LV€€B€Q€€€€€€.€d~D€8mJ€€7B€XK;€iWY%€€(€€#€€€€-€|K€€x€l€€€f€€,iKF%Aƙ)€€€€€T€}0€€€G"€y€3%<€(hgd€€€€€P€W€q2€€€€hX€"€€N€€=€n€€L€_x
€€k*u€€€3€€€עYk€€i0dd&€€;€dAG€€3€b€€z€R€€k€>€b€€€€Ȫ€^€€y€Y€r9\€)'€€€dg€^€c>VB€Xk€€lW€€;€kb€C€ +&€€€̙љ€ €€€€€qv€€€€ydm-k€€€̪€€€e>
-€FI€€€Jқ€{€€`;€€]€€€€V€€€.e€€R€€€€€€e~€qm€€€ȀF€)W€€w€€€
€.A€>€a€€€€€ee€€y€€€Xi€€ +@€~ÂŒu€€€€c€h=]€\€/x€€€]€€€€N!€ 4Uu@!€€€€$bÆZ 4€ً€€M€8q€9WA?$€M€€t€€Ja€€€€€€^€€€6y€€AN€$a€€€€€€€<€€2€ͅS€8eh€€€{€A€ €o^,)€OD€6€+€€€U€/€€RiG€VX€"Q€v€€€Izh€PhÞ›nMQ€€b€€€0f-€R9€E€,^€;€؋C€bn€€€n€b€€e@ّ€c€vtA€€O€FbX€€pA€Oi€€€{€Y€€L€X€€0€X*0€B@€€€:€Y€R€ €%zUҸ€i€T€Z9
*€€4V€€€€€(A€€€€€ €€€fE€m€B€>€€€€€€€d€~€€F\~€b€€€€wY€ܪ€Ƅ€H€€€É€€€€€M€:€€€E€܂.€.i6WÈœi^€#eg€€€oYr€€bjA€KdE3\€K€bir€€€+'€€J*Jf€€.€W€€€€€€€6€̱P€€W€h€X<3Z€€*€€hiCÍ”A.€€€L(€)€€`€]5€€E€HS€€<@9YrK&P9A2V€€6Ï•+€€€€'€4€€/it`~€€€€€"¾€H€€]€€€X€€:?€€€€€€€pqG!€<€”€€€`€€€€\€i=€€€€€4€€V€,€€|h€€€€€[€B€A€€.j7! (€€€|€A-J€o€€]€€€϶€)-€_€€k€€b€€€<€€€€/-€€$€€€€€€$€<"€u€€€€€F€€€€€€_#TG€a€€R€€€€f:'!|€"€€;€€€V€DS€€€C€@y€€€gs€€€€i€€V'€H€€€€€€€€€ 7€4s€€Nc€8€€!€K€€[€,€€€€ €€€€){3€€€Vfƅ€/€€€M€€€^xΎ€^øPB€|€€#W€Lj€€€6€X,CO€-n€€ɡI |€QD€€n| +I[€€qh€b€Z€€€€oy€€A€€$€€€€"€D€!Ag€ +f0€QR"yZ€€[€€€er8€€Bv€€~i€C-}Rw,8€l €P€u€€w€€€Z6€.€?mKp€€,o€F€F0€NH€V€-€€€Ë€47>q€1€€€ݾIEq€b€€€a€€'C€€|ޗ€€€L€99€6^7€€€Kv€€€7X€eÒ•~€q€P€€€€
€%€€€€€yh€u€S€۰L!c7 LV€y€Z€NƟaGɊ€p+€ؚ>?€€€w!€€€€|€~€€€€lw€V€
M€`J€W€€`-Zs]€u€G€€€nL€€m€€GJ€€e€MC8€k-€e€ru€€€ث9€6€l€#{€%€€€€€z€€A!O:€€€€€4_€wV€€€€€€EÙv€(€Y€T€€w€m=€w(+?b€޻-*f€€x€-€\€€€^€€€€Q€€M€-€fE櫄€€w!|~€€€€€NP€H]€F%€€€€;d€nDV*€%€P@€L9€N[€€y€H€€A €ٜ€sO€LCsjH/3€eF€€€GI€fx5€d1€|€[€&€€_r€%r€Ư€ۑl€€y\€€€Ւ€p~է€ ,€€€€€€/ÜŒ"A€€€€€s€€€€,€€q€&Ù²ui€,7€$€웘aP'o6€€i€
|€;€€€w€€€€u€€8 +€€"€=€ €€€€€n€B0€T€͕ €Ko€z€€€G€€V€€dJ]ä¹C€{ +€Қ,€€H]BQ€|K]€C€z€9€×݉d4€€€€ͤ€%O€-ti€Σ}X€€€ҋ€D€ԩ€€€3s'q$€€#€€€€€gpGVZ
, €€€NE€76*e€€ š%€!€3€€€Y€€€€1€# ؜€€ €o.€ >€wt<€€L€D.€€€€}>€€ €€[<€#]€5+€o€€P€*€€"€€€7k€"€6Ey€€€n:9BDmSZD€€ZA)€g-A€€€,€€€iF€Kv€$€oItH€€*€€98€7€`€€€M€%€bJ€€I€€€e͎€€€k€€В醀€'T€붴€€dg€r€€€€€€8€nk€€=V'B€
€€€
v€€€o€€€€Q€€<6€€%p€€N€€T€€!es€3i)X€3€€€t€€/€B9€€€€ֻixf.€?€A€T'€€F^i€€`ʈ#o€dm€€%C€€€Ȁ€%nM€}€h€€\|€$€€2$€€We,á©£d€Ym#€-:-€€s€s€Nн(€€€SzC€€{€N5S€€D€€-B€€€o€~€yJ1E€6€&€€€b€<G€€3€$€€€:€rE€€zīę€lR€€!1€5€€Z€€ r3€€€C€B_lr€€Kn)€%:€H?J€2~€o€I€>`€!€€ɜ2"€g€€€€€cy€€/€€{IS@cQ€3€h€eO€k<O€O€€qo€€%€€€€€NR€Q€ÄBת€E€€€ŵ€!S(€u€4€X3€€u€€*€€{€€€A&€€€=€€2f€g=€s€€€€€€|)`€€1-)€€7u€*€€ϓ+'bݺԳX~€€n€€€€€s€€dZXI€F€Z€rf€€€H€7I+€€wH€€€yW€@€D€€ €<r
f€m€F€€€€€^mO€ !s€zq@€€€€€€/€€€(2€G€]HN0€€h€€̤2Kh]€I€XV€A!}s<€€C€€€€@CD€€lp€€ļ€V€A€€€€Cl8€-Õ Â€Â€Â€Â€A-€ +€€I€<€hF€ €5€]€€€U€€€|€,€X€o€€€?X€€€ШӲ{€€+€€€# hH€€€b)Hs€€4*<F€€€€€€S€#€#€€€€,€̚€€v€d€]<€€Y2,=^ymqi€€€€o~k!&€€€#€€/Aa€#€y€g€€Y +€K€,mrV|>v€€€^€c€0€r/EOUI€o;€XR€Nv€/€Wr€*.€€
6+€€/€a€€€€H^g€€€€oU€#€-€)8f€€€€X{€€_€€^€€€€P€2€]€€f€N€€,€q€€€€€€€€܄€€€@il€€h€€€9,€:PIwã®Nl<€ +€kF€6€* 9€
T}H?€€]1€妇n€€€Z,€€€h€€€€Y€I€€4E€€WH€iZ€€€?€L€nX!! +€€q
`Ô†'€a$€X€泈€V€()€€+_m€<€€€p€×€j{€€€€€!/Y€€€H€XÔ³j€6P€Q€!7aq€y{€€Q€3€j€€j€8v€ј€€€
€^ؤ{€"ϓ€к|0€6€€!`uB€€p€€€]t€}€€v€€;€B€€€sfEۢ€z€@3€5€€%€€€€<€|€€)€€€€(Es€O;€a€€LfF0#€€€Zh€€nz[$\€€~€€€l
€:|m€€€5*€jC€€€;€Ƿ€€f€€)€€€oVwc V€A]q€€ݕſ€l€~aÌ”2€€€"w€ɉ6}NbJ|+m€€r€€ +€€Bs€€€q€6$mG$Uw€6€!€€€€€,p€.€€a€€㙪€;6|€Qj8q€€€"{X€^€€€€€?$Jl€@€Z€w€y€EkM€€ODk}€€E€7nN€€€€€€:€€€€x5€a#,€€€&!d7€€€€€(;€aM€€K€m€€€€Gv€€B(€€/$ +€€\|x€^€l€{ÞŽH€€=€:€B€€€"€€EP1q€€ €@r€€€o%€jx€€<€~u€€V=€€g/€€€€Vw€€#r€C€,;€f4ORG4€€{€€€€€e€€€ښ? €G€€€€€(€H€€1Pe +o€\)€€ʀ€€€€]?a€€€3 +€€BÉ®l€U€€]€€€Z*€€€€V€tÝ"=€€€€€€b<{xj €]A1€bU€€&€€#dA€€:€A€€Ai€€Ztd9㤌9€€€ⓩ-E^n[m}hr€€J€€€€m€Z€=€o€€€€Q€#7C€5.€K€'>€€,D€€€0€ȞQ€+€
€E€€€NH€€8€N}€€9q€€€€k5BiZ€€€€€€C€\€D5 €€Y5€̒r€#]€pvS-€L€y-€€L€}J€#€€ݦsq€€€3w€[ +=€X€H€gpgt€€|€€ћ&€z€€#€%€egT€t€s!€€=€€€€€.€€֩k€(€zr€€,1€€D€€€K2€P€€xT+,b< E€nÈ^ß%€V[3€€)[€€sԃ€Uc€r€m+€€]€`€&€€ G€*€a J€€€€€r€rÝœM€€€,€€€$pytOr€€oh€€€/€€€€€.€€&X~€€Ye€5€ݣ€€U€€€Ê€(€€€€=I€̨ €D€e€€€€G€xpJ @]€€€9€'€ZF'€,V€€€8€€V€€Q€㞲6€€€€E€Ť<€>€€€γ€€€˘Vm€WdWw[Æ„L€€€€5€€€€€€LwIhwN-Nqgf2€z€XH!zE`€nt{€€€€€lp€€€€€p]€€€Z Cg3€€€"E€c€J€0€B€%Oq5€?ÕºTR€2c7(`l€-l€€]€€€,€€€ +C>p0€€Sw€3pXp€€,>9KF€<€)€ź€S€4s€€)€€€ԌTt€€€O-€;€#€p€ᑾ;€€€HZZ€€€*
rb€€€_€€€€ +l]€)€L€K.€Bbx€€€5€k€€Q€€€yE€€*-€#€€€€€€^€P)M€€€$€€6€€€€€\€V€؇€€€€€€€VAŸ&¥€€wG€8€€;@:€RE€_€Tr€o€è´Â€so̴€1€€%%l€€€€€€8,€€€€G€€€$€mgC€X,€ʥ€-_)€}>€€€€€02IK~€$mÂ€Â€Þ *€€G€€#€iw€€€d€en8U€ +€.d€D +€7`€u9dE€*f€€€,I€,#sJ€S€]bLm@q€€k€S(hf€N/€QO5€z`€€€s€i€|P€#€f€€^€k€€€8 +€NȲԘe€R€ϯ1€b€€9€E€€€ż2€%Ӥ€t€軋U€€;€€B€5€$€€€&#€Ɏp]>V€€€€<0} 5€€€€€N€€YN€Ery€€€€€€}€E€V€€€€j€U€w,€0€€4€€a€Xr€€€€y=@€€€€6€<€>`!€€€€H€d€€Q~x€c[€?xO>B €(€€D€\űe€O€VS0v7KxX€oyg€€D+€€%#D;l €sR€M€wFY3€€€\ƈI€ėq€€€T€/€€€Q +Y€€r€)F<C€€=n€,€€ȣ=€r€€}€tB€]l€€€€€€3€O€B€,€e€€8€/€_€>€€€,K€+€y€€G{€;Ç·uS€Kl€`€ʽ
€€!€\€€€€|€x€Jv€̚€b€re€l~€€#›4€€sb€€c?8<€€:€aD€B9€€A)€S€V€€{€€€9€€FE€g焮1-€€€bJ€ )y€€N䑅€€*g
€L. +B#7/€€Î€ +p<M€S€€h€€t€€€€׿€€€3&C€€€Í€€€€€B€\w€€5€€€2€I€+€€nK€€[€oÆ•Â€Â€Â€Ò *€€`€,ZL€r€z€€€€€€€€Ð€n€€€€~€E€f€*€N"€G€*€@%€>X€€D€3€R€a€€€€c€›W€€L€%€_€,€€{>€~^€€ß8v€B<€€€ €Щ€€€|#€[%€r€f+N€€Ñm€֦€€€~€V€@€€€ץ€€:€€,€Jw]R€€q44nJ +*ᦌ*€€)Xa€€&€MVRb€€D€( €€€€'€€N €^)€€]$€<€/€-€Mo€€€ €€z{€€€P€q€€w€ +€>Ip!€CS€€t
-h€,€dx€"€€€B€)J€€€€g€}Ò¤o}€€€€I9s€€€€€€€€€€'€€(YZXXXb,K€€s€oG@€€€lE€ +€؋/€€U(€€9€| |v€/€€€€k €€€l€€l€qo€{€€€?€€€mo€€€;o€€ +€/€€€€€€C€€€w'€€F€n€€{€€OvU€7ա€6"€i_Â€× Â€Â€Â€F€€€€€Z€I`€€€.L €Lß©<:z€Zv€€Ϧ=€7€€-€^€W€€€€(zN€€€€€€€e€M€€€8€E€€)"5€€==Ԅ€q€C€€€€€€€\T€ɱA.7U€€€BC€€€€`*€D€€€€€03Ó—19€€ +F>}fjs€\€€Y +€ +€€€Чy€€Z€x€薣.€j€€9,€1€€€0€G€€&w€€oc_€X€N€VO€€^€0T/by/€-[€M€€vn[€€w€€d€{%€€6M€&€€!p€I€€a,€߅€qGX]^€3f€<>Q€€€ Q€;fLCs€l€)€ +€qÂ€Ö Â€Â€(€i, \€€s€€€C€8F€€dq€o€A€a€€€@MhF€€€cl€j€€€€€€€€f€€)€€0€ +€WP€L€€v€JA*€€7€{T3€YO€.€€€€)€€<€*€&× Òµcw€€h€e€€to€,€€€.~€€€€€€€€€oh4€€'f&kT€€>|€=eMÛ‚7f€r(O€ކ€€Yb€V{eV€*€€!n€€E€-€€&gÆ i€€€Z>€'€€*€+Se€€N+€€€€€8€€€€yO€€ Y€Y€€€€ԣ?6hD€y€€€€l€v€~b€Vpt€J€q€€$f€€RL€hd€€€€€0>ec j€€€~Ha€€€Ʉ€*€g€€€€i€€€€H€4q€€H€т€€€6€'€€wv;.€8€bi€€€x€2€C€€€€ze€€€KA€€€2€D€ڽ)€€€€Ջګ€€js€€€€€€€M€~€€€€/q€€€€7€€€€W€€L_€€€~^€€C€79€€€?€€€.r€7€o€€.A€Q}E€€e_/T;ܥ€€e€€€@€€€€d€€€€EM€(€€€MK€€(r€€€€mUZ€݄/.€€€€w€>€€Y€€€€s€ӽ€N€w€€€z€ €€-€-€€€z€]\Д€€ѧ^€],€€€c€'€Íg€0€€+€€ +uV€l€€€€IO€N€mWU€€€Ӣ€€و€€(,€y€H€ȚZq€Bc€€€~€?€€ +^€€w€o€G€€K€€b€
€€€€€€€Sx€l€€US€e€€ĘXg€@-5€€€m€5€%€€€€€*€2€m€€€€€Ô€;€NÚ -€€€€
h€W€€€€d)Ԁ!€€i€-LnB€€€€,€€^€UXn€€bq€€€S€h€€€"€€ɸ€=€€€F(€~H{b€€c€p€€€
ҟ€€€/€€€€€€t€€:h€€€€€€k€€ͦe€^;€=€y€€h€J|€-g€|€€^€C€€ +4€€€€N€€€FO€k€€€€\€ +€€€/?KR€€o€(€f€€€€y\€0]€h^@€JK€]Vt€€€t€%W|€@€K€+[:€€)€Kp€&€€0w€S€%€€€€€,f{€Y€€Ѷ$€a€€€=dg€€€$€G€J€€M€€"s€f`€v6€€)[€€^R€${€€€b€wj€€€€€€€€€5^€ €A~€c€-€€€fͰ}'€+€H€:͂W€€o2F€dV€; +I€€L€d€J€€N€€€€€€€R€߉€R€€)€x€€HƎ€€6€€€€€k€p}€€€€zh%€€0€€€€z€€€p€€ +O€`€€€n€€€_g€€€€;,€€€>€€€€(lس€go€€€€,€c€€€€x}ZiZVt€€€v$€€ p,€w€P€P€€€`7€€Y€b€€€3€M€~€Vl€J.€€ X€€€€€U€€€DXPP€En3?`€€€€3€,€r€€€3€5B1I€`€€€g€€](€€&sV€?{€͢8€bV€]€€€€䋥€€uxqs€€€€€e]€€,€{€ {R€€
€o€ܚ€/Q€4€€Qd€}€€€yޱ€ßB€€9€€€z€€€>D\]€€€8€*~€€€€€Kw€_z€€{€€€y€I1x€}€u€€€€0€=x€€A%u€€€€~U€G€㶧IKH€€'€€€*€djQ%s'D+€-v`Ԛ€k>€{R€€€x€€€,z?€€E€ǥ€€€€㨜€!~€€5[€€€e€}(€€-€€˲€€€m€€/LY€€O?z€€€G€€€€€O€€€k(€€ecǰ€*€€QJI€g€€€<€€3$L€€€@r€€€Hә€€&€€€€€€}F€V€>Ä°{8€€€€!€€M€X€€€m€T€-€S€€€€;`€V€€€€€€€€€€]€a€€>€
€ +€GÏ.€€ѧ€€€€€l~€€€V€ϧ€€€qE€€1^€€j€€#€>f€€€2€€€€€€Ii(5l€'€€ |€€[*€€€€€Øu€m€I€€€*?€\€€_sY€€€€€€_€^~€€€€€}€€€m5€J€€€T€€€€)/€w€€€#9€€K€%€€€<v9€q€4€E$€€j€€
€€q€I€oQ€€?€J€€̜0f€]€W€€€€€€€oGΔ€ja[€€€y:€ZI3ÈŸK +Ѳ€g'€'€H~€€€€€€€€€S€€€t;€€€w€€€T€€€'`a€€€,I€^6h€20@€{$€€€€[QpK€n_€€€⛟€€€&{€€At€W€€€a€€€€€>€€€yc€€€eC~€R€€x€͈€€€r€€e€€€^€€€"-€€3e*€{Tav€€Ķ ޶€â¦EǪ€€€!€€€€€€€xG€?€"€€b믊€*€z€2€€<s0F
€€€€Y€€{€m€€€€€€ש€6a€€€€#€€k_€N:€€U€€F€€7€€€6€-€ +G€€̒t€€€€r€€i€€€0€l€€€€1€€€/_h€'€€€€]€؇€ €€€%Ö€€K€}]€ € +W4€ɱ€Vb€€W-€€r€9€krO€ɇ&k(€€h-'€€€€€€\€cn%f€. +€ަ€€€€€€]d€]€C` €€€H€€9€€^€hr€€u€€€€€€}€Jf€€ã¦Â€ a€8*)€€2€mak€€~€4€ހ€€€€€€€Zu€€$ZRQ€|€)ԙ€0€€l€ +€€M€€8$€t€b€G€€}€}#€€Mؽm€€€€€J€p$€u€€€c€I9€€€+€}€€€€€〼[.n€$yB8€€€€<噵€€€€/€
€'€?€€u[€€[Ωm€L\€7"€€€|W^€€€W^Ú›*€TZ€S +nF€€ڈX€€*6mF€€1€€5€€€€7€€€€~f€€S€€€€07l€€€€h@q€€€Ņ€iXl€€€€€<€€9€73€€€s€€X€M8€€€k맓€?€Ic€€€1N€€ц€€7媨ִ€ND8€DpÂ€Â€Â€Â€× T@€€^D4J€”€/t€€!d€€8l€€€
spiderwebman.tex€.€z€p€$€€€€TEXTMPS €m5€m5€'€€mZ€N€x€€-€<9=o€vy€€€€€€~]€€€€~€€fx€€KO7€m€€€€d€h€껮€€€.㋑}€eBP€€'€(X 2€}€;€>€[€g€o€ȮQ.:€€€€€€c€€sK-Ԏ€€&'€G+Р€€€€{+n€€xd€,€x€A2€€XGU€Ѫ:€€w€{5€€€€€zw€€€€€D€€q€€m€€€]€€m'pl€?T€ €€€:€€€€€€9* +€€€€|€'€<€€€8€€&€;€€>€€|G€€€c€€7€T€€€Kw䨃€€€€€€€]|?€€€ھ3 €€€€~€€w€a€€i€€w€€g€V€oO€UϷ€9€ݞ€€~€c€
€?€€@€€:c€;lh€
€€€&€Mß‹&€5r€9#C€y€€×KË™D€sf€€};p,,㌩n-Ρ?€€-€X€7Ö¥;€/O€€€Y€€€u-€€cG€G
€y€Ӻ€€xnģǢ€€€s€N€|/€Z€€€=€;€Q€粡€€<wd€RV&€;€^€€€€€€8€)€€mOg+€€€4»€c€€€€ 3€€€W€Or€:€f\€SL|€€€ )€w€x€€€€C€w//€€€^Mp€€€€w€9€/€€K€€€€7:€€€€i€€€(P€4€€~V€M=€€€€€€D€ת€{7€€€€j&y€€68l`€€€Vv݉€€k€€€€€€ €a€€Njo€$XX€~-~€€87€€=€hӀ`€_;€So€€J>€w€€€€;€{q€€€C€/€€€P{€€€0€€€€€€_k€ܸ€L€€6€w2€Y€HYPqK€€ӗ €€=€€€[€r€€0€_#€€€€€€€P_€$€',€~€€#€G[€€€>€ͬ€€>€€€€€€€;9€€€|€ V$€€"€-€€€{€m| €€K€7€'€€?€9€€€]ƨ€€€aq2Z`O} €€€€EXc€€€€x€€€6&€(€˕€;€e€€€~€q'€€b€/L€€×q€€€€€k8pÑ3€€€Y79€€=pp;69€€€vß™x€aL€€M€$€€€?€€€€€_€€l€|€€u€9i6گ€€P€€Uc€N;€€zY?:€€€Aиn€€@€v@€€eAl[
€€S€R€t +r7I(€€€sK€€ €€€1€{€5€€uo€€j€€€€.~€a€€€p2u€*€>Õ?€€€:__Q5€€€€w߾€|k€€€€VP€R€€€€€€^hxl,6C€8€€€€b9€0oY€€c€€q€€jLJ5<€1Ϙ|€lo€€m€q€D€1€€ᡋ€€k€€do€€H€
€};€€~€8€w€>€t7F€€€^€€*U,€:€€€qƞ8€€€€_x7€€|€€€€€|€y€@}€d€€€hDa €€Ȫ& +€€€C(X€€p€W{€€€€€0€€€€G€6j +€Υ€s€X€B€c€€?€€Fɥ€€Kkk€K/9w€€€OƘ€€€v&x€€€1€<`]€€D€p
€€€€#€€-R€€€€\€u€{€S-€;€&q€€8€€C,€9ÂLp*€€:y€€€>6<€€€vGBÈ ]€mj#€€t€=€nx€:€ٵ€€€c58€€€0>€_€€€zǙ€j€3€€KÙ¼q:€€€ȋzE9€€€€€€€S{€€Y€V6€€€G€@€€/€€ose€€€€;€€g€ƜC6€ a€€å´Â€Â€Q<€€€€€q€€ +-€$€.R?
€€/P€€h€ +]€€€€dU 2€J€€€F€І€`ׅ€J(z€C>X@€€€€tM€€?TӃ€{QO€0>
€€~€€€€€€€€
€v:€.ʒ€'€€€€€h€€@$hV#€#€€~€€€€€ﰑ@€z{C=€
€"€_€G€€q€M€x€€}€€€o0€€|€€€€7q€T€€€Zx8€€€€w€@€€;?€€:€=€€D€W€€€h€€€€`tWU€sÞ¢UBÊ\€€€<€(€X_€€\€€MÑ„R#€€€]c€k€€€€€€n}Õ ps]€€€`€`€o€€ś€?€;=Æ!€€€€€€2€€ovS€€€€a€€:J€€€{^8€€€€<€€€=€€€N€q€€y=A€€€€u€ĩC€]0€x~€€€%M [ €€I€.€ALÕŽZp€ce0€^D倀€€€€b€€€8€€{€€€-9/s€b€€ +€g0€€€dP.W€4 f€O€€pJ€€R€€|€_8AX€€€;#
€€>€w€€€€|Ό€p€€ȹ€€F€€O€€AH€挳ٛ€{N€ʺup€mp1\€€€€`€€€€€€(€€޹€€F€€V/€I€4€€€V€€€€" eSs€€€€€€€L0€
€इ€€{€U$€€d€'X€€Ap€<€;€:5€€)1€€1€/€ݱo]*€€€€€{€(€p€5Gc€RH€€€[€€$1&p€€; €@€=B€€#€&€$€E€"hc€p€|€ €€}€€<€Q +dN€`€
5'€
€€€€ИT%Qz7€A€N€!€#€'€{€ܚ€eR€€?€€$€A҃€€€UM" €E€Þ€€€<€€x€[€€]%u€tx€€€€€€Y€2<€€W€;€€m|b€€a€€b€€B€ш8€d€/€ +€€ڋ€€u€g€€>€€|f€€\S
€0€€ }€TI€!^€>€"€€€;mp€a€p€X€€]€5€f€€€€%€€;dUDN €I28€€k€€€W€*€'v'€,€L€€ݼVZ€~>ć$R€€F€€K€€GAz€€€I<}€€ *_ܮ€j€€€€€€€€€L€€k€RԢ€€€4A=€€€W€€>nn€€€€€€O Hm{€€€€€a(v€2o€Lr€Z€B>™a)W€€K€€\€Tّ3€7€€€€`.€G.o€€€€N €ӇZw8€t€`€qq (ζ8uݽا€€€€5€€€€€,€€l€BI€vQ=€dW€F€€€€"a|€€€€€+€€€€8€€€c€€€€€^S)t€K€€€K€:%X€:<U[€€7€Z€€f€€_ǯ<z€vI2@b€#€&€€
€^}n)€€F€€x9$€>;Ι€€.t€€€6M"'!€'€~€]`P0 +€€Xwf€H€€g€#€€€€€€€€5A€€J€€u€6b?€€X€€€€5J€М€E€w"H*€r€€€€€5€€S/€i€€€€€€€€1D€€=€S"€€€E€€2R*b€€|€cX€€€€t€n X?€€€[6€ly€6w€/€€€€ €€o€PÕ¢Bu0Â€á £Ø¤Â€Â€Â€C€€€€€€€€ip€€M€€>< +€€€0€€€€$€B%€*.\^(€€h"€ €@€€Q€]€€€>€€9@€€X€$n€€€€(C€€Ύ
€€M(€b0€€/.9-@dB€€!N€2€€WN3€€5€€€׈€€;[€^€ch0€€R€o@€€€€€:x€z*€€€N€€00€€€9F€N€€€i€t€r€€€€€€€tÇ€€Ìa€€€Z€o@D€O€g€xx€€€K€͋"bh8€€€M.;€aN.€€[€€€?€=
g%€€N€€€€3€M€€a€{€@t8JÂ€Ä '€€s€?m5Nl€€€€€x€€€€ +€#(z€€€€jU€€'€>€€€€€€2np€€€€€r€€u{={Q%€€€-€W'€€€€`€y€;€3QQ€€€p€€€€€€€€1Ò§B€+=€A€€>F*€Fa€e€€n€€€;€€€њ$i]&€€4w"1€€€€޴€€~ڑ€e€€R €l€€€€>€p[hqi€€ €€v€I€€<C+&Ý¢&€Q€€z€Vrے€'M€€4€z€X6€z€[€/€*€€€€K.€€%€/2G4b$2€€€X€€€"€€U€+€€€€c€‰€€€€vhD€)Ô¸~P€€PÂ€Ö Â€m€RiCK€€^€€Y€L=€xɸ3-V€o€x:€H€B€€'@€%€)e€m€"€O€€€€€€1p€Y€F€€€!+Ō€C@€Fߎ1€\e€x'€k€Lzp€€C€€€€%€qkS€-j€&@€€f€€€a lM€€€€S€QSI€ϡ+€€€€8€€N€9€A'q#r€€€€`J€ƀs€€ʴ€l€.€([Xie€K€K>€s€D"€K%W€BL€€Zq€o7)x€€[€^€?Ǿn€S3€ €€€ПR€€€4PH€*=ܘ€hR€€€ؚ%€$€U?h]€€€€€,€`€€@€€A€6€ŗ€€;/ò€€_€U€€€€2€3€1€c€@w€Ո€€€€2P8€€&€UÓ @ß©4€€8[p€€Z:€€€€€€>p€€€€€.€M.€€2ґ€€s€h€€M}";€}?9yJ€€Tۂ€>}l€€€€ €€S€:€N€U€€R€-€AHP=€ Â}€98i0#€J€"^€&€Z€€€b€€€ €€€}€l1€€€€€€`€@€€€€€€# +€€€€ۑ"€Z\8€€€€€€€AtäQN
N€@€%c€4€€€W€€w€€*e€€JF€A%ޯ;Δ€€€@€€€0€D€€x€€C€d€]K€8p]€€€r€1€€€€€Z*A€>кDX)D0yR}`€!o€€0€›€L +o €.@€€uѧ€ +€€€€€Ŕ€€A€9obQ~€€€€€€:€jL€
€(€<€%1€€kp€€€;V€€€X€€8046€€€N$€D€€€d<€F=€ +€ť€e€€u€zQ'\@€€>L€€D€€@Z€-@|[)€€GPM€€.€V +/€€€x€h؀#[€|w_ّ€A€€ €€s€<fQQ€2n逊€j€p€€"€OadL€ ]3€€€_u€$€€V%~ #F€Âxͱ_€€€ `€€€€/€.D€€H0<Ë…b€€>u€€€/ )bCi€€€V€'[r!0€}`€€
W V1.Vv€U€N€€>€jM€"€M€€;€€€€€R€€!€]€€€r€€s€uQ€€€€I€€A€€
€<€|G€ Ñ„u@&€p€Db€d€Kc€€`1_€c€€"€ݟ€€€#€€4€Î€€V€€%€y€5ZP€€łr]=˿€€€6€g€F€#€=d€ȣohH-€̜€&s€€i€U€݀€€z;<€€€k=€T€€€|€€.MSϿ€#y€+€€€€€/eߋ€po€P€M€€$"L^€€Nx5€8€€j€ƥ€€€ €ֻ€€ +€€€€kzI*€€€€€€Q€)€[€€!€9"m#zZB€!€n€s_€€€ €€€%€€€€\\<€F€MwMÕ Â€Â€Â€Â€Â€Â€Â€Â€G?t€€5€
@€€DXD€€b€€[€€ +*4€€€€].€€€4oM 7€e€bU#€C€~€X€5$O>€€€€3€€€€s€C€Yq€€€€€Z€A~€ PQ€fxRXH€ )7;1x€€dg۴O€Q€€tvL€€
*€€.€.€€€&€-TiA€!€€*ͫ€€€€€>€€€€€€€€HF€9€€BMI€€€k\€€(€€A€€P]€'q€€€v"€€W€€n€i€r€€€P€€€€aoV€€€€€`€*€€€€HkÌ©bU€H€€<€e€€€€€€-Å€€€€M] €Q"Ø‚V€H€-€€€n-€q蛔€@!€!€€1€€€⛳€H€€€€!Z€]Q€3€dw€PÂ€×³Â€Ý Â€Â€Â€kcF0@€€€€ޟ€3Q€L€|FD€'d!€o€x€€€€i€€€0€@€JBu€€€|0TS9CU€€9>€'|€J€}€jb€]€€€ݳG€€€zj|\€€1[€€Z@FP4€€€€X“G'v€5€€€€ys)Ù‚*[x€Q€€G@P€-€€.8€76€€€€€_Xd+{€+Q4€€€8€7p€P€€߷!€€€R\%€€]D€.P€DW€~R7 z€€G,€€+ǕŔ€#€€Ϋ €ނU€€o€m{!Ll̓€€B€#R€€€€.€(€€€˹p@€€w€D€€%a(€€w€€f,)€g€Rq€`Õ²(€t-€}€€̼€f€€€y€€wH{S€U€€€T:€I€€-€€€C€€Ù€j€€€€XEdQ€€esU5€qO0K€E€=l@€€o€ €1€{€€J|€G€€hgMO€€€-€€€€€€€?E€M"€€4=A€€€€€€v[|€m€€€.`€€]€ֶca€j H,€å¡"`€'A€3€€ÆV_w;€€€"
9€ƃ€€€€€€rZ€€€€€€շ€€J^||€€€€€d€NP€;€؆€f=z{ €€ G€$͗€€€džp€`€W€lI€€!%€€€€ *€€ܕ€€€z_€[€#€€€uY€䅅q€L/ȕ€€€€* Q`DP< +J~C€x€€z"@€X<€tBѵg€'€W€}W%€€€€€€€ €€€0€€Ð€€z€€€€0€€gi€0w€
[€€)€ +å¡d€€],x€ٚ0S(€€+V€€€#[€€€€ €k€€5€EfϞ€/€:€€€€3€€€dEPN€€€A€-a€I€M€€"€"Kp:€{€€€€€X[€€€)€K€€
7$€a€€ X€€¹1Щ*T0y€GR= n07€(€0H;i€€€€€C€€K€€0n€g€Q€€€9!€€€€PgZ€€n€€€€!€€€€€A€€I€m€€H8€%#Bƙ)a€€%E,9Ԏ€€/€>€€€€€{€€€Aj€€e~pN€€ +n€€€€€€x€€jL€€€-€_€€( +€€€Z€
]ٵ€€€€€€€&f€<€€|&€\"%t€p€N€1€˨€€€€€9XL+fg€i/m€v€O€€qr +%€Ď€^p€€\€#€|€KP€€ +€5€€€€%€R€P€€€€q1€€[w€2€ €uzXN€w€€lx/1X€€x€€)V€Yׂ€€P€Z€l€€€)€€iw€€€€€\€f8`€
€4€€€€€y€;QQ!+€€3!€x|"׃€S€H€€4€€€$(€€ %\€€€b€N€€6xq€€w/xC€€€€€"]€x€b0€€R€z€;R}€€ ~€e*Q€?˖h€€@€€k€Hd€€DE€€€V6€€B%€)P€€€€@€~!€k€€Y€Z€€P€5€€'€t€€rv€€;€€€b€€ɢ
€ €W*m€€F€6€€€€r€€KT€€&€€xe€€€€€€€€-€€a€€^€z€€€€€b€l€€Φ€g€j€€€€€€€€€T%D^D€}€ܘR€$€3€€l€€NS8€li€€s4€€€{~€€6€€,€ €€€€€V€€€dH €nL€2t€-€6l€G€€€€/!€€€€€ꀯg€m€ +€%)€€`€€UD€;€B€q€R:vfX€€¤€WE +$녑€s(ËF9?€&€€o&€€€€ #0€,&€€J€$6€€_€ /O€€pÓƒ;€Vo"€€U€L€€€9€QF€]€€€€2g€eJ€r€€ma%n"€K€-€ˈ€€€€€o6€€€O$€€KxHLE€%5oh€ +€€6)CO"C-'€€(€{M\%.1€€E6€€€N€/€e:y=Tj€ܦ€€$ub€I€€€*W[8€W€€b0s€€€\*€$8tG€K€€€€€h€€fD€O>B€€.€€q€€€€€€€€aB€€€&€VX€€€h0€€Bk0€иgÏ Â€e€€ A1€¸O€€٠€%€€*S&m=€3€€/B€߀€€lF€ 4@t€p€€Y€P€(1bS€S€(vKQf@>s€4€eqb2€E€)€p€€:j€€NϲCj€-€1f€€€€€(A0€w`€€€hŸb€L€*I€=D€€€D€€G€€v€€Լ€€k<€€tTR€€€2€€^p€€€€€ €ɳᦎ€€w€yi:C€€4€c€&€€& €t7€[€}€1YH€€€8S€€€5i€€€z€€~M€€€ +€€_b€€€€U€€+ +€€€€€?€ג0€\€Hc)€€Y€€€Wl3€[WQf€€€0€€€€|D€€€€€*€V€€ €€X€€p€€Q€d€€(€[€€€€%*_*€€]€1@d€TE€€€'€€€€€€€qI€€€€1€€l"€€€€ €h€€bvX€n€cs€€}Dk€Éyʦh€c1€Y€€U€€€a€€€€t2[)è” Â€Â€,€€€€€€€]%Â€Â€í»‡Â€Â€/ZE
€€w€Ƌך`"€€y|€I€€€JW€\h€€yZ<0d/€^LS€N€€d20€€€)Â€Â€É Â€Â€Â€"€€€€€€0g!:Ö©l/ x€€7;a€€" ,0Aá»Â€Â€"Jlt€"€f4€F€€€؂€€€!M€€]p@€€
€€.PNdw€#€€%€t€€€€`€e€€€W€V€€€€ӆĊtӴ€Ö(҄a€$€€€@?܇€Ѵu€ €€€€0€t>^D€€€€€Q€N1€€€€1%.€{€@
€*€qH!-XZ|~q€l€lz€)Y€{€7ih€€!€€€Yi{€€lKD@H€ €€€€Y€M€v€€€€p€€€t"€3€€):7<€€€6€€$€,€€€€i€€"€€€€€€5€M#€ €`l€€€€€€€1€€:83€€€|€€€€B€Ρ)€?-€€9J€€4€i€pQÙ”pV€2vPF€€€u4a€X€M:EPLDA€=)€`"#€oVj€^€€Âa~€h%X€ah€+€\E€cM€F€€€rƲ€€L€%€F€6€3L €€€€€À €€€q€€€€mω@€ +€wj€€€€€`€€€€€r€!Q!€€€€!Rc:/€l€€TA@F€€[€€>u +v€p=Z€€re€D€€dU€Ü€M'H€#sNw€#H€f€€€̙€p€€\ms€ +€}à €'€R'(€x>€€/{€i€€€ׇ€3i€?€€PԀ +r(€a€n€kY€€V{*c'€€€k€€ש€€ +€@A€€]€f€€' €€7€)€€€€77€Eoh€t€€Z4I€€bf€€Z€(S€€P€€€€€€)€I€sê¢ s@€€p胢֟Pj +€?>a<€&€€A€€€1€cx: !h€€t€Q€€€€€5€€€)€ଞ㈄€D€=€€(d€S@€G#€€€ci€€TU€€n€3€M€_€+(&€괼*€G€€p€€;W +S€€m€€€B€th€I€t€R€€I€€(2€€uŲN€$€$εLa€U€Fs€€€)fRX€€+€(€€=€€€y€€€€I€€€3B€€ăN€ +k€€=€R€€܎|Nt€o€€59€<u+|€€Hx€€<]B€€L€€€5lÃǦ€N/€C€€W€€<1*|UJ€€bGI̔€€€g%€!^RbƱ€€m€€€I€€H€€+€€€^=€€!€€€€€Ṁ€€€]6€€€€5€-€€€^€€=€d€€@;`sHy€€5ZM€.B€E€_€ r€$€\1€€€߆2$€%€€؅€%€€ €€@€€€Zh€€€`€c€UZ€V€€€jq€!€Tb6J€:€1€€E€J€€n$`€ ;€€^€#p€€€@n€€Lu€R€rM€_€@Wa€€q€€€€:€ +3€1€€€<]€iy€€€€Hoz6€ €BLurF€€Y€€ݔ}€0e Υ€{ i€€€€<3€h)P€r€€t €'G1€p €+.A €€D€H€€€€€is€€€€J€€€€€:l€_i€€€j€x€€€7€€?€€{€ڻ:[€C€p2€€€€€8c€€€€X€D"Æ¡X-n/=?€A€1€€€tT€€€€+€€IkX€ƶx€++R€'€0AdP€€€]HÙ€€\€€€!€/H€f€€H(|VKŀ€rN\€pZFi€RYJ€€C#ɢ€€c€r€~€€^3Qt€k€€o€€€€€€€DҖ€8%€Q€€9€€&€0€€Ǣl€€͔,:€ `€€€CL€RsH€ +€W€ €€{€k@€-€€3A€€BYa€€€%€"I3|€ +6€7H€j€_8a2€(u€~w€€k€AT€B€€2€€€€(€c€T€n€€)€€(0€€€C€€€€$€€€t€€0€€€€s€€€ƻxpt:€{€e>€H€"€Z€)€\l€€€V@€€fns€,€€€€ho€€€/#€€#&p€9€€€€I€€y€ ]€:€3€d€€€€€€€*J€€€/€€_€€,€€=€€€S€€$i_€F€€€€x€-€€€(~6€W€3€€€€€;b€ +€DLR€€€€R[€\€€虺˥€K€Ʒ(€r*€e€)€"i€͖Q€t€€€€€
€N€ €Ò€€€€Qg€€c€€q€€z$€푌€1vN€€Z€jU=€Ĕ€F€€c€€€€€W€nW€€^€€€0€€€2u3€€€#€€<3€€[€€f€z'€€5€0O-:€t€':!>-€q€B3€€2'€glZ€z€€€€`€0€€C€kH€€€€w€bb€€[Ô¶}[ €j`€y*.€j€€€SV€€ +%J
2zN€€€€`Z€€€6_.Il€og]€ZH9)(€€€€D€P€€€€u€€Mш€€€€ڧ€{€€!€L€C€€`€Ɉ€>3€ñ.xsbE€Pp€€?€p€Y€٥9f€;7€$q€€€V€1(€G€HG€$̀€€€€%€o +€m€u€TU7€-€€A€o€f€€€€U€E^,€€0N€Rt €€C,W€€F€L€€€€€ZA€€€€B€€se*€€€€€€€€€^€€N€HZ€m€YO8€/
+€A/{€€J€v<€€€ˌ),\€€€\€€^€€€€վ€€/€€f€H€€Oz€€S€€>€B€c€€sV (1)e43,€̟n, +Í>€>^€+H€€€2dJ,>€€;;X€€gu€{E€€€5€€€/E€\€€€|€€'€&n`€€)I»€€€+€€€g€€€€V€€€9ֱ€͗€'86j€r€O€€%:Þ½>߼€€€X€€€€b€€€€€€€_€€>€$€€v€€€€1€+W6€oC€€Ch€€€-€€F€jL€€q2T€rQhÌŽR€"7€bi€K€s€€€@€€€€]€€€€n€(?€€Fb€€€€h€hU<*€€D€€€€€€9€€H€€.5€€€1c€€v€H€€f€)€€€Adj$€u€€y"€Id€€ +€€B€Fy€TNN€7€€€~/agP.€[$":z€Yb€€€€€"vQV"D'€+b€aIdq€€€i€€€€€€YZ!€.I<t<€€`€€?€€€[€D€.€€{W€K€€?€K€O€€ +p€RÖv€?ub€€€0+€€L}€A€`W:€C€€q€€LEՙ€€pyj-QN€mi€€€€ €,8€+H€€€>2€€<€g@€€€€€€€?€€€€€S€
€€€?€0h€€€€ObV$€t}€RP €lu$€€Y€€SY€€w0€€f~€€d€Li€€@Ps€1'€€€€q€X&€€€€€€€[€€0€€f€€€\6€T€€]L€AH€€€€(&€@€t€O%€€V€€b#€ÜBjQ€%Z€€€€€!~€€=n3€,^€€>U€I)€"u€e€DvB:€€e€€=0€€XJ"€&c€1€3`€€is€``'€2 €€q€"wX€€€h€€"€€€€J0€€€€Cy€€-L€S;€3€/€>зi€€€gM€€€€€€€€€Aɴ€€€€€,@€7$€€B€TxBʊ€U€E€f6
€€€€.€y€€e€aٶ[r€€€€€€€i €&H€'H@g3J€=€'€s€C€M¹€+€fR€s1ٯ֓€ _€I4ñʼ1€г€'€~€€f€x€€€€€̒w€xs€€ܲ€€'€"€e€€€€M=€{z€€€€€ޒ€#€oPak€\4<€€T€r+iU€€>YҌF€€
€€p€?€t€#€HF<UKm+€f€ui+€€2ßœS:BKGh9u€x€+>€€9€0€€V€€€JYR\Ï€€€I€ٻLÞŒ[\€1bL€~p%J/x€3h€.9<€€€6€U€m€ZP€7€7€MÛŽ8€€€€€€>€€+€nVnf€#Y€_€€€€sO€€€y_<€€y€€4C€€W€lF€€u€1€€v€€̌YY€Y7€€€T€J€JVIt舊}€€€€€Sk€€Zk€€;€€f€҆€:€€€֯O'qc5CYkʽ҇€i€€€€K+€€€b€u€€€€ {€€(̸Ei€€e€€(€
SW6V€|#€€€a€,ju€€Z2'[€€€$<^€€€b6(€*€€€€p€"€€|€€€~€€E€b €a_€|€x€€6A~€5€78%€L ?€"€.€tǽ5€)Oon`€1S€3X€vr趦€€€€r€€€€€[zÍ€UǬ*€^rAed(€€p€€€€€€nX€€€绋€gq€t€ìžÂ€Â€Â€Â€Â€r€j]€€€€g€€ E€((€€f%€"€ZB*u<€hUJN€vy€Ƃ€. /€ukd€€]€1h€€€s€€GÆq€B0€€1€€€喑Ki€€€BBwG€€=8Bhy^€4€Œ€€€ ٘€٘€€€€€j€=o€€€'€I(b.N€€€sAф€X֚ݫ_y€€NYXN€€€€€€`€`#f€P€i€€R€J€€€€€8€€=€€U)€DAL€ +€p'€3€A€E&€)€€€€ij€0€1€H€€!H€€€€b€€0€(€€!0vÙ•Ý!0l€˪€€€€F|€€&€€.€€€?€€€ €"=€€I€€S!N5€$€a€€€D€,o€{Z€ۈ€€s€€€㲻Zf€€€i3ش€€$€\zÈ•U€[€|€€h€R€€#P€ޢ€€t€€€€€Q€vi€
€^€€ޥ€€€€€NMH?€€:>€ +3t€Lz€"f +€€T€€d€-€sҶ€D!5€ €Xe`s€€€Ⱦ€€}t€€IO€9(€€€€€€>C>€€€€J-:K€g€€€`VT`kZ6€BD€Q*€詫€€€z€v€€]Օ€€I뤂€=d.ß F€€€/€r€`bC/€€$€€€€€€H^G€a€€€B€d€€€ګū`]€€r+€€7€€|?€€€]€€l[€>z<€€€€€b€€K€ȶ€€_€ >€€^k€€J€s8€N$€€€€y€€'€y€€稔€€€/€€€X€඲5€€€C€€i€€€[€,H€€wL€€€€€€:F(€€u€~%5€{ZD€V€2]e(Y܈€€rQ€A€6f€"6`/M#€m€€W€ NO%Ê€€€AK)RQc€ V€V€€€m2€€€~€V?€L€€kƪ€€w(U€€2€€7€€q€€€d€€+H(€v €€€f@\€j€€€€WqT€+€8€€|€€€€-€€be%€~Z€h€€xC€€€€€€€€€$L€€€:€€
€€€€&`€€€ߑ"U*€ui€;J€€B €Eا|€€%€뙀eWRN€€1L€K€JŊ€9€€X€€Ȍ04#€r-€c€|-+€^w€`
~T€Tm€od€פ€TET€€€€ڼ€g€€eO€5ʑ€QߟR€€€P0€TEu€€€€!V€€€.€€Qt;Ñ™M€๚€h€€€o€Rb8'u€€€€€€I€,Õ¾l€€΃.€`K€2€€€€€.٢€gb@€Qh€d€€Ԭp|€P7€€€€a€=€€€ =€5,%€<Y€€P,€€26skaӃ€Y€a€€Ö€€=)n€ے/€€<Z`€€€€QxL€"qznx€wN[,€l€ۙY€€J€€€‡€€{€€ž€'):€€€t޾€€€E )€€h€N(€5͜€€€€€€N€€€€F€€€)j 7˽׺€-€#?€€€I]€€€€B@€B€FFm€ߙ€€ޔ€€€l&?€>€0mO€ZQ€€€Ĕ€.€€7G€M€€€ܤ€€Vq€Q€ΡÉs[:€€€€x€R€€}€€€
E)c€p€.€Y€€€%v€€ÚO€F€8€€`]q€€"€€€€NQC€tp€€€,y€|€€È€€Q/€Ib?€€€€€+r€4ÛQX€o€?€€;m€Qf#C.€U€q€€{€-€@€2€[€Bx0ʜ€€,€€€€€€€€€€'3€8g€g$€:?h€@xUЈ€€€K8€\€O<Ö’-€pr€€€9€€€{e€v€UÕ€€€s€8€€\€€WO€€n€€€p2pb€b€n]'€€€€&€v,!o۾€o€8€m€€1€€€?I€€e&< Ù†_€j€™€ [€\N€€€€€€-€€C€€€€€Z€?€€gh€0Çš"€€€;|€{!€€€(€€€€€€€€€-3Ïxjf5Y€Z€€€€h€x3€L€e
€5€€€€%J€€csrr€€€D9Û<€H€€:€€€*€{&f€aF?ƴ€x€€)ww€Uw#8€%9<Uy6€€{€€€€€ ͈7€i%€€€€€€-E&€€E€Ru+€H€TM€€€P\€€ +XY€€€€aMڦ€Ҿ*€€€€€€€K¤#€PKP=€€€M5@wBh€€`C€€1b€";€Ɯ€<1€Rw@I€€€J=`Z€€Di€€J€_€€€€嬩€€€(€mÒ„?€€€€€€DgC €€€€€€+€€*]€j€€€€€.€€v0€Ux€K€€35€€€3€ €€[€€V€€€€{[€€@v€€€€€"€€E€4|N€K€€€€€O€w€€€W7€'+€€€{.€€t +€}€€€[0€$€s€€€€€€€6߃w8€,W€€($€TM€%€W€€Tc€-€ €€€€€9€€쬈\60HC€€N"`€x€I€:€€€Q €€Pt€€j€€€a€€A€€L€€€€c€_€9Y€€Ϯ€€€.Þ®\€€@€€A€h€gʊ€€R€צ+€+€^€€€€€€€€8"+€*€€T€pQW€U€5€€}€2€€ €€€€€nr€€CÒŠP1€€a€€€€7€€€|w:€€€€Z9€€%€b€€€C889€7€€H8€,€€~€€H>8:9€>m€.€€€€€$i€€\€{jX€;u €$€€5€T€p\)ÄD5G)€€€€€€wճ€3€8K€2l(€€€r€lÆAF€#€m€€€€"ÃŒG۪€€?\G=$9H3€€€€€€9-€€J€€$rt€€€€€€€€f€€€€G2M€€=P€€G}€€M€€€L)g}€8€€€M€\€i`ǪdlE€€€hq€€2€B€€<€€€[€9N€F€€B€€5€€bn€iAs€€€€€€H€€€(%:€X-]/€ݒ€K€€Ö€€€€€E€€y5€4€€€ o€R€R€9€I€h€€qv€<3€ +Spyw€€"45€€VبX%Ü€€=€/€€=_€m€€€€(€€ €z€+M€€E݂€€(q+€€E€O €€€€j3YK€C€ܨ€€€ ؼ€r€€)ma*G€'h€tp€€€ŷ(€€€€r€2€b/b€3K€€€€€ռ€#ԟ€€D€€€h*h€€)H€€8€€|!c€3€€€i-€€€Uo€€€kkÛ©_€€,I;Óž(4€€*€€€I-€€€u€c7r€Q€v€Zd€4€€cP€W€€!5~€€€€€€ +€0I€y€x"€X€€V€€jQLBhc€y€€[€D€€+€mK€ˆY€€ad€€€ֿ€|?€€1€C-j2=€C€)J€C€€€s€M$€€!€=Mu€+€€I8€O€€€Tl€€RV€€€io€ +€5€€\Jr€€€€V€5W€\€€Huņ€!€+€€€#S€i;ʼ€.g0€z€6€€6"€ۈQ)€€€€c€& +€€€€y€v€it€€rSt€<aE8B€ug€90€&€5€€€=€8€€€wߕ€!€€}€€M€1€€HQX€€?Y%t€u€ɑ€€L€€i-c€T€€€€€Ӧ1Fݖ€Ue€7vU€4ě€S⓷€&1K€€UH€4啴€9€#€!Q(J[u€@€€€½€Ѯ€s€l€€3€g]n×€€€R€L€€͔€ €=?€$€j€|V€2€€+w€€€m€€x?€€V&ј€€C€€€€B€€;€/ €8€€,LY,€?a€q€C€Ͳ€a€*€6€€%!.€€z:€?'€ &€O8e€!€€€€-€n€[v*Õ Â€Â€aI(€€€ħ;€*€€u€€€i€€xG€%L[-_y€Z€€€€x€€€0}h€*€€€€-€V€u€(€€!4M߼€€€€D€!€€C€r€b€€È2ԗ€(l€€€€q€*&€N€€€]dU€"€R^€a€€€%%J%d@€€€:R€#€€€,V€&€`fv:€€N€€€n€€€€R€XK>€:(#ܵQ€€€/€)X€|Tn€4P€Zra€\j€(€€Z€מd€€€€d€€.€cvs.:€€K€€?€2€eh +s€:2Y€€€x€*€#€€€3€ë°o+€€€€.€Q
€€G
7€€€F€ €€n€€€€퉑Uo€€Ѧ€ +€€€€€g€€&€a€€3
ƔӜ5€:€*0Ii8dfyܕ€O
::SN4Qͨ€F€ڶ7A€5€€9€"`€€lRG€?~€?€€€:€l'€t|€v€€a=€[€w€€€€@m7^€L€ug€€€O€€g€€€€s€>HGtY€ BB€€€K€€€z€ѣ€€s€!Ԕ€€€D€€:€€i€,"€Y€㊿€€s6=€4B€x€€€€D€€w€€F0k€€€€J€€SS"€€€5€€€€iX€S€€a€מo +€g8€Y€r#€€€€ug€ޙc€€ߨ7€€͗€€€€€f€€€€€€n€9€6€€T€@€}tYUTJ&€€KUQ€€B€€mc3[€M똶/€€€t€2axE€€€_@€R€€*lj€@d=€,b\€€€€€JU"H€€€K€€p€E]/R€&€@€€`€[j€s€€€_.Qe€€N€€€€€;€i€1f€€h€8r€€€V€Í$€
0€2€€€€€yR€A€LcVr€lvA#6Ѐ<G€€€€[Zf0G€€l€V2€€€ +€]€€t€ +J!€Gq€€ÄHO€€*€€}€€€/€€WMm€€~€~€oF€
PQ€M€€D€€?Ŏ€€€ €€}Qz,€€€W7€€€€zL€€€Ay€\€€ʖ€}YGG€4€Z€€G€n€€€̅€_€,€€5€€€€|€€€€O€€x€€5*ϡ€/*gpuwy&€€{€€g€!€€€€^€€X:+€€ €Ý€€XZ€f\QXf€ʥn=PK€€N€€S€Y_w€€">g!NHz€€€€€€€[€z7€i:€`€D€€0€d€€€€fܣ€O€A€\€€€9ܦ€]Q€V€€€€€€€ +V€ئ€4zz€€€e€ׯU€ٖBE€vV€G:|kd€€€|€z€€€I€p€n€訕"cg€€€{[€€€]Cj€€€v€I€€€€G`Zz€+€+€D€€€;€oP€Rw€iTl€j€€€€€€Tu=ڊ€€€6€.€_€wi€€€€4>€€€€$(p€1€9W€€)€P€$$€€<9€*€€€€7€€€€H€€ +q
€€ +'%€€[€j€5Yd€€2€ +0
;€€ܕk€€ouݞ€לD€*€€€€G€h€€€D€€€€f}x%B€:#Qm€!N\W€JT*€€€YQ]€]€î‚+€F€€€R2€Æ€€5€ÌӀ+€€KDU€0E€€€€e€R€:€ÄSiҡ€gW€K€€€m4GÚ€Kk€€€ nv/€€€Sl€3~€O€-ǹ€€€€€O€p€€>).GU€€€!€€€m;J€€€€€uC-€è‘_€I€"€<:v€€go6<€gi€&VÂ€í«¹k€€€&e}€u€€€€€€€$R€€0€]Q|€?9€Y^+€)^€€a€]eԀ€;€!׫€e +€
M€€€€oC€€<€€€€€€L€€€P=w`5,€Ya€H€€N€R`€€€re€€)Š€=€€x€€"A€+/':.lh€Y€+€€ʎ€:€'_€c€€€€€#s)*€€€6g€v€o¾€iŃ,€€€€€€l€€*4mX€2€s^€ݷ`€.)€k€$a€s\A€€€€€€WvZ&€€Ew€€€€^f.€€€€p.€€€€€b€y€+€€€€€€Dm€€€€†€Js€4€u€€€7|€m€͙€€{€=€€€G_€€€;€?€c$K€€C^×€€€p€€Feu€€€€ë¥rE7€}€€€€;€€€€{€€€ଞ€T€}W€€€%a8€€€€€"/.€€Da€v<;<€€€/Z€r€€*t€€€€€€t€9I€O€uk€o€€n€'p€F4`M\€€6ʸ€-bSU€L€J
v€R€€€€I€€t€€pa€€€v{€췕€€r€r€€€€€€PV;€€jÛ^€€\]€€n€€€^=€€€˴yb€2€€'c€-€€:˺€€€Ap-€€f/€€.€€€€g
D€€€€8€€D€€€€€3€€(t%ͻ€€boV&€)W€€]2`O€€ XcL@L €(@L8€€€P€€pUc€€€^-€€hL€\€€`€pVZÛ¨~jgf€|€€€fdo>]&%/€€€9€€€€€€€Km€€ €€€€yq€5€€€1Q!€€€€j€€s€f€€€bÂΕ4€*€E.€p?€8€€W62-)€€€uG€€€LÌ„-$€€K€c+Ap€€ fvB€€€€€b€y€Q:g€€/€€Y€€€€1J€s5,€€ZK@€€€€!-a,€€Q€€€b€n€N€E_€€€?-€€€)€€o€€2U>€Z€€€d€cӖ€€€EEU€€L€*€@€€ €€|€5ܷ€A€,{€VȽ€€€€fh€€€€.jm€€€w€I€ʋ]€€€€n5 €B€]€] /€€7€TÅ¿;0€t€€€~€EC€X€.@€hZd€*(€(€k€⚻L'w/e€>eH€㰒L€U€M(€\€€\Y€€qTz^€jV€l~€€€€€€€U€€R€y€ϒ€€€€€€€€]o€€€qV/t€K€€€€_€€)€€{W(€!h€€?€€`b€d€Fm€'ru€€€p +€€(€~8€€€€<0€€B€R֨€€€z_WKd€€€€€€€€€vY€€=€A€N€€eg€guÓǸF€€U€€=Xu€]:AT€€
€cr€€0€f€1 €€Y€X* +шo€T€€Y€€Y€o@€€€|€€€&€2E€[€€€€€ͯ€€€
€€L€€€€€€€€€€b €€Ç7~fp(P€H€w€€( €[U`€€€jz'€lgl€>€€-zh|X€O>€€€ €€F€6€0l€>€€€"€QF€}€€€ZÅ€"€€€a€€1€Q€€떰s€:t
€€€€V€M€)€3 €^€O?}9€B€&5€€ك€.€€x€€€€o€4€q€a€!QIG€€€ڛ€+X€n)j€(€€\UW€ST€<€€(€u€€N€s&€€€쨀€7€€€€ƃ €€€€€€€€A€€&€fU€`æ3€&¢[s€'R0€€€€€€;k€€d)€`€€j€ +)€€€€€x€U€g$|xq>Lnq€j€€]T_€`Mَ€ϼ€XQ&€€€R€U€EE€\€jR€€ﻪY€€€i0€8€€€r$-€€€€)ow8€6EJ8@€Z€mU€€€€E€€RG€#;$€nN€€€
@€f'mUV€V€X€Ή€0SlÂ€È .酔€€€Ⱥ€P )Ҭ€f€vπ€€ +€۫€€u;€€€f_€€p€€€9W?€€€€Az€[O3€ȟgL€ezϧ+€€€€*€€€x€H:+€Pj€VZ€#-€€/€€6-+}rD-O*€€€€€U[€x€z.5€€Q€Pİ€p€EÍšM€ €€;€-€*v`bf€€€;€ړ€€H€/€€€P€{Õ—)€€|C€h~€ҵ€E€€8€Z˒€Jgt€x€ F€ʴ€mqq€=€q€€9ľ€€€€*<€€€*€€IÛŸYt€a€.€€€f"w€QԲ€z€#ڸ€a€_$0I7€€€n߸r€€R~K€z€€€Y€Y8sh€l€€a#€^2
€€\€E€€€{ +_€€€€-*€€€a€Z€€ŗ@€x€€l€€Վ;`€6{€€€€€n]€Q'+€€€€;€€A€€€
€€€L€€p€€I*€s3€€Sw43€rZe€Y€€€{€€nS€.EG€€K€€€q€f€;€[€€€,T€C86Xr=6€€E€]+^^2€€韱€€€€€€€t8R€R9O(€€€€PY€yw+€€j€€+€ H€€^€Í$Ńu€€€€f +€€€/€^€ѓjyڳ€€v€4€(€€€KÌ€€\ +8€'€€€ \f€L€€€€€€}€\(€€Y€€E€€€H€>€€}€̙j"BW]€€€_€o€€4€€€^!ObKw€€€€€j€~€*F€7ll€?€
€€€X€4€D€l/ʧ€€€S77~b€€€{i€[€€€€€N€z€€t€€b€Y€€m€)J>€Bֽ€€€N€€€€8€lӒ€N=€€]€€|=€€o€€'€]3Gw€€€€€€td"€€. €€͌2€P€Z€1t€€IJ%€q€€U€AÉ
q
]U€€ €$€aG€€E€€€s€€d€Y€yÅ€?€€
€jL€€€€,€€€կm0€€9"€UTb1€€/€_.€€€h,€€3€G?hqqso€€€€N€€v^€€0€€€2rr €r'j€=€€QKHy_€a(u€*+€€€€€€€€€€€F}€€€[€c€€F€€"€VC&f€€€€€€€€|€€`€Ș€€n€€J€δߢ;F€€€ƕ=v€€*3Y7€4€,€\v€€"€€€€erDÔ€€ €^€$I"€QlaW{=€W
€€€€Оl€?€UQ€€O€T€€h)€€€BiHF€j€€>N7€€€Zy8€€I€nx[€B;€€€Gs€€^€Zd€;€ē€€€€€€ 1€€Ύ€€\€p€€€€€l5ZbO€o€Ghc€€$JK€€
€-P€€Q j€€|€z€R"€€#€2€&€€€F4€
€€I€O€¥X€GB2,€€ €ugT€&^€€!d O€3c€|€d{€€€P5€€€€T€€7(Z׶$
.€x€8€g€ӧ€G€€A€G€€€€€€€a€€a€€OX K) €€L€&€xa€>€€€€€€€€€m€ܗ
€€€H€WV̕€€€€€€€U~s€6€€ۂ€#|€€z?€€€9€%€z€*1Un€€%€.€F€J€€_€€!€€s€@x€€€i€L€€€Ԥ€'€Kq€€t€€/€€€r-€€̀€F̟€|R=€€€|K⡻€€€*€8€~-€<€€)N€€T€€M€A€~IÓ.€N€Db硑€€€B€€€̒€;€^W9;€€€€€€€€€w€€WY€h€xÞ€€1€(;S€|_€€€€i€€0Ç€Nز^o€€\€€:&€€€/€€u€o`Pmad€z€e€eg-Nt€ػf?€Hz€€y€€€sk€a€€€S€€€€€€€€@€<0€f€+1€#Ü„ÎC€a.o€€t8fG)€"€€€€H\.€Q`R4e€<€€3€f=1Ê´GN€h€€€X€=€€€ +€Y€€€E€qU€.€%Qv€IP€€€nND€€Q€q€4€Kb€€Po€w€€€iʵ€ѵi€
€]€CuW5Br€Z€€o€€9€
y3€@€€v€@M€€H€l!€€tu€J€Pȗ€€€€"*€€ uo+€|€/;€€rN€ +€€ݛ\€/SE€K]r€ €€ +€€q€€€$€€iD€޽€€€Na€€€€€€€.d\S€€&ݽH(8€€F€€€e€4xw€-€€€9€Ç€€P€€€€€8€.€€€€€€U탌x€"€€D{:€OɈ€ĥ€H€X€O€B€€"€€=€xhtq€-ay7|€€€~e€€€€€Í€Q\'t:Zx€d€s€€i€B€€]€€€d€€7€€y€€m€€€€€.A€€€r€€€&T"3wp€hK0€€€~€€ljJGu/€€h€€€€SA7 +€€!Z-€ +€€ޤ€ €€€G:5€os@ &€€€€C€q€EK,q€_€q€€Y€:€€€€8€.€€L+€z€€€V:€€€€€1*€€€€€€€gZÏ"\€U€€€€€`?RZUE€€€ʉ€€€€€?`]x€R*'€€S7€€x€A'
€€€€ꄣ€€I€€iˋ€Y,R\€3€m5ј€€€2€€y€^-€€^v~g)€€€iZ*#€J€€€€€Y€€9€FE€1%€N€"€t€€€dH€€:6rMJ [E +€€€U€€€q€'€€,€€0Ӭ€€€€0€F-;€0€9*;€€>hhT€v€-全cnj€€€P€8\Rƫj k€T€€z8€€U=€€R€%}4€€<€k€€b€€€lu€€€f€N~JL€9€;6ZM3y€i€€H€bV€€]YB€€€€€€Lf€€€€?C€€|.S€€aY€€€€€€)c*8O€€"oJs€u€`€>€|z€€֗€c)߫€E€€€#P2@.c€:]€
%RBc€޹€€Z€€i€€;€€€€€-`€€=}€€€€R€€4€B€&€€ +€_€€1€€€€P€€JoM€€€€T€ev]{€€€;€+€€lDRv€^B@€€L ܸÑ}€C€€€ٕVbX[Yo௣€x¾€^G€1€€ܲ€€Z€€€€€b€O€€f_€+€*e1€€DZ€=€]m?d€€V€€€[e19€€X€Z"U.\գ€€|rr%L€<o€ÕϚ€€€€4€€€ep0>IS€€T#€€€€#€z> &€F€h_€€€d€€€;N6€€Q€CC€€w€8#NTI€F€€€˚€2€L€€3€gnP€u€ÇjL-E€€P€€8€€€o€U€€€€P€i€€€€u€€€€€€€[+H€}Ó»G€€L€€W€€€̺n€€&j€€€8€a€C€ƥ€9€G}O€+€qh€[€j0$€O3wm€b.d€wb€€€e@q€€€:€Y€€€Gw⧞€z€€€7€€€€*€r€g€!>f16K€€€%s€€jHP@v€$€€€g4$€*€[€€#W-9€J€,N€Û€`€͙€g|€_€G€€-XJ€++€L€€€8€€7€h€F#0€y}€G€€€=€€q€€€5^€9;€w ܳ€€€P€€U€€€i"a€=€A€€uD3,€€`€€f7Q€€€€€v€tt€€Oc€€€z€aIYZ€>3€@€P:s€L/€+PP€€€€!€jÆ Â€.€€€I€€€fÙ¥/€€z€.hd€R€E€zl€:€€€H€b€€땩Ì6€b€0}/-€%€€€$€€Q)€€€€€€V3؃H€[€.U€_Mo€€€€X(€€€€€€€€ +€€3€€c"€_€€y€€€€"€€Bo€֫[€€€V4€đHV|#=St€ €€]€D6€HgR€w€R€VU,€'\n€b€)%€€€b€\€€€€o€€€C€€}V€(€K€A€€/€€2€5€€€6T€:€av[Ø€<€€3€€ó€€€v€€"€€ m€€1=C>^Ĩ€\b€€€€€€]U"€€>€€A#€{€€€ +€€S€€!M€&€\x€€€€€ȕ\€0k€€K'€v€R€$;I€€€€€I
Q +€F€€D^€€QfI€€€Ƅ€€€m€j€dR9€€D€h€s€€€]ݨ€€=rh€€iI€€€<€€G€€€€V€€q€€€6
€K'€y€€a4€€€<€k€€€=€|€XS€E€g€€€€d €,@€8€'z€€}p+€b€*€€€€€€€#€V€=€R ވ€jKL]€€€€x€€t€€"%€€$€€+€ԕ€ X€It€]€€O|T*dL€+!€€€€dm3M€€€€%G€*€G€a€€e€D +@j +€0;€:€€S€€€2S}€#€S'w€I*=€ +d€6j€€€k€€L{¬€€€€€A€Q€€յ8 P€4_€V€€A€€€9zA)Y€€&08k€€€/€€€€€€€€€L€9€€€€€1]?€I€€€€€€]€€(9E€€g O'7>0€€\€'p€TSk€€d€ݫ€q€5;€€J!n€€+€sF€€g€x€€€€€€eޓ€€Ǽ€!W`€z€5L?j€€oc€€sR€€€€߽HVª3€€€t€t_€j7Ey€€€€9€5f4€6€€D€PÂ€Â€î ˆ7€€€H€eÉ”v6€€P€€T€H|€U€€€€V€€;€ҫ>[€8Y€qj€€_€|6€
تFOٽ€8€4B€€D€€ۅ€`€€Tԇb,€r€€W€€H/€"(€ ʹFz€O +P €Te +€€\3€€"5ܣ€€€g€3€€hq€€r޾€녅€1€€kɪ€€mH$.€Gs{€`['J€DN€€€€+yu€€€€€e€€€,€h€p€€G€€>€€€3€€€€9Y€€{€€€€;€x€€J€pq€€`=€€€f:/)nѧ€€€€€5€\€P0€€€€A€€€€€hh€Io€.$€;c€O€€€A€€Qf€€€€;€€z€$€-€b€Mf_0H€€c€€W€€9]€u€€a0}E€'€L@€ ٕ
€0إ€€b€€O+55€dg€!€€€Ü€€€€€€€#€€€vF€€^€€ʻ€Q€€€€2€[€€0€P€/€1€€īoX)€€Œ€€)€+Ԉ€€X€€€,e€€€[+%€€)€€~€€€€@€€€€`€€h8€X€z€€C€€m#9€€pl€+,€XT€€=€;b€.€€W]€€cÉ‚3€€6€(ٶ€€l€mn€=€€€€3€€€€€nj€u€76S€5€s0P€- A9€€€€RTk€€Ù€€€Ȭ^;€? +€€?€<Ô“0$€%T€(€€€€€€€€o€:€R€_^€':€€€€96€€NY˯€€€€€€)€€i€€€_€€€€€XW€p€V€9€€~EלxR
€Ϳ/€€€b,Pp"€?t€D€!J€YE€€"€€q€1€ +=€€z9€D1€(€b€€€€d€€€€`d€d€R€h€€€€@j۾'y€q:€}€€€€4&€€€€€ €B€qC€€€uRvf€̔€€C€an}O€€Ɯ3€Tڽ>N€ 07€GZ3
€UÈ(s€€~€%Mz96C€Δ€ə€€iZ€€v€€]"€€p€/P€u€?€€€{€D€€y€ͩ€^Ŧi0P€I=Vg€€€O€€€€€€€€€€G/€€:€€U\€€€cS€€lQ€r€UÙ§I€€u€̥€ne€T€€€Q€€,€Je€€€]*€n€w +€8nz €€؉€€T€€€\€-&+€€?€€ry€€€U€€JV€\0w€6vw€€€f€€€;€]€j.€€L€[€;酼€U€€l%€;€j€,€n€€€€z€€4€€&€Wv€€€oO€€K,€€ĒߨT€e€€€]_€c€Q€€€€V€€€€?р€€€Fi{qg€U~X웸€˻€€€$,€€€€€€iÆžH)€€ +2€€Jn€fw€€!€€{€ÒaY@€:€d€€€"€u€/V€€GC€€`€ +€p!€€€k0H2dd€KIl€JNS€€€'€€@€MN€€:€-YÉ´W€'OW€€1€€€upI€€2>dY€$@€I€€)5€(=€€€/€_f€p€€d€€€ €?l€uL€uv€€[f€v€la€€lj€N€ €%if€€7€€5€€€~xD"€S€€€t€X€^@ 2€€J€X€€ *€€€,F+€€€ދD€€.?€€€€€K€€w€€H)€{[or[€ш=3C€€ =€J€v^MzZXT€€€ky€`€€T;€€€€q€€€€$&€€\€5 Z€u€€€€_€€€€b€#€€;€€Dl +N€€€€/€€€€nyc€,€K €€\,m€ll€€[€€€€WȽ\€€€^@€€S:€€[€€€=O€€c€€j€€€U(€€ʖ^`K€l 4€€€€€€=[z€€W€€/J€y€Ç3€€
€€F€€€)€€(€]€,€€ɪ`w€€:6)€T€)M€ؙ€€7€D€€€#€€€d€€€€>@€L€x(€V€b€€!€ +€€€€€?€€€|ʇ€ €€€?@[€€€gf€e€€€3€€€+oxu€€Dn:4Є€=€€€aM€€€€!€€
€€€€€i€€€*€C€€€f[€€€€€€€w€€€€€4€€A€E+€q€jn€u€€€€€"€€5€€ۇHM€€€€€€€;Ŭ€_|j€aY€ƶ€€3
€€ +€€€€€ €>8C*€€ٙ€€^€€?=n€€€€d€€&zK3€6€€€=€€T€€€Z€᷇€㴒Q€€-€͆€€D €€%8€<g€.;i€v€\€tf€€€N€€V€€n€€€С€€զ€G€v'€[€@r]€€
€rI€€€€€ €Y€w€)€€€€4€€nVU#€€€Çz€€@€€€B€€\€'2€-ƵE€€u€€€€T5MC€)€€z€€%ZI:€€7€€
C€€Z*Û¥[x(h€€€E7€€x€0n=€;€€€y€€€s8€_€)Ǒ€PIW€ +&RkK~€€€€d€0V€`ק€=€€€€p€€;€€(€€€€/€%€C€€€<€€€!€€€€€€{€€؜€N€€€€d€p@€€U€€€s€//€%€[ÔZ€DM€€ΑO:-€BU€€€]€€2;b€K5€s€€4[€A&]zRLl€}€€€p2@yC[€€bF8Qz(€€XV€€>€€€~€(€€`€€€€y€€€S€€٦€€€€A€*€RJ€€€˧€€€€D€€1Ĭ€&F€Y€ĺ€€W€€$,,€7€€€`€€@€€@€€€_€€€O€)€€y€\€€˿'€€€PR€€€G€€€€€€F€€0€€€€MaN€:€€€DP€&€5~€€€€€€J€€[€ؘ€€€€0%€€<lb€€€j€M€€M"€€€€€+€)€ˇb€€€+Ê€=€€€>0~€€Py2€qF€€€€_u8€ €€A€F€€€4Lz^€€€€s|L!YHHaTL€€\€€€rR€4€PL€€h?2e€€€€UYf€€€€>€׵<J€€̂€€"^€_€z݀€-€€H€Þ€€@€(IudF5-€>M€k6€jsMCF|€d +j/|€€€*W@p€J€€€€€€.€€N0€W€€٦yc8€€€€€€N€7€€Q@€€C€€_€€€€€€€€€#€d€<€[€nr&€A€r"€€€€€€€̋f€€?€x€Z€€`€p€€€€z€Z€)E€€€€h>€h€_"€€|W€a|?€€€k€€€€)€€€t?B€€€Wv €a€€+d€^1€;€D€VU'I€€V€€wHCNagu4e]Sl@€9€€
V€€,k€ॳ€€f€m€I€ǵ€c7&€€8lW€!Â€í³™uÔ€͙s€€s€€"~€€a€€€€€o'Yk€€A€ZÙ¼O1€i€E€MKf€UXÄŒ"VHG€_nr€6l}€O€€(€€€1€€pc€€€€€4Ù€€€€€u7€AƼ"€€+€i€IwE*E€€:€N'€€(b€€€o€px€]?€€€€€€€€€€I€_€€o€€z(sC€JÈ·8H€€>X€ة$€9€w€iʔ€€€Πņ€€]AN!T0 P€߲\€~€J€€U€€}8€L9€€€L=€€€r"€V€Q}€€€c€€fEd€X€€€€€ݾ€€€]€€{€€€€€'€[:C€€@Q|€€€€€g1€€€€€€€€€€€+i€c€*o{mY
e€€€€N2Ö–u€[€€€€X€1/€€uf€€R+€6€V'cU€€€ǽ €€€v€`€ܲ€€€€+€€€€€jg€€€U꒼ϴ€aR.€€€B€D€锴jJ€€€2€a€̛xZ~€~€Q€€'€.€VY_\|X€€€x€€€€€€€Y~TF30€?€€€€r€€'€n}'€€€€€t€xw€tr?ʉ€€nĽ€o€€€PM€G,€€€€€Š€*]€€€€€|w€€€€N€€Yd€€f€€€€/€€Wx€€€€DeX€€€€¹r€)܉€€Q€€8€k>yC€@€(€8€€€€y€N€€€w€ }€^N€-@€@É€yP€'€C€g4c+8 €€€?€€€Z€f +€BSH:€€€k€xÓ·Oݿъ€q€nŨ€Ǫ€€s_?>€€Rs}>€€Ȫe€G€€?€!€€€€a€€€€€€E€€A>€€p€€€L€
€€€€|€an€€€€€Ω€€A€(€VTq€ +€€€€€J€€€A€€Z€K€8€€<<€€|@€؃J€€}Q)V€W€€)}S€€€€N€€X€€€€'Ab*€޿c!€h€€€l€€G€€€€€Tr=&zO€^€€ω€qkR€u€[_-1€€€g€€€€Yl€€€€B€E=Q€€€€€€`X€€€>[€€_€€o€c&||€P€€€€o€€€I€€€Z€J?€Íb<€€YD€ǥ +a€€€€,€€.€pJ
Qu€\€€'f€€€\€e3€r€€A€!F4€`€€s€€€€>**o +ej4€€ε€Ðd€-€€€+€b€$v€l€e€}Kl!N€€n€<€[€TZs€€€€N€H€ +M -1€€€3€6<€ZuB€9€-€€n,;€;t;€€€rU€.€4"€о€VF€Lvbv€Ɠi€\€U€€€Z€^€B€fO€€€R€€€
n€€€b€6€€ك€f}c€07€€€€€€€€g€-€է€€g€€Km€X€к€[€€€€€€€€^€€€h€-€€ݽ€€€Nw€S€€€€_w€€^+€€€€€/€s€€€€€i€_€○w€w€€m€J€€€€€S€
v}N€€]€€€€8€€€€€€€€€L€€€€€€€€€J_/€y€€€€O€€N€|x|€,€z€€u|€€#<€€\€€€€€€ æž¾:~€:ͳn€q€€€b8cD€\€€N€€€5€€€q€.€€%€€€n€€€y€€6€-N€O€€€€q€kX.nc€€ +€€€€€€_\.`€x€€€7€€€]€€€€ }€€€€€€€€Ƴ€€J€€€f€{€~Mc!€S€ŋ€a€€€uK€ €t€€€€)€€€~^€€€€W€!~€€]€ְX€€68€€eqs0<€€€€€€€€€. +€€€||€<z€€qV€=€€:\€U€€\€D€$m€RQ6z€^€۟€&€€€€€€€€%€€q€€Ú€oN€>€€€f€1€€€€€Y€y€€i€€:L€€€-s=Ge€€{€G€€"€€8=Y€V€gϻƀ€P`€€$K€€€€€;€€€71€ I€€€ €€?€€ì§S€€€€
A€1€]€A0p€€€€5€o€/€€k€-€f€€€ϙ€€€W2€€#€€€€€7€€€€€€%k +€€€}\€s€#E€'€Z|€u€O€€€€샧€€c€ʧ€€€€€€j€l€€p}€€z€_€d€€€€]€r€ €€(e€Y€€QŬj€€}€^qK7f€5€8Q\€€t)€€5Tٱ€%|€€€<€X€€€€~€w€1€,€€3€€€ù€$€€s€
B +€'€€€³€€€Z +*~€W2€€€€€F€4yTCA7€Y{-Xk~\€€'€C|€€€€€€€ €xG€€g€n€u€€€€)€€€€/€~€:,h€€€6€(€FH~eY DģY€w€N€€€€k€€Dz€€9.€€€€€€€€%€€€"€"€€€o€€€€€€v€Q€u€@€€€G8쀡b€W &T8€u"|}}E€€]€Z€€cݮպ€€Е€bL€D€A€r€&بYb!'@€`'V€€€;~Br">|€3€^ €€Y€AM[6€Î€€€€€;h€7z(€€b5€€€JI€~Dۀ€ř +wb€€r׫€HV€R€€n€€Ă/!€€€L€€l€
€H€€€€€x€Q€€}€aBM€€€€|€޽€€€K€€€J€€ҡ€D€D€8€0€ݼ€&€€€>]€€€(4€yAڲ€€6€[€4€€/€€€€W€€€€0€€(u€[€€€߸€O€1€€€9€c€€8€€€-€9€€€,€Ks€€*P€€€Λl€Ȭ=J€%€€[f!rg€€8X€^€p€<€~€€v|B}!€,€@€€a€€#JЊ€`€%[p€ǵ€€€€G06€€Z€€?Â€Â€Â€Ý Â€Â€Â€Â€Â€hC€6€ϿA'%D9€vYt€€Q| €X0€V€&Q€€€
q€€€Ǹ€1Jaj€$€_€C€gظ€€T7{€m€€}€3€t€"€€!@K]M€€€l€€b€R€L€€]T€€€V€€i:€€3#€€}A7€€T5;/€
€€€q€Ԝ€€€:€]r€€€Q€p€kZ`€€K€€}€€€€€€€s_€Y€€6€€€T€€g^€Y€_€€Rr֋€€֬R=€€9€;o%€̫€€w€8€€ﴂD/€€fu[C€:b€€€q€êœd€ړ'~_€N9E)€€€€Wj€b€xwج€v€€€يF€8Ϥ€€€5€€]Ԅ€qW€€C€kg?€fdYG€ €€€S€€7}€€vD@€[€€m€T w €€i€X€€€€~€w€ +€€0€3€E€€€[€€&k1€€€€€{=&S€fT€€€P€€€€$Q€]€€,gMs€#<€JE6sz€€€|€G€€€€€7€€€͕€€€҇€x€€'€€>€5b5€€^-€€~€€2€g€O€D-M€€€t€d€€€'o€,€€k!€O.Ä?€€€€V€o€€€€€€€€?B€€g€g€[!€€kJ€o7€Ȧ/€€€€N\€€è€€€€z€x€€€O€ӟ€€€:€D€e€Tz9€€:4€€{€€$€W€€;€j€€{w&€w€c€€€,€$€€€+SD€3€(€\€€,€€
O€0^€€%€k€d€€€: +€V̂€€€\ €€:€€€€͉k€€Q€h€€€wsre€ȯ€6€y€{/€€{€(_[q%*€2€€G€te€)€"@h,S(/^b€€€€j€7gÏ^LON€€1€€€ +€
€CgZ€ AƦ€Vs€6ʉ<€€€€{€€€€T€1~€€€€xÈ—J€€Džm0€ΦN€€C+€€€'€L€€匩€2€€r€m€"'€€€€€ї€€ +€I€;€~€€€€Y-y€€ +6ğ€$€€€R.€€€5€a[€€€€€€€€€w€€u;TFw$€?€€?€,=;m€€€€€|Ĩ€€€ds€€€%"v€Ͷ€VS€€1Ó»os€€C€€€g€҂€€_€€€€c +€ +€€t€P}q€'€€%€€f€&€xR€(€ €€ +Þ‘.€0lz€ZÛ¬,o€€.Ȳ\€€€ Yeˉ.€#€€p€€€€€<~/€g€!ç“€ޯY€€€QB€r€X4€}X$J04a€€€hL]€€CF€C€€€Dt+R€y,u#€€€€€€X€€o€€nO€€€f€€@]€o€,( +€€€€w€|€!€€3F€€g[T҈€€h€t€?€€€€€^€€€€€9a%€€ €%/#h€€€ß
€sp€€@€Kԟϋ€€€€€€ €E€_€€b@€6.*€€eP€€€€I€ODeZ€ї€€ߓ€€€6~€€q€€€ €€~€M€{€€6€€€u€"€€€€Z€U€
€€h +€Ȱ€€$'7€€€€€,€€€€M€€SG€€€2€€V€€€€9Br €€€€w=~k€€€X€€€nQf€ ,€€€€€€C€€€(€€€PB€€€€'€{€"€€i€A€€€P€t€kFe€~€G€>Û Ð”`€€€€\€2€€€P,€5€ €€{#@+if€€€M€9 €€€ǟ?€{€€ +o%[ф€*€€|€€D€€€/W€€ €€_̰€!€|€|€€yæŸÂ€Â€J€€k~|€.PdV€ +cv€䎦€*€h€d€€2€5€€€䚿€)o4v€! 8€诪€U€!€€e€6€€€"€QÖŸ~N>/I+€€€z€€3fu€h€€€o€€祿Y€€€€V€€1€ €€7€5€€ςՖV€y€€€€-€€N€P€€€€€€€€o€q€'€ʛ€€€s*BqT€CV€€:€L"€€€W/€€€€C)€€€€€si_`x~€€ \yzS€€/€^€6€ M€€q€€+>€€€k?€×€X€l€$V6L3€€~V€ri\ €bᇤ€
Y€€€96IgB#€€C€7€u€Ϫ€€ €1€€€€€€Ԉ`A€€€b€€I€€I€€]€Q|̫€€7%€€€Mc€27€€€€\€€5h6€€€9€€€€ޅ€€€€€*gkh}€€=€G€ٽ€"€ +€9€Ȧ4€!"€
É¡<€./€k߀'C€€8H€€S€l€ €Ð€€ +Zm€IT€>€s€Xo8(€~܄€Vʨ€€€V€Q€>!€€քj%z€Rkn€€%€T€*P€€€€€i€SY€!€g€€qD&<}€€€€%€Tu€Ǥ€I5u€€I€M€L]€y\XTbn€€€€彩nj!€€€€x€F5€€Ρl€Tʉa€€Y€{€25€qh€b€€€€Hə€<P~€[€€€€D€€];€€킳i€#€€o€€1€@€O7*€2d;v€c<€€€€€€}րo7v€€€€€#€A€€€Ʈ€€€n€)a';€z%€€FA€€g€€€€(( /%€>a+€€5€w€H∟@ €#!€€z€€€@f€€€O€€j€€€€y?uF(€€€'€€3€€i€j €€€€S3€€Xw€В;€€.€N092€€`O€€€€€6€€"€€0€a€!€€€!€€0f€{^€\(€ €€€€€}€XX€K€€€€c€x€_O4r€€€i€d€I!3€H€ş€€€€C]I€K€,Y€€J€0k`T!u€?€€€€A€L€€z€ɨ^BÈ–0€€€ʂ€5€r€N€€€€>f€D€암€€ܶ~€@€€€Ӭ€€€5€zA€&
€!=b+€€~jV€€€}€€ €2/€€€}€T׋€8iÞŽ$Y€.€-€:€€€€€U€€€€€€d>O€€€€€€€€ P€m€G€€€Z S~Y€S€€PX€q€€€€€€$€/w€H€ݲ€€ +€€€€€t8€€€Xz€Y€€r*3€€e:€U^T€€€€€€Ps€BbH€gv€h1€€Å|€€€€(€V€P-€€€"/T€ci<w€€B;€€Z€O€;€Y€€#bA€€€€€C€€Ց.€EĈ€€€€€€Z)MF_€€".P!\YÔ€€'€€ _i€€€€@€€Y"€YS0&€€&€€€-zsM2€€19sØH€`€€€€€f€€,€€€'€@€s€yB>€€&€€€|€€€€€-€VVL€)!e\mi@€€Dڄ€3}€€%€4`€c|€W€€e€ua*=€€€€€Id€€€€€€$(N€€&YI€z€C!S€€€€€Pr0R€€4V€€(€€€€U€€ €9RT€€€€€€€t€X€€H91€ظ€*'0>s€€@€€K€€k€€€€€n€1r€r€€>3€4$3E4€€€€€^€€€͹€€€)€I€rJ€€€+^<6€k€€!ZÄ“M€4Be€€uJҵ€€€mÔˆ €}D€1 0mG?KAx"€`g€G€\"€€€€
€€eNo€€R€€€N +€W€6\O €sű€_dҜJ€€ܩ€#;€€iC
T€|.€€€c€€#€o€]€€Kp€€FN€7"y€€€/Z€P€€€€팙€*T€€ML€€@0Ғ{€a€€3€s€€€€6A€"
€€€D€€€€€€€M€€h€€Ǧ,Y€€€€€€€€€y_€~>>f€€€€€€€€€€ +€c€=[€€€q€H€V€}F€7ÕƒS€€,€€€V€g€*€€@4~Tm%= +€lE'€€?5€>z+f€€€0€€€o6*€€€w€t€:@4€€€A€€̆€€€L€M9Ew€H?7F€;€€€€ŖJ€€Q€€% €3~È€ή"€€€€5%€€€T€€€€C2W€˃€€ €M€B€D€€ê˜Â€Â€e€€€€ri€r€€߿"€€€€:€€€€€€€hi>€€?c6€-€D€€€€€ +€Δy€€W€€€[^jU€Ç̧€€€=€€1€€@d€+€€€FPd&€D €%c€€€^yL€€P€|Â€í ™xH#€€€yJG,€€€U€€€€w!(€€
€p€2€T99H?f€y :€q}€ϲݲ€BW€€N€_€€KØÑ ^€i€€€€(X*€€€€I€€Q€1q#*Kl€*~€Ͷ€Y€2>[᳼€€G/c €€s€€€<+|€€€
€C-1€€€%€€€€€Üp41€€Œ +€€€€€€M€J€fK&€€€€@u€P€Z€€Qqb€€€€܉€k\Õ"€8!€€€€Xs€HW€p€€€€B4:€B€o€B€€€€€€X@€b€€z€€€I€c€g€€%€€€€AXB€>€MJSJjҥ€€€;-҄€|\S€€€t-€T$
AN€€;ߌ=€e!A€cš€€(€&n[€€F€l^€<,€€€€c€f€i€/€€n€8€uʽ,l€Wߵ€3Aq€€QYF€€̩|7p#€ֽ€€€€€E€\Z€€@€€€€€2€€€@e0Pp€Uӟ(,I€3ԩI€€؅Iy€€=€€/-$5d€(€ ?€X€`€€€3€{G€€p€j€D€g<€-€€$€€€€€[(1s€€€€(bM€P€,]&8/€+:lr€U,€FL€#€€#H>€€=€r€€-^l€€€a€r{€€ +r€Xo€M€€t€.p€
€Ø€A€€r1€Ƶ€-€ng€>0u€1€€k{/€I€€_€apz€[€u
OR€c€€ +?O€€ji€`K€Y€u€€€:€€f€j€`€{€Qֵ€e€Q xm8繱€eG€jw€ys€8Ա€뺾€@W€+Ú!€€@€€=ע€€B23e:€ut€8fѺ;-5ᡆ€f€€€Dbf^Li0€}€ s€€L€€€€ҢCx€€€€€€€H€P€€€€ €<€€€2J8Xԃ€€€€(€G3@€'€€€Wd€8FIm€€,€d€€2%€0€*€€€€Z€{€`Л€€T€€3€R€€€€€rJ5m€D€E€&]KJ€€€€
/€€]9€€€€(f€Cfd€}€€€D>€t €€€q€€€r%)I€dMÒ F€€€:(€€€€€€€S€U€€€€€5<5Y€€€_{€W€b€€€^>€D€€€(€€B6h€C€€~€{€m€-€Z€\&€D.€z€€€
m€€=€b€}€€9A3€Ӧ
€*€€€€6€e6€€^M€|€(€€€€EH'€€€€l)€p2€€€-€€€€n€7:Օ€€€2E€€g€€€€€Mxc€€tUP%€S|€€uN€4I=M€3€TF€!3&€€€€LF[€*\€€B€?P.€j!~l€€€5€U€€Ć
U€€€,dz€NP€k€€E€,€h€89€€V€€€L€L€=e€€€Q*3@€€T!€Y€H€e)€}€€€/€€€€€€€[3S€€€€€hgW€b€€_€€8{ת€q)"€€€€&€Z€€€A05T€C€€€€&€€A€€x€bDn€€~€€€€€€€€€xLYh€€c^wIx€o€o€e5]€/€€K$U€€€-€€€€Q€_C€=(€b€FIL€1€€€€€D€w€g€j€€dÞ™c€€d€b€Ƙ€|#€€~€An7€wހ؅€€2€€Y€€c€b#2JnǺ€€€€€€€c7€gqh.=j3€ +€y€!€^h€€€€ €T€€€۶B€€S€€ +€,2€g€€j;r€€z€[*€€€2€€€€Yl€€€€J0nTt€€[€-O€€€e€€C;€idм€?€€€ZWh€€_€ٰ"€g€€ʔ€€€D€3€€!Lc€€€€AS€M€e؈€€€€4€Zl€N€ €€αO€S?{€€"€€€€Y€"€hX€=€€G7Oړ€x1€€€d€R€€Q€Nw€(#E€€Dl€m€Y€€S0Uv€g€g-€l€€GH€=D^€€E€€,P_€W€€\€w€.1A--iw€5(h€b€KS€€€ÙJ€V€€Wb€€€€€n€aj O€€€€VЀ€€€E€€L€)1€€T\Z€€V€A€€€sq€€€€v.€€P€€h€b€8bg€€`€k€H€{o >€q€PꯈX€Fi`€€A;€€{×€ €b€ €€ѱo€€€€V€€€@9€׊€€Z€3ܞ€.€€€€d€%€€VCL€F2<:€B€€€u&AfB A1€"€€9€€€%6€€+€€€€(h€ M€bGpZ€uAr€_€{€Q€t|€:€€€ԕى€)wJz€€€€€€H-€&€€^I€€_0ى€"ǯ€€Pc€ƈ €€`€~€€=€B€+€€]/€€€ €€V€€€€WT €€€g4€€€€YÂ€Â€Ê Â€Â€*€€€€NK€r€iئ<€3€€Y)€]W`€(€D +€%€"€€p€€€€+*ʌ€i€8€0@€LN€o{ €€R€€€€€B €€€_€€d€€R€€€€J€€$Δ%Т€€Y€&q€€|A8€m€€€€G€€€€"€+߂€P{€€G€€@2€=€x€|€€o€#€t€<€€€/€€RGRd€$€J<}9€ +€€5̀‡bÌ«R€€€€.q€€€#^€#2j*€W€€€w€t€|€€(€€€€€€f€€€€€€€€9€gR(#]€T€
)_€/*€8KÝ…}]E€€€cB-€Z€€€9€€€U€}€(€˹€M>1€€L̀€€;A€@%€2\P +B€€€ F^€yoh€Y€K*!€€I€Uk€€q_€ˑ V"w€2€K€€ݔqw€€$vX€1J€€€G€€;fU€€€ZIBA'T€€0yY€€€F€€w€i€r€#ØŽM€F`€€€€€€€€w:h€€€€*€%1€€€€M@$€€€€€݋kPH€€.-8€p€€,RR€€€€C€JX€€H/:€€€€6€€a€KrA€3€O7 +€>€;"€ €€€ R€€S€€Qܼ€8Dn#|Dv€€Bb€$€€3€€*€€̤€€€€€€3Ȥ€€2€€V€€U€€J€€o€€~-Q€7$^`,€O€=€€PȯQ,˽€ө€€s€i€=t€€€ +€>€k€;€€€\€ +€€€{€€Ut€ +€U€C€7ᅷ€€ +e€{€2€€€Nr€€9 €J€v€–€€tݒ€y/€€€|€€€€1]_1tz&R#€3€9€€OÂŽ2€L€8€€}RT€€R/T4Y€Z€dÚ©J€€V€e€Z×€7+€€€€€T€S\€2
DNv€M€€I€k.€€AI€€€2€x1€ZҎ€€€€€€€€U€K€W\€Ad€ +€€D€€gTL€))F)€€wuHoxÓ½"€r€y^€€€€€mH€€€b€D€Z€@€b€€x)€€€l€€r€€€cC€€€:Óc€€€€b€€^-B€H:€EAܹ4€!B1o€UW€2€€€32€@]6MFw€€€€l€Ҫ€=€€€€B€€€>;{QU5^€€€€€€-€€TPfr€(€jg€€&€€€@`Þ¼bX€l€€E€ €€€U€€r€F€_€€€8c€9€€€€€€oW€^!€€xv]lJ€F€€*€€9€P€r€ +Ã#/€€€m€€ ;€-€€m€.€€O€q€€&€$€Y%€€ t€€€E%€P€€€4:W€€4€
Rgxl&r€€6€€€€€€|3€DD€€}=€׳ +9L€F€\€€r€€€€€:\€ +€€€€<€EV`€€Uݸ-€€ +G€v$I6y€I€w€;O€€€€rFrhÔžÚ‚^€!AL€€He;€€€ޑ€€!€(€h€€U€m>€€>?€V$€€׶8€€€P!N€UU"€€€<€€€0€ԧ€€€€€8a€ZL€€€'d Ï°U€bp<€z€o€€`€ؒ_€€¾w屄>€L.e€€.B€j€8eR€€z€'s€€€€q]€Мw*ɵ€!x{Wof€€k€C€€A€€j€€€€€r€€Ђ€h€€€=m€€€Z.€€€'€#ʌɖd€^;H€ F€6€€€]€€€Cm€2€€H€€0&€€€€Lʗ€€`&€C&€^=€€-€k=[€€€€€€k€€6h€l€€€€€€wbkd€€€€J€€Ե€€U€€€€€An€€€$€€€=€-p€€€Y\JtH €>R!€€U€€+-€uE€€pV€€€€Pk€€€€H" B€L49€€L€XE€€O€€€€T€€7€Lj€K€€U€€DRÞªT€6yÀ€€nw؋€=€NԻ€K€.b'C€×!€€€€*^|€!a€I€PN+y)€/E€€/€!€F?€.€G€€€$€2€*€€€€€mÛ€€€€€€€€'coC€F51€L€bM|€̙V)x%a~Ղդ߄
€8€#€€&H€Eh€€vw€<€€€3€€€€€ Cwv >;€€"h/$€C!€qt$€?€Ҍ5€€€€€q€€€K\PQQ€€?̶€€-€V€=+!җ€€h€€€€(€€€2+eV€4z€U€€€€j€€€\(5€€€€:€d€€€€4€CF€Ub€€€€€€€€€€8€€€€TD?[€€€€R3€€~€€*-<€\Kkl€Ǵ +€.€€xiM€Ǵ€M +6Wp€€€€€€fǧb€Iv€€'ÇOhIO€€€Mб€€€€€€bkyuuk€n€C€BE€€€Чâ¾fQ[€}:O€€0U€H`L6a€€"c€5P€ZLC€€O(€€€€€€{€M€l€€ô€`JT€€€ПL^€lJH@€€€€€€S֓€€€4€)7€C€l€%€€bK €€Z@3€H€€5€€b(€wQN€€C€€€€€DE€€^€€9Ph€2GA€OT€€ +*H€u۠LK€€€3€€€xV9t⯪u€u€V€<€Nhp^€P3?L*a, €h€x?€kO€R;
d€€€€B€*€.b+€€€€€€M6,J€€€b8€€-€"€f€:€€€ua€T€S€4c€€€(ء€ >€C +€€€.n€€)€€R=`R€5HA_Â€Â€Ñ äˆ’0€4C€[ €€
69T~*€=M€€hU/À€a€h$K€b<€€€€L€S|gC€ݢnP-€€€j€€%€N^€€h*€€€€€€'Ó˜ *̎€a&€C€{"]€€€^Q€r€E€,€|€€€4u€d€€5a€€€q€|6€€€9J€3D.€€€€€€J
€€c+{)Na€€U6LU€Ghi€€A€O€0€T€ij€€€&€P€€€€€I€€€ €0x€€€€G€$M׮€€€É€Œ€€€€3B'€}€O€|€2{Ù…B€€>\Õ³jA€9€>€€X8\<€c€Ш€s€€yx€€-E€€
€€?spiderwebman.toc€B8€€€$€€€€TEXTMPS €m5€m5€w€%\catcode`\@=11
!! SpiderWEB €ourcG€ +€p€$€€€Q€€Q€3QlI
FixupMPWSymbolsc€€€€€€€€€TEXTMPS €€€€€]T€O€-€€:€_€€vb@€*q€2€€ND€€K€€Ǧ%€€A€€@€È€€?€#84€O€ͤ€€~€€€€bE;;€€€q :k@€عI€*€ZeE€€€S€€€€€Z€€€€€!€,€€€€T€~€H +€(€qq€€€r€€ ]€v€͚€€U€€N$€€AO€Y€€€nt€€€ѹ€€#(=?€€€€€V6*w€юB€屫 9b€€f€€S€€gnnN€€W€`€€29€€6b^€€€i€€€€€ZyjE€€€€9€S€€€€€ir€~NP +€}ߤ€G?€?€Ɉ€p2€+€x€f€=PO€޻€€um•€€€€€HE€€ו€?€T5€$n€€€c?l€€€R€€^z€€"€.X€h; +€€-€€K?NR~€€뮫[€€€€€€x€€€ÔB7€d€S€€€Y €€>€€i| {€€X€€ė€€%%9`_E,BoLq>€R1€)€€€€€€9W/€bO@/uS1€J€/ĉ€€ +€J€€€&æ¬ hS +$J€1€R€^m€€€€€€f€€ˑ0+€Z€R]€е€a€%€€€€o€w€€€6€C€€€n€m$3*N€^€
€€ɩ?La€Hl€€€U=v€ߩ€€Q€a€)֊€7h€€5€߰߯€CTm€6€=?€€`€t€ji#7N3I€€€*€€€€|cc€€w€€€€€^y"I€€r€1€7J@a€XOh€|6| €€€€m"y'€€Z"D€€a€€€"·0AF4€€€€޻€€€€€.
ފ€`~€€€c€€ €(€X€€€a€€Co€€m€@i38€€K€€]$€€#€تZ0M'€€%Q€,€€DH€8çŸ,€€€€á±Â€Â€Â€$€:€Q€€4M€ũ€€€€€€€€2€€Ԭ€€f7%R%@€€€€/.1€€s€€D€3€|€€€+€d€V€7N€€Y€€*€€p€rQ7€€Լ€€€€€w€/€€("y€5LU€yL€&€'€€€9€€€eRj€€P +y€€Er€€E#Ғ€€9€)qb?€€&€€z€€,<€€:n#S?KDC€
€€2iPM€dp)8-€€€€€ұ€+c€€J€€BiSrL6€r&€€€d€4f훹1€l€€€€€t€s€€ -w`€I€€€€€€e€6,€€€l€:€€'€
€€€€€€€Zl€m]€‘€€Yf€T€I€Ò€€€€Fu€. (X€€š€2€Ec€€A€€wWZd€€U€€€€€i€€Tw ٔ€y€€€€*&D€*F@€€€X^؋€€€€€)€€€€Ȧ-€€€gr€€lam€€L€€TM€€?€€€€}4W€>€FNzyN€9€z€€tKsJ*€€€9U4€'€€€€*\-€€€€€€€mu€€€a€€€K€€$€€€pHҎ€€€€€=X€Ä^j€j€€J€<=|쇶€X€€€€?^??€€vUU.€z€P=wS€€!X€€ +UÂ€Â€Â€Â€å± Â€Â€Ö‹Â€Â€y)€€€€^d2€n<v€€S0€l€s:d€KZ0x#a€U€;€0€^€€RfS€-€€vp€€€<€€\F€€
J€€€qaU€u€P7C€Ps€ȷ\€^€Fj€kv€€€Lu€€?4S€€/€€"€€G€~€€&:6(u€au€€ ^€AC€€€gѬr%€tp:€ã‰Â€Ç€€U€€[}€€€vt<€4€܃€€;€ٺ€€{€€]€€f€€_/€€%dÓ
€€{€€13€<jZ€€C +yQJO}€ը€€3O€s€€0€aNv€€€€ԕ€€€h€€€"€€Kv:E€€€€"K €€F€€€€S€€O€€€€_=€€h$€€2,e€GR€€I€€€€2€€€!-Üm€€]€€€C€€€{€|UfUy€[Kw€U
€€S
€€8Ϊ€€€€y<€€{€€€€€6€>€N\€ +€5€€€€I€€€۔J€€€I€€€€a^E[Λ,dg€6>€€€€|װ€€€j€Ŷ€€€F€#€€ot€€]t€€€€€€1nd€vy€Sw4%€?€z€€^€€lS5f€€9€€€€]€So€MyF{€i% €€€€sv€€kNu€€€:u€€8€€-C=€€€€_-&€E€€€€€€!\€€€€€€|€g>}ɘ2V/€€€€€€€p€0<€€€ϥ€<€E€t€n€+Ïr7€ݵ€€d€W€E*(*/?F€€z€G€€|€€;€€€6€U€€ +larch.unix€7€$€x€€=€€€€€€{€€{!;z
l.spiderixmbolscK€€€€€€TEXTMPS €m5€m5€a€€€€€O€@=€%49€€0€ '€me€€e>96€€€~€€qJ€y€€€Aou€d€8A?Z€
€̮ €€F€N8s€N8%T€Y€€x€O煚€€€W_~%Fs€*/€0€0€r€+^€s
€/€€€H<€:€TXJtś\€€€i€q^€’Lg€4€R€<K€€€€Ӽ€Be€€€€ʳ]€€c€H€€€€?€€?}€€€<€b2+E€ +€y1€0€€‰/H€|[€L€€€{Dy€"€HN@B€€Ig_€,€<MT&€€€€€€€€<€j€€o€ €€p€€€9ʤ€b*9a€&€X€L€€€ €h€€愋€L€E€2€€{€€9€EٲL€$€HE€NZ€*˧€€t€€-0/9€Y€Uf€T€P€€N%€C`]€ +€€€€€,€€€[€|€€A1CVy€G€€֊XtD€$B+[0b}€ʣ!A€€U€@€a€€€ֳz€€€3@€€[€€C!' €€{H9€m€=R&J€v€¾€€€€€€€w€€rY€€1I€-€€v€Ɖ_(€€E€,€#€xY€€€€€€€l€&€J€€€μB€7€:€o€QX֯P€€€€=sP€g€e€6€€Ne<€Aь€n€k€yŞ€m€€.€39i٫€b€Xw€c€€)6€J(3€Z€€€€
€U€-EK€L€€€€}Q€€€x(z€€D€€G€€/€z€ €QRÃ3$Z%ꀀ€€€ƴ€.€h€qA)=€Sl€€g€:€€€€(€SA9€€!l\€Ò€T€8=%JC €€€$€OU6z*ah'€€€
OT€(p€*a{€€mt€€€%€€€74μ.€iv€€€€k$€_F€{€€€`€€tl€€Ӏ€p€€x;#CB€€€€˧€€€€C€€p
€C€\H€€@€7€€Y€tѶYVg\[Mbm€€A€Ƶ€7d€W€€>!€Wm€5€€€d€€€€€€€€k€€€H€߱&2€#€€€Mjl€€JJ€
€€€€*€,€€~€€U:Z2;€€ay€8€€€€€€~A€s>[-S€>|€€Z€e€i€€v€UV-pf€€€'Ã¥.Tt€"€€€€uM€m€W€ҹ €€€t€€€MS.€€en~€€ʒ€f]€€€@€Zy7q€€€2€€€€s€€€É€€2€
G€u
۰^€€€€€Ԃ@€€€€@€!€6€!P€Y€+€€€€€€€€‡€a€L€€_€€-€€€̩€€€C@g€R9€v€h€i€?l€€€x€p€€€€€ɣ€€O€€€€€ssY€€€d€jlƹ€6^€8€pp€€€€€€GjH€€-Aclj€L€€ݚ€-X€Lp€€€m€*€€d;€€€SX€j€$lv{=€2\€€+€€€€€rr€€W{OGz€z€PGEX K€9|}€€R€S-gq~Hs€_W€4$;€ҥ8€€€`€€Np€€ +/€€Š:€9€€€v€R€'€,a'€€2\€€€€Y€€u€€|G€€O€€€w
۹€ݽak€€wBt€€€€9€€€V€€€€€€j€€>€S
€/€€։€g€9€ XjЃK€փ€€€€€azqʹ€azz€€:d€€€O{€€R€[3a€€m€€y€(Xʗ€l-2€pF6d€dQE€€€MX€€+€€€mOE[€€€~|kq€N€€€[€€>€€6ݯrz€€G€a;DE€€€€`€€€T€€€€€€3€€€€`€upn€€€p€5€€Q€,*xD€€€€ +€b€.€€€O8€߯€€€`€€€€€€ €pu€€€€v€j6€€rY€T€9x€t@ß¾-€d_€€v€3€[€€~€;€€€€€X€€N€€€€$r€*€€v€H€€€€€Zڵ€8/€€€€€4€ك€€€€l€€€€y€€€z€2q€€ЅΞ€€pÏ Â€Ò·Â€Â€Â€Â€ÅˆÂ€Â€Â€Â€Â€Â€fu€€@€€€€o.€€€€p€€
_d€€€8€€€}€
~€RI€€w€€`|€™My€€W€-{7€€ab€v€€€
lists.webxmbolsc€€=€K€€TEXTMPS €m5€m5&€€€€€ +N)y<A09J(€€ +€V€V2\ɱ#€€€€€€#€€€ % €€€€€€€€€€€€€€€€_€ Ž##F€€1€€'€;0€€€€+t~n ?o€j€€D€€`\mL€Y€=€€€ab-€"€€1€€] €€€€^€$€€v€t^€€€mT~[€€€€€€q{b€€€
€㮆€ +U€€€2=€W€#u€€€€€Tb€€W&€€€€P€€:€€T€"€T€€€6€€€0€6K€€€N;KG€"€T€*g)a€€€€|€€1€€ܚ€€€5€T-] +'uurB€€€€MXÕ°4€P$€P€€|€Ц€6z€mI9€GÔ Â€AS€€€;h€€€kꓢ€c€5€޶W!V
€€€€€€€€€!€NM€-tDk$x€€€€€i;kjh€€$R€5€€;€ +䩅€€Ϙt€€!€€7y€€€€€J€&€€Y4-€(nx€>!aM€\m =€€€€€€€€€y€NeZ€€€€€€a€€€K€€€€C€€€€€v8€€l€€€W€€1€€€€]€i€€!€u€€€€€As€€E€;}чx€€s€cv€€€ྀ€s€€€€|€€'€€€€e5€€$€€€73€€€€z€€€C€cb€€W"f€IK€'\u€€€\€€B€H€I?KKi€€M€€k€€Lz€€f€P€€€!'€€d€_€€Zv*€€Ö;€d€z€R^€eȞ€€|€€€0€€€7%ij€€RD>&6€MP€€€o€€€€5€ћ1€€€€=€Z&€
makes.webxmbolsc!€€€€TEXTMPS €m5€m5[MY€€lQ€tH€€€€<$'€€>€€€K€€€€€@w!p€1€t€€c€ v€2I€F]G€€€Hs€
Fg€`r€€{}Ԗ +€!! SpiderWEB €ourcG€ +€K€€€€€Q€€Q#,G€o€
Makefilebxmbolsc€Z€€€€€€€€€TEXTMPS €m5 €€B€k€€aAp€€€vbUѣ€9€vG2€4€>K€€€€€€€$€€€8f-€g€b€y2€€€€2€yrt +€c€=0€€€
€€€g€€z€€l-€€ +€€b€ڡ€n€€s8€€€€D€€€€پ€€€Ы€0t€bhbg€N€€€S€€€€vt€7gk,[€€3€€-rV>€€€OzF9€€a€€B€€€€,€€€€€€€x€2k(=?€^ߺ6€€;€€B
€€ 9b̔9w€O5Z€€€ +NW€€€€€€ʎ€€€lBL€[€€]v+€€€w€€Ȁ€€R=/`u€V€2€VFP€€ €€>€#€€9v€t1<y=/|€m€8}€{€€€h€^[WJY6}€€€€ €t*€!€UZz$х#)BM€€€:pg!U€*KH`M€p€€€!h€9€€ښ>"Lu€€€€n€€€€€€€€€th<dڡ€€5€;€€€t€€0€€€Z€FtR€€€€€'€TkJ€€€€?€€v0€x(€x€r€U€€r€€j€{€€€&€€€€€€€pK.f
i€€.(€€€€€3€NB€"E€€€€ +Ȭ€R€€€€K;g€€Q!€€fSg€€ra]€€€m€A3U€dz€m €€lY2T€€2€h€€€ݶd0-€2€P€E€v\€5€\)€€U€€om€.€€uo€|€!€€€D€믢l€€€€wV€€9W€z|€€€ֵ€€E€`€€h2€ɰ@€p€€o€€D€n€€8€€€€ð€^€€.€€€b@Q9d€€6€5yyf€€€€g=€€1€ +€€€lv€&€€%€€<€€_;€=€]€;cN€€ €K€L€5€5€€D€/€>ɀr[Yk€€D€Ut;7o€€€€€€m€ -€<€U:C€€4 '€€€€x€},€€_€€€6%?€?€1#€+{€:3>€€\S€U;+
/N €€€€ٓ€E5€L~€j€€€€€€€lv€l€.€k"v:\Y#€0€€€€p€W€?I€€!te|03va€.€€IQ€€€$€3~€&€Y?€q3€€€s-€€€€ ^Ä€
Makefile.unixlscM€€x€€€€€€€TEXTMPS €m5 €€€€€€T€]€;€€x€€€u€€€€x[F-€'€€€€B€€`€LTb€u€D€€€€#€ԗ€"C<N€€€3€€€ +€n€€e€€€€€i€€c$j€€6€l€€~#UJ€€.y +€=€€rM;Ǝ€mG5H€€#c +V€1€F€€,€U€u€u€€i €€DO5€€€hJ€'€*€M€cy€u€€€€€W=€N}7@€€~r€€
P€{7€U€€u5Z€€€€€0SÓ€€€€3Q(€€ +NW€€€€€€.exF9F€€€€c+€쒰s@€u€9F€€€kx€€€€`€€d€€€ +Ü•4€3€ȳ#€ €d0J€€€€ €ԴFÝ”^€€ޅ€€s2€Ô€€b;€€€€€)Z€&/ab-€J:€b€2o€€90€€ƛ€,Z ]€|€€€5€€N-€"=€sU!^\~LOO€]q\€€H€€A€€€L+B€RY€ €€s€€€+8€€€€€}€Oi€>€+€€˖€€Vd€u€€n€€€e€$€€D€€€€€A€o0€:;€09€m€€€tzxu€€Ng€€ W€!€€aL€댄€€€+j€€€€ji€€0Ś€€€r€n€^€€P€3€€€l€@1~B€G€€€€|>€€&
€€2Ө€€€'/€ך€<€€€€%o€.€F\)€d€ +€s€€€€%?Z"€ +€€€%"€€€€M€Z€€[l€s€$€€€€P€€7€K +唾 €€b€$]€Ub€€€Ż__Ǚ€€€€€€}€€€€Ƥ +iL6€7 g_y~"€ZiU€€g85y>€€€Q€i€€P€€€€€1^€€3€M€€@€€A€€ɥw€K4€+v€€D9i€€a€€uk€€'€ucޞ€_€€€x€€'6€€€€€€2_€s€€€1[a€€H:€€MV€€€€8€@€Ӕ8€c€€€_?€O€€€a€lfc€t€€€€԰*€ED€u€€€€ѧ€€€€€€ €*€€6€ѯ€#€€M$€€€ߵa€€€~32€€|€€€€00 XhZ€`€eJ€€€€€#€>X€7€m__€K€ٶ_€6€ master€€€€€G€€\€€€€€€|€€&O;€ €
common.chutixlsc|C€€€€€TEXTMPS €€z€€Z€€€m€€z€;€€vb@€#€fF#a*|d€€€=€IK€€€€I€՛€328€€€y€3€€B€o€c€€€Tr@€Û€Ggy€€82€€€mN€5z€5€€ʲ€€y_€€€€k7€€€€€€E€€€€sFR8€m€€Dʴ€€ɔ +€€Fn€(€€h i€€6€€€€,€€Y€v€€€€F€€€€€€D€€k€!€€v€/€]M€ c€(5+€€j€ €3€N9y<A0€€€W;€€€€Û€€€€€(?€Évٻ€V@€€€€€€5€€€h€€€€2€ '€€s '€Ɉ€g€9q2[ €€€@oi€v€€€€ +26€€,S€J€3 [y€r€g€€V€€kx
€jm"€€€5€€aC€'€€ +an€€ J6€€€?€s€s€O8€€€€Q€€A*B€)€€€€^]€€€€€€G^? €K€JÒ«s9€×L€€Y*u!€€p€€.€QzÛ¦A€€€€Y€ˡ€€KL.€r€€€€D€U^h€N€q+"€.€q€ €@€+m€€hfΑ€
+N8dEj€efDֈ€€J€€€S€€ +%M€€€+€€)€€€^x€2€'€)!S€?€€z€€€€€5€V€€€J€€v€€€€€€'€€€yëp€n€€uo€€€€€>€€€˽€€€€_}}€€€7O€€€€€€޳€€€q€€€€(ͤ€€€'€€€ً€€€€€€`.Ý€€€<[€y"€r€€C€0l€€`€€n€r€€€k€€€9q2€€U€€€\BX€Rq€!W6צ|€6,€€/€€fe>€jbzXd€€`O
€€€ +€#€€H€€€k€€€cAwdj€€€€€€=€€k€€€ +€D€~*€8o€j€38K€e}cn€€Es€Pi€€ZX€€€€€€€€q€!€q€€(j€€b€2€!€5 +€G€#€€)€€zF€€D€K€€€€€]h€:P䚖̩€T*˩€€€€€€lU9€k€J€C€p$€»€€*c--a€wT€€€A€/€D€?|€昼€€ŸkL*€€€U€{S€Jg€€k€€€s€€#€}3€€M€]€€p€€€€€t€ €ư€sO€B€t5S€۩#fZ€€€t€;€€_€Ɇ€-€&€€Kk€w€v€z€vii€€`f€€[€/€€€NUE8P5N€qB€€d7[€€L"X€€誙€jD\O
GgP€€€*Â€Â€Ì A€€Z €.€[6€€€€€0€o€€!€ӣ€€Pm€€աazr€~uX€€_€€€[=JA€CÌ5#)?
€€€n`€€ȅ€"€€}(€€K€\Tǘ>nT€€!b€€€J€€Sm(€€€€€€€VA€\K€_€i_€€€€!j€h3LE&€]\O€s€€€ǔN€YfNl#JȆ? +€'m`ÉŒn€h€Ӳڣ0l€lC,,€߄€Kl€Y€€€€€€€8-€€a€[.€m5€\X3O=Y€z€ǵ{rhrq*€Ò1€€ׅW€ €
G€+o¢c€€wM€L0€€a€\€a€€€ +€€9€€F€€"€{`)\h€€,€€€€€€€
G€€€VE€€ €€j\€N€€h€ +3r€€€}€€€€€w€F;\Ιr;,H€€€€€€%
;4€
€€€%€3€N~.€€€:€€€€€€f€€1?~il€d€€_a]€€٢€€€€€€€Ñ}€&€X€€'€ꀟ€€"M€ge€€!€E€€<q€€}€:o€&€€€:*€€K€€€€r€5=Ë¿s>€ֿ€u€€€€l€€€€
common.hhutixlsc€A€\€€€€€€€€TEXTMPS €CD€J€€€€€€€€ L€€vb€€€>w +€€€̗GՒz€€€ P€3&<€€€։€J€€€>€]€€$<€~€H +€q?€#,%=+L΀9€€$,5rB,€=€f€€u8€Zg€€l4€J€O€ˎ_[€€€T_€€€ €L€s7€T€€€€€,€`%€€F€z€v€(o@€€mv€€€€-€€€G€€gO€`€,€S€ym€€zq€€€u
€€yՙ'l€€o2€
{%€ +€€€€€€j€ €€<€5€€€yY)€€KM]}€R€€
€€€t€€P€€i€f*ǀf€K€€TD€:€J€€xq8€|€€€€ +DO&€20ʼn€€€2>€€€)Â€É Â€Â€Â€Â€Â€Û¿Â€x€€€€
_€}€篾~q€€€€€_4*S€p€€^,€€€€€€YZH+Z€ʥ€X€\>Y€€O€€+€;D€X€€€>€€€|€H€wb€€€€^4€€b€UQ€E€.€UP7y&€=y€¾r$€/€}€€€€OǓ€€:cO}Eg€?%XUI€>r(€*S(!€€€€€I-€€€€Dy€€€˗€D€4yW.€YÙ2€€J€€\€€@€€€€5+-€J^x_€z&g€k€€€?p€q€€pSim€ωU€€€€7?€w€€€€€€p€u€€€€3€€€€`JW€€€€€Dh€mZ€$€€# €0€€€[€€z€€€Qi€€€A*}€€€M€€€o9
€b€€g"@{€$€P€,€ €€2z€€O€€գ€€€€!€K€δD€€{€O€{'=€G[.L$zs€!lFe€€€u>€#jFÈ€Z€脇€'Q-€X–€,€p€#R€€i|€:/dN€€€€€€€€€€p2€=€€€€*\n€€€{€9€€JfD'€€€€€G€.Â€Â€Þ Â€Â€Â€b},
}€€€€€€X8c€]€u€h €32€€€Be#M€€€€S€e0€€J€{€m€%€)Ѣ€q€8o, +€`€Z€€ŅWn3 €>r€D€*€7€€€€Y€€m€2%€€HT€€€€€3$€t€>:€<%B€€€€n€€8€IV€%Â€É Lh(€€€I€>l€deK€@mGdy€l6€€
ao€G€n€€€a@]€€€R€a€E€€€@€€€€€ +5xd€€6€€ں€8€K€€R€€€€ȼ€7P€pH€€Qe€€50€€x$Yi€Q€€€€⸸€€€€_5€yÛ¦>€-un€[€€€€w&gwM€EØ€s€@€€9R€;NB}v€€VS€"€w(€8€€_€1Ñ«-ۄ€€€€€z€€9€€€)€#€€€€€j€Z€1€6€Y0€ep=)€€€ޖ牱€ڪ€€`€S€€€€3€b€7€€`€C[€2T;Z +€'#€€R€€€€€>:€?q'Q€€€o€€€.+5€r t€€\(:2€€-C€o€€Xܕ€€€€€mS&b€v€€€€€
Ý€€-€€€€€€€€F€ґr€5€q%€€#€€€}€€€€p€3@€91€_€€€€€Iê„€ֲ€€€€t€€y€-€€uH€> €1;€€€€€€€t€€€m€€€6€€(T€1ϰ€!€€X€c€Cw€w€
r€\_€€ +€€€€€€[€=€€,y?D€{€€€€8b€)`@c/6€\Vm€/€€€ߙE€€€€5€€€€€‡€+€4€€)[€6t€€$€u€>,€H€7€dP!€€DB€€B.€€F +€€€V€€€pÛc€€-l€i*€€&Â€Ä Â€Â€Â€Â€4299€3€É€/{A€€j'4€€-€-M{S: *N?{€!€&6S€G€{€(€X|6w€^€€;€€/ €Z*€)€
$€>€=U€€€€#€bee€p€LX1€€1€€*HA€F9€A€€C€F€€€j€bVYP€€€€j€€€ €€Ɖ¬Ă\H*€€€€€S€€%€€g€5€€€,€wz€€.€€€€9€W€d{?€€JV€ץ$n?'€€€s"€€€€U€€€L5€x€]0€€u€€("€€O€€€7€`€%€€Z€Ɨ#6€g€€t€Z€€€:6f€ȟ€hҹ€€€as€+ãŽ:Wwcl€ԇ€€€€€_€€l€€d{€€1€€5€df€€y4€-€Þ€X€€€€€4€€€€€2"€€`vǷ€#â«» yC€O€o€<€€€€€^w€z€€€TJYd€€€"k€€€Žݣ^€Ñ€q€8:€c€F€k€nJ€€=>€Ch€€€ +€€XoF€€3€׃€€€€€€A€Ù+€€€W/€€G€\€€V€iq+Վ€G€U€€n€€€;Bl€
/€h€€w€€€*7Nx€=c€€$Hv
€€€€€.€ €v€Ö€€2€€' €€€i€€&€
^€€ݔ€€0ޗ€6;€€}~
}€ Z€a{€Oۊ€~€€3(€€M€{k5€€€HÂ€Â€Â€É ?^€€€lEM+€ZWL€0€&@€
*-€€€ Ƨ€€ժ€]€%€€{€€€L€x€€€[Bܾ!€€W€€9Z8€€€^€€w3€$×™D€€r€€.€T€€€€LC€€€qy€洣1V€€0€€t.Y€€9И€U€€€€n€2€D€d€sb|€#€ €€€̮€}D€AЀ
+common.webtixlsc€C€4€€TEXTMPS €m5 €m5 €€€<ղ/€€%t€vbU€Y€F€€€€€p&#,€6€€浑L€'€gdp€L€€€€€€€! €€l€€€{_F=€€€
€€G€DE€€€€€€€€)€Kd€_:ř4EF8Ìd€€rU€`Ae€`8€[€NM€Z€€€nn€€€a€f€€˔$=€€aZy€€)€VO€1€Z|€*M€AT€€9#)€€€€ €у€f€€€€€€8€@ã€A€€)€L€€
H€€O: +u4p€&€€1S€€€€O5Z€€3€Ny<A€€€L€^€€€€€€€z€€[]€€€€>ϳ€4€€z€7€З€€€€€€€€M€d!€,\€€[€€B J€€€J€€€€g€€€+€lzY€Ƕ€Qr€/Y€r€/€8€ѽ2ϫ€ӷ€€.€ne€€€€oP߬€€⥷€I€#€M&€€89J€€€IO€K€N€p€€՗_€€D€€,vq€ƹ€€Ä?€€€{(s€f^ €y€€€-dn=€J€(s鋡€DV9.€T€2*€&€€>€L€0A€C€U€€€bFR€<€€€€€7€€€€[R€n&€B€a&€Be€z€€€~€€€PCq€€€€&€€€u€€L€27€4Lֽ€Ҭ€€€€D€€E€€kyA€€'€€€-v€€ۤ,€€€y߽€T!1€ €€A€(_€Qw€€€vü€€AY€Ç€€_|,€€o€€€€€€€ۖ€W)€{q"€8€B€S€€I€€€m€/$€€D€e€€n€V€€€"Ç‚LdF€€€x€u€$-q)€€Y€€€€HN€E€c€> €€29€€€€&€ܞ[€Ϩ€+€N€&€)€%>€€-€?~€ +G €w€€€€Qz€€f&2€m/ξ€€HN€€€Q€€€€€€€€4€€€H9}€€€v<€>v€3'€U€€€€€xW2€Ӕ{3€h€€€L/p€F€€gT€€?€€€Y€€€Q*/€€€€cI͞€€t€€@€€ؓâ›Â€n4€(€_€€5V€羽€€€€.:4@€g€€€€€S]€M€€U€PdE€€Ӱ€€€B€€o€€€y€`0X#€ϞL€x €i€f9 T€€€G€o€8Jհ€€€€€Q€\€,!t€C7€%€€/*})€€֎€f€d€€{€€€€€€€€€€€^€0>€€€€/€!8€€€]€€+€€€€ۃl.€-€êŠÂ€Â€È”_z€€€€לG€%€€6€)€€€@8€€q€€׻s€^|€h€€€€yKcÞ‰*GA4€vd€8à¡Š"u D€ű€€€€€€{gIHcT€€:€€S€yHĺ€@f€:€€IL€€€€€€€GX€€€O€-€!`€@e#*>€€DD>€_€€`s'€€'J€€€€€a€?€€e€;#€hٲ€€֞€+€€=€€λ€€Y€"€€b€n€tN€€0i|€€}R€€€K€a€€€€!€€5€€€7,sl'@y€€€.€€o€€€€€€€)x\€€R€€€W€€g€€€€B€€yᇪ€€€(€}s€€€€€€€G€€€N€Y€€€!:€€{€5€`}€路€{€€?€€€€g?€nF+€@€Q€?€@ ϱ/Q€;€5/€€b}€€€˄€ +€€0@X(C€Š€€€€+F€€€> >€(€€€d€€€T€€8€€€€€@€€€9֘€a€€€€€€
€]B€E€€!S€S€m"€=Y\JT€M€=€.€·€n}:3Sl€€h€.:€€\€€€.€€€!€€€€q€€d€m€'
€€Kw€€€^€€E€€€)€XÂ€Â€Â€Â€×²× n;€<€gsU€€€€€€€$r€€€=€"Lw€~€F€€p< €€=€€9€E€€ӯ€€€׫ +€€k€€X}J€€€€€€1@r€A:!€8€€_æ€Â€Â€A€FDNT€y€bbCH€@€@€€L€€:ò8€€[€€€냪€GDH#"€€>Xb€K€€€€€€E€€l€€€
Å‚p[€d€€€€.[G n€€pÊ_€€€6€e€€q€€?€€€D€€B€t€€€€z €€€€€ɩ€€€€j€ €€€|€€€3a€Ȣm5;€€€S`€!€J€€ƀ€C€€}t€€;€€d€ +c€€€$Y9€A11Lk3€€€x+€€+ *€ +€#+q€€;,d_}€A=€€#€(f2€€P4€€€€"Q€MΣV€€€`X m€€€€€I€+€ +4€ €€Qk€€,3€]€leÇ‚8h:€€º.F€€€€3€€d€t€€€€`€T[>€u€;n€m"/d€€5€€d€€It€05€؅l€€€€€c,ìœÂ€cHR€€VÏ¥4P<€\H€€€F€&€€l7$&HF€0€_;$€q]F1€LXJ€{NX€€€€B€€ +}€<J-Z€kKpJc€%€€€\E€€I€un€€$ x€€
€S€€{€E€€=€~€€€€G€7€€€€€€€ €a€€q€€€u0phV&'€v(€€;€7 €€f!€$€€,€3€€€€Ze€kXBQ~P€ €X&€€x€€{(n4€€f€.€€€>p€hO€1€mٔ€€P€€€ €X,lE€€€6T€€€€?,€k F9o€q€€ m€QÆ°y€€i€E€i€*€+}€€€G.$€?`€€j€€M€q€€f€Zr€]?€KL( #€€2]€ܯ€ +€ΘX€€;€;€M€€N€€€€Y€2}€vR' T€yH€rU€€€_€k@€€€€€€MÆ‚uÛ¹-€€c€W€€ +U€,)667€€€\€€4€€€€€3€€7€u,€b€€€€€O€"T€€I[%/t€€€€€'€€e€€€%n~.q€s€7?€€€€o}.€v]+€ €€x€B€€€€c€x€€:€€€y.n€7S€)4€7€J€w#€ݼZj€>€€€€€€€€:s€êœw€qj€€€s€€|€Z€€Ɩ€Y€g€€€€€€z+#€€p€€€€€}€€€€V:€€V€€ݼ€v€€€€€€€€€€€€€€€R$Ad€€€/€€?€,€€`I€[uy€>€܅€6€€H€"B€€w€€€B€€€€€%MH€9WY€€€€€€9( €h€ +€7*Y>€J€3€Y€.x$U"€€Ig€€€6€€ۺ€0€€€Gk€Mp€jQ€€€pK€6€;€7€ރ€€Y€\b€€ւqR^q€€3€m€€AE€;F€€€RK€F€A€€++m#€€€Se35H/€€€€2NYVX€€w€A€rPq;Q€G€€2(€`€€c(€.€€^€Hf€€€Q€€L€V€€€€€m2€nZc€€€€Y'4€€b€1€?w€x Z€Y]i€%`€Y€€€€€m +€
յ€m€€€€€€€€€€hj2/E8hvT€€P=" €€€JiŪF
€€€-Qӟ^AH€5€€mA!>€€€€H€€€;€€M€X€;€҃/€ˆ€.?€[€OxI&€€€!`€€{€bU€~uiT€€Οm€€€€€€{5€PZMʔc€€3I€€@G€ €
$D)Tt€ M€iU +L€€€.Ôª'Z€€€€€F€€€€€€€€€5€h ;U,€G€€€€]f€€€&€€€€a$I€/€4*s€01ڗ€ €Ór8€€l€Ȍ€€€€€i€&€€Rt?1€i'I€ ѯ36€L̔€€D€€r1€€€€|Y€|€)€HB€€€`€y€€ĵ€€€P€Q@€€HC€MN€€fr-€€'€7+€3€`#€\€]€r$aQ€€€€!€E€D€m€&€€I€h€€€€€[€jR€(€€kb€JXC€X +€€p€>€€L€€"S€€*€€=€€M€€kZSX€h€:€€PW€K€€€€9K€?Yn€4W€Z€í§Â€Â€ßžm€€_~€X[Ϸ€€€€€/^~€€€o^€€۷€€€|€€€G€€€€€€€€O€9ywz€<p€€ <Gq€€€`rg€W€€€€€€€€s€ec€€€t€€~0€€€+€Y€V,€€€€[€€€H.€=€N!ÇœÈ|ZX€̈€€i€€]Ó¼9€€J€w€`€€€€€€€d]€ JL€€6<I€2t€€s€D€€h€€v +<€€€€€€Ί€€&e+3€€=€N;€È€"GZn +{€2r€pOBË€Y€€D81€(Ou€€€z€ܧC€Wg€Y*g€€H€€L€{€€€€€€pÛ¾ctx€€€€f{€(ov€€€TÙ€躹jG|Þ›Pby€€;4€€!€€€€€&€€€"*€€€+€R€(€h--# +Qs€€€ͻ€"€€€€€z\€€O6Iw€`€€ڙ€b€`$€=^€€a€0ÇŠ! €Õ€-€€€€L1k€>€€bV€]€€>€€€€}€Y€"€+€€f}*€€s€€€ wB¾€€€€Bao€e€€U€€zډ€~€F(h€<€,€€€kLí¿‘Â€,€€€€€€€>€6€uKF€&€€€€€˕4€€]ɹ6€-€€€€:i€D€€83€€€8€X<€s€€€€;€€p€J€€x€>€{N€€€F€€€&:A€€M€€bk€€€€y€S€€€€€€\b€€€€€@€€€€€oE€I€€oU€懪€!R€€€€€cP%€€܆R_€€€:€€€€U€€y€3€3U€€€/}€€€€€€d€€pgg€x€AoWI€€ʱFX#Z€€OO#SY€f€€€€]€€€6€€aݪ€/€€€3q€€€e€€€|o€0LЇ~Y#€€€€€}€b€:€=€€€{€€%€€€~€€
B€€€<€€€€slY<€jj€€€€€€€[€€€€€€€,@ϥ€ +€€€€€ʀ~G€ש L€€ €€@€€f$Tn€ܼuڻ€€€€p€`!€9m
4\€t€€€€€h€€ێ€Y€re€T€퉌€!€€€f€VG€$€^€nV€€LJ6€
Kxßy7€€C€€€€Y€)€€I€be€M1J€&Y€€€mH"e€€€d€€€€-€vMq€ph€€C€€e€€€~€€€5 +€i€3€€)€@&6Ö Â€
Hw€€€€€€€€§€€}^€l€g€€€€€ +€€€:q[@/:}e&€Y4€܀€p€Z€,€Ã{DfH€€S€%€3€€€€€€€z€€=€€€€rЩ€'2/€€t|í€pGG1€€€€ݶϷ€t9P&€€€h1/€I?€€D€€€m€ +Zˇ̧€@€Q€Ä(€By€ +x(J'€F €KR€F`€€/€€'€€€E@tf€+<ͅ€€€ 2:P€€€85€2€€gDj€€€`€1
€€€z€€KC€€€j€€€€€*€p\€€E€;15N^€€€€€F€€ٕ50€;€€€O5j€€F€€&4̥€0€!eQ€€ܫT`Zk€€€*€€Z\€€€GJ€€€€€&€€,!
+8AM€W]€FX 6€`€€€i€b&ܵp€!€€€€€8€Â€€€'K1€>€€€/nٗ€€Ѿ€W€A€zôI€ BêvVT$-€€€€P+€€€׻bu€€u€€/h€P€<€#€€S!€€€€€JJML€|M€€€€€€X1t(Vh€8€93€^€ij{€}€/€cI
€yT€,€Q€€Q[€{ۯ%?€O^€.QV€î·
`€€€€bųicm€l€{€wz€€€n8I€€€6€€€ʘԼu-€€€p€€3€h.€A€€€€wM€J€€€€J€€!H€k€€€~€l€tL€€-9€CC€€€€J1/€!`€€€C€JWPn€€cW€kp€€€€€3€9€P |€9%€v€G€€X€€€ +€
€b€€=€€€Ó\€ϕAƲu(!}z€€€,€€€€G!d€€€-€٠€\Y€€€€€HC\€6€€€
€€.€€m€Y€€€€€€2€€€€€Y/€5€€€m€֦€K€lx€6B€€3€̱€€€€€€€J€`c€€rQ€XN€€C€
z#;\€€6€޺ o€i€X€€€+a€€€$€€€€J€
€YD~€€€€Gl0€%Bs€Zxv41€j€R$8€€-Ù€€€YF€€E€Ę€ؕӕ€h€€€=H@C@€€t€€€€.€>$€€€R€9€€î“€€€€'€
€W€€h€€€€€;"Ί€BZZ€€€€€€qr€€€€X€€<€€l€€€€€/€€€€m;€Ɉ€~€3€€€z€€€€€l>aRg@PuEÕ‘WÖ·?€W€܃vg€W€€r^€€€i哑€€op€€)k€€€€€€1€€Z€€4€€DP€€B€$€sI3€€€.€€݌BVV=JÖ¯WZ|€€ij€€ŗ )€€O=€€€'€€€€€=€+3€m^€€m€ +€€\€€ˣ€€€@€€0Hk€€€€€€€W-€€b€€]€f +€h€€b€@€€Y€ߖ€€]JŶg'€5]q)€#€&€€€Iĵ €€E7b/`v€€ՖEf49€€Ҏ€X€xl€€h€A€€]Ε€€€€€€^€€H€J+€7 €U€€€€HB€€€ˌIkÈ€€ܗC€ztPLƀ€
€,4€€6€C€f€€€€H4Y=i€4€€€€S€s€)€€w3"G6u{€ߧ3€€{q€€€,V€€€€s€€X€€€J&Y€:€}ɳ€XM€€€e€7€F€K€V€C€6€€€WU€Ré€>€>€€ɂG€€fR€5€H€-€€|€€€€@0€€"€€F'€ߦ€€€nwH9€V&€o .I€<€€E +€fs*X€€>R€Q0,€Ô$U€<€€€0I +<e5c€)h@"€€€_€€€€€€€€&ÝŽJ;Et€€€.€€k€p€€cF€_€€A>€€ݚ€€{r€€€€V*m|0o€€€€)'€"1€€€f€Ai€6{€D€€Ƅ-J€p]€€BZ+€R 7zW€^5€€€E€u€€€:€ڥ4€€`]€T€߲€€?€€€1€j€7€R7z?€Ŋ€€€+€€€5dG€€L*/€€€€€€€€€¥6€X€€€€€"12€D€€{€*€Z€€V€4u€m7€,€€6€€;u€q€о€ql€ll€€€€€€€€-/ €N€€€@BS€M +€€€€m€+'€€;€€}Z_ҳ€×`h€!€'€€€uÖ«6€z€F€€Fd;G€&€€xGKח€€q€€H€€؊w{€€€€€4#K€€€€|€€€y€€u€} €€€€€€o€Xy€€/ߤ€€KTH€sX€€<k€€€i€6€€€€€ +€€xN€€nn€"€-€€7€W€:€qD"C#€€&^€iWQ9iJ€€4€€€€w€!€Aۗ€Ʒ€€€€j㯇}€€€€€n€€€|Q f^6€y€}€1Lhٿ€m€€BD몮s,€SND€€(€*€€g%€,€V€&€&€€€m€Nqñ€€`€2[dk€€Pk€€v €€1€Px€l(€
m€€€or<`€€€€€Վ€€€€]y€B€*€r€vp€€И€< [ac€€€T€5€€€'€r}€y€€€U€ R€€4%'€8€€€€€€*u€€€@բcT€€<iZ€`صC€€€€€|ӱ€sz€)DTa€m€d€€Rޜ€ X€€€Q@zl€€U€Be€r€˦m€€€D<w€Q€€BI€€ȳ€M€€6€€&XQaW€ӎ€c€€˷Y€€€F€
'€€x€(6€kZp)e€x6-/€m€€€€'€н€€7@€*€€]<€€€€F€To€€t€g€€ѼU€D€€€!$=qq €m€€€^Q€)x€W€€|'€€€€eq]€֚€ +€^r€{€€ +վ€y€g€€{/n€€*€€€€€C]€Zxb^€L€<€€€€f€2€€€€€€€€>€ug€ßx€5€€€M-€<ׅ€U~€C€y€€€c2€€€t€h€O€;€€€€€€€€8F€`}f€1€€p0y]€€ݾ€9€ԗu€€€BPp`+€}8n(€€€€kK@:€€b€€€uL€\€,€€€€ki€J€Q€€€H
€L\7r€ӲN€€€!t€€€€k€Ul€€K2€€€
t#€€€=€€€J€€€.€<¨€€"€1׈^N€}€€€€m1€(>w€€€€,€Źq€€€@SW[d8ޫ€s€CH€,€€€R€€l€€€€€_7€C€€0€€'€€€€4z€.€@Jy€€Z,€ٻ€€̾i€€€€€€S̄€@:€A€€€€€€5€€Y€€€€€_€€€€&G€b8€JD€;Kq€€F €€\€€چ€Q€9€€€ €#|H€jgi€ӂ€UBժ€,a€€V€ € Nf€J€ A€р\nFHH€QK)€C€€€€+€܋PSSü`bh€YP€€[ =€€€€Z€2=]CN/,€€8€V_€€AhELJFx€€€.€]€@€S0bD€€#€€A€€v1"q2€fqɒ€4€ܱ€€h€I€'9€c€€€€€€€.€6}4ݵ`€/LBD€
s€B€ջ€f€oNCp>€€€€܉€LW€K€Yт€Z}€€{
€q
YDp€M€'+)X€€W7T€w&€€€€5€€ÈÅ”!€a€€€€€T€j|€€/€€€€€€€_€B<€€€€Ȋqr€F€€f*€r€ϰR€sC€ҵ€?f€€€Q"€B\€€e€€€,€$qb6€1)€֢̉y€d@€7€u€€&&€mlW"€€t0<[€€€€S€BPK€#€€\€€€'€b€€:l€€L€r!*29 +€€<€€̎€€ңD<€€)?€€S +0W€€€€€q€o-€o [€(€€€€×a€€ϫ̡'Rm€ܱ€6)€%ڡʩ€Wc=€ޤ€€h€I€€€:k€€_$€€€\€€{€I€€)€Io1€€ǯ€`€BH€€€€€€>,€Wo€\€€p/ɚ€€€€k€€€€€9Y€€V€€s€€V€€* €c€&mgګ€X€€€€>€)€€ܵ!W€€,€€€h26€ק0P€~€!€€€V?"€€€€€€k€€$€€€(qʺŎ€
€€y€€€€YÉ¡<€?r€y€€€€FZpp€€;€ȟY€9€€ۜ€6 +LB€€€pb3o +€€€v€mE:΢X=gÙª*€ft€!€S€2€,#f1€U߀€?^W`/€$€€wtsw€€€5@€rP€!€€€€€$o€€e€ua€Vʻ€)O €€}€6€bM€€S€€>z€€€€G€€7€:Ĭ€@k6€j€€€€'€o~€4€L€r€€7€^aNzq)kWK;€L€f4p- Ø€€€€€^€U€€<[€€\%€6€€c€€~€€Z=€AF€mf€7=€€€€€€
Gv€€€_€€1C€Cȕ€€€C€€€a^€j}€^+WA+X€€Q€KP€H€WV€€€€w€€5€€qQÅ«Q‹€%€€;€s[€"M€€z€€€c€€€€/€€ö€€€*O€:^€O€;€€_4€O€€€€€2Ҥ€6€€!€mj_d€,2€e}c€€.€€h>€€Mv€A€j€x€€˜w€hRs€€€€€p€€ €€:P"ê¸Â€Ð§@3#€€€H€€PF€\€€€.€w€GW€z€€D]€€5€€־$#l€n€mÜ·_ ;M€€€€€€€X€€Ch€€^€€8€c€"€€€K€u/€€<€Ä€€b€€nZk€ݗ€暬g€€€#k€€€€e€ȗᲾ€€qGz€ vL€€EQ€-"€€€€€€€€€€up€€€€€崞€Ù€€mH€€€€€x€€"€x€
f[`f€€€€jnA€*€U€€d>B€ȗ*d€b€7€€€w}€@€€gbD€€1€{c€€€€€€€io€€B Ô2U€e€ +bK9€q€dc€€€€€D;#vI€a€oel€€ +€€€"€x€€€€tvpp€€o€€
8€€=€&Vh O1€€"€l€”@5€€€[Z€€€ ry€€€:*€€€T€€€ä‹Ê´Â€Â€(€*€m{€€€€]
"Þ¥.p€۹/€VÓg€€P€€kAɤ€CuDG€€<r\€)G€1€€xJ.l€V&-€Y\Â€Â€Â€Â€Â€Â€ê ª"9€€€€&€@€€L€j€€€€Լz€€/€"
€v€€c€€€*€cHp[€ €€ʸ€€⊑ֵDsX€€€€€€0€9€€€AS€|€€[€Y€€€L€R€€€/p€d5€pk€€€€€€€€N€a€@G€€€w%€€c@€:n +€L/e€€<J@€y€]»€{ €€[PJaº +l€€k€>M€x&3ስ€€ja€€,mcc}Z€€=/2€l€€€qQ€€m;€y€:€€E€ z€€t€€€%͊z€8€€€€-;x€€W€Y€̚})€E€€€
,€,€
d€€4€€(€€K|CU€€W€€€€b€_€4€k|€€&€t%€(€txS€I:€€z~9KnTM(m؜v +€!1Qۈ€R€rѻ€€+UH€r€€00$€82€€€€# +€€€ +€n€€J€€€0
x€€€o€sBIlY'L€€t8IC&֌€€88€$j€€€€x€€Az€E€.Z_zPݱG7B€t +:€€)l€V2€€€€c€|€€g€€€€7€+7F€€o€€€€€8€€tvâ¤>€hwW€(Ӭ€€*0€€yaF€)m€Յ€€c€€!€K€c€€€€.€U€€€€€€,€Y€€€€dEq뤴`€]F0€8€€€€,€BN€€M&&J€€ .Z:€'€-€€€€5€ui€@€nm€}€€1Iµ4€ +"5€€€^€€€€0€^€€€*F€€€€€€€V]€x€€€€B€B€€€N€€€€€€⒆€€KԷ€cW€€qLb€€H€€X€.\/€€ +o€€ +N€€p'€€HW€y€€€€g€€C€€€z€:5€€€}-R€€"€]€€€€ Ъ€€!€€’
^3€S€€€€J]ң.r56€bm€e€€1€&€|`wa€€€€6~€0 co€ c€€€Y€B€1€),
C€€ €Pd€€5V€Czx€ǘt €f€V€Ư€€ݶ€bߓ€.€€K€v%le=€ j€€€€€ +€€2€€€ǜ€€€JN€€I€€€^€I€W€€€R@L6€€€-e€€€€Y4H€€€€€^€€€\€€h9jڽԇ€#€€€̆բ€#JV
}€4€€#€€€w€€N7€€€]€4yL€€€l6S€r€€€€ƻi€Þ€€€€O7€€€/€€€€r€€€Z€Tr€€€€€!€€€€*n€qG€€i)€D`€€€,€€M€€z€€%m€
.`€8€VdJ5€€7IHp?€q€R€TVgg€kc€-&€Ş€4€€€@X€€€XyE€>€K[€V€S̉Ԇ€h€"€#€€.".€oP彤)8€€֨j€€€N€€€<€06€2ZjA7N€5€€€VD€€€u€/€#U€€€<€o37€A€^89€0Z2{62*NoD€€@g€€.x-DZ€r€nn€e€NïšÂ€Â€:€€Y€غ;€€`U€€€^2*y€€€z@Kx€T€[€#nZ€2€€F]€€€€бj€€€E€K:uvYR€a€€€L€r€€-€‰Q€€Z€Ju3auK>kGA9€€ѿ€-c€€€1€" +b€\W€€|L +€€{€€€CpIB€€€E +€oiʚ€€€`,€Wb€˾Qpy€+€!€€€2€€€5?€€L€w€€€€€Yu€@€€wuB€€€€[VX€A\€€J€?ؙ€4€g+U€)0̒€E€€€=€f€€€I€BW*€*€€€€€@€€n€T38€
€€€Z;P`_€€!€€€߄€֑€Z€Y€n3д€€nǓ€aÕe€€€._€€€€ʫ €€€'€€i€€€S-€€å€€y +€€:P€S€€f€f3€€IJW{\€"!I€-€€€e€€ ˜€€L<€€v€eds€UsuGPw€€&Ù¶Bv€€t EX€7€€€Z‹l€4€Pɼ€P€A3€;€r9;V€€€I[{€€€`2])€€€€T€
Ƴ3€€H€€€€€ٙGq?8€€\
€€y€€€€€€Ģ€}€_5€8PBRm€J€虞€€R€€8€,A€\٬X€€X9€l@€€€¹>€`TϮ{ҹj€€€€:9€`o€#€€M;€€€N€abv€€п%€f+€€B€L€€€n*\j€€€t?€E€€IRߎ!J>€€o
D€g€€rgFy5M€ȥS +€_€€€\뢓€ÖZ€€]€€v)€€Bs+$gtè¡Â€L0m]T€€€g"q[Dž€}8ʈ€(`k€€eK +€€]€)!€€€€€d€€€wޔ€2.€€x€€p6Zn€€€e€€`\X㡴€€.€p€J€€€m€€€?Y€€€€;€\€`y€4€€€)5F€[5€€q€*€=€€€€J€€€+ W€D(o€K6€>(€€€<€€)g€d€€€{€€€€9ˆy^€€€€€€(p€€€€€€,€€&9€€T!(Úǜؖ€$€tf&.€€=€€$€j F)€€D;Ғ€+:9€€.€ë§Â€.z€€Q85 +€€U€c"y€€>€€€kHx€€€€ÖR€€5€€}9€_4€€XS€êŒÂ€n€€€€€O€€€€€€m€€€€9€€|€€€o۴€€ +€⓯€€3€ς€€t€€€F€€€€Խ ڥ€€&€@€€€{€Ӆ€n€X3€z=;€ɮۘ€g%y€e03Q,K€3€FJ€EO€€VYu€€€0€m€[€€€€3Ҧ€2€A€f€€0=3U€lG€€?mU€x4€€T€soQЫ€€€
€€€€€€€€N€"ZAh€€€€€sM}A.5€PE€ɡ쪑w€j==U€Qq"€€€€S+€G€€P€€_€{€€€2":€~€€q:€N3A€2 +€€!€€€Q€d7{aU€€€€€e€€g6€€€q +€̤€€ˑ€€ €D€64_yX€€O€{€ָf) AL€€€€€9^~€k€€:€z€'€a€`€€€€ F€&Ħ€^A€@H$r€€k€€\€ZR€€€$€€zꩮ)€Y"XR€&
€€€€M;:€ݩ€€|€F€`&€8€-€€@€$€€€€P€€€^€/€€€€€J€Qt€€H€€45€O€€€t€€€€p€€€A€€€pI€€€Ȓ€€b€2*€€€}QzLx€€Q€#€/}'+€€>€€)€e€htBn-€'jZ€^i€ʹ€}c€;€€S€€pUr€€SF[s€Q+ @%€€€€T€€€€u+€ƃpT€€#Z€€앚p.€/€€€€€€T€z>€+€Êèe\€?€v!€dM}/€€€€3€€k]€O€€bDK€€€€H.+Pg\€€€€€D€G&€€M-€€F€€PK€6€€tкk-v€He€E2€€€€t,Â€Â€Ò Â€Â€Â€we€€€D€€e>) +?Ke€€<6€€€ul€&^€W€Gj€€€€q*^>€€€€€bW€(;\Mʲ€Y€€€uf€€€q[O€8kYYNo€€,'buG)€€€€€b5€€€€]€x€ӅH]75€Q0€ki€1{dT€P€€€@i€€΋€:&+€€J€
€€€€d€€€*€€ {€€8€€€"BG>€€ċ}€8€€; €€T€€ +€€u€J<€n7€#Æ‘D€!H€N$$€]zDH€€g€ɽ€n€€I€€€]]̩€L€€€€€€Ψd€u +5€=.7<$€bv€aZ€Dm€€x€€=€€€€o€€€€€#w$€&€m€€+€€|F€€Ņ€@AC.€€e€€'€8€=yV6>€jcíž«A四€p€yf€%€€€€XR!Z€€€O€€€€y€€BZUlRj€^€0€<mAG0€u,€C€B@€2€B€N€H€€€€ω~z'€v€1€€€€€60€ػ€Y!€€KÕƒ.€d€€€(}F€€€€a€€€h|:`€€€"do€€5€€€j€€Þ€zs€и7€;@צ2xG +=€€€€€€€J€€8 €#€€€p Q€!p1I€A€€€€€€e€€aaj€€>6>
€€F€€€€=€ɶ€<x€€j€Hxy)€€€€мbT-€$N]€€€€_V=€€<r€€࿲V€€€hp,U€€Eu€k{€{€&$€t€€_3€3/HO"€€9NЛ €€€Ü€€€TB €€Pv€€4€r~[€€[s€B€€v€€€9€M€ +€@g€)ûJ€v}1NnOY€0€9€_Ï—Z+€mS€'z€€p€€Xz€€€€€€€€€wm(_La*€c€'€%€Ԧ€€€fꀀ"H€€€€€€9€{€€€8€€€€@€B€€f€G;Z€€kAƀ{€`€>€?P€U€i€.€/€€I€-€Gh*3*R€€[>€\*€.Na€E€m€$€*€+S~€€7!%€Å/€X1}€~€[͘€€€7€€€-€Q€€p!€Y€€4€n(L€€5€€N€€€(€€.€€€€€€nN€€5€€v€G>R!€i€1€€ +%%w€Iwvp<€€伺L€€u€€€_€€€€:€€€€€€}€€8@N`N€G€߮€€€€€_xL59€r€€k€€Axpe€편€S$c]€€n€,.€xf€€€'Z€€C5€0€}XK€_3€€[,€ԋy4€€€t +€€€ꂊ€:%j€€€.€€€x1,€+€€€1&€€€o€€nV+€€€!€€€€€€NA€eqF€€€ c€% -€:€IS€n>k€lH€S19h€€€zA}€Iq€€€€"€M0€ wT€€€C€€5T€€€€€€€V€!)€jl €N12m€4€€Lò€U&€V€{€,€€€n€€€€€{€@(,€d€l €5€€€>jzӥ€€€€€€:2€€"€s]t€)€€؉€€€€€N:V€€ €B€€€ +€€'a€€#\pVI€€|/€€.€zd<i€0€!€[€M€€€€
€N€j€p֣VL7€jqAMam€Oa€€€€€p€€ +€€Ub€@:€A€€€8€€:€V€0€DXނ€ €o€<€U€€e$B"G€nc€€€€€€€d€€:o€M
€$̪ؔ€€€€쌌€€[#ʮ€L€€€jDES€;€L€t€x:€X€L>f€h€P€€c€d€€x€€€€pf80o€.Q€
( €M3€5€€€1Dz€€|€%Q€9~€€€€N€췧€&€4ØQ€ ʜ€€€;9€€_tw>€ʰ€<ĩ€€.>€€€e5€x€*e€J€q>€G€€ +€€€€b€€B.€€€)€€͇€€&~€€uݙ€€y€€€II)€€€€€€U- €-}€
Ë€€|j€>~€BJff+€€R`﷙€€€\€Pm€€6€k€€€R€H€t6€€€n 2€€.Ä•Iu6€7d5€(€€€쮾€€)€€Êcn€,€€€~€/u€€r +)€4Q`€.€€€€€€h€4m€7€€Q€K€L<€`W;€<$E.€yb€Ŧ&[€L(€K#€fpH#€€\r€D,€"€=Em€€€€]€€Q €9Q€€€6€z€s}€€Ź€€€)€c€€Ir€€k€€E€$_€€€€€w €€/€€€tq€€€€u€€€€€€v
o€€€€}€€n€€i€€V?G€€<布€€€€ +€€€3€Ք(€d€u€J[€/k޽?€t€€€€€b€€@T€離€^€3L92€€€€€€~€€€€t"M€€€€€€:F;€€€t€€€€#€]㴇€€€€€b4€z+H€€7€d€€€€€€€€€€d€€€€€#€€(€Km€b€€,€&€€ +?€€€"€'€v€`܌€€€4+€€g1t€u#:X€€T€€Hp€€wpH€€€€€'€€.€€S€€ +JR€€€̘2$€6€<_€€_€
5-€B&-`€`€€K€€#€€€€v€a=\€€r€€N-€b€€:€€€Ժ€Lnӥ€€€xJ1,€W'K€€0h0€0˷€(%L€€KZ1€€€dq€'€f|€€€€€|<W€J€%€€€n€w€€€I€€€€€€4ë–€f€€k€L€€4€€6€€nj€€a>€1c€€^€€€{€€t€€4€y$+€€€h0€€€€€k€0€€€K8Y;€€6̚€FM'Ü«Q +T
\€P€€)€€h€€€B€ݘ€b€€€tÒ“))g,U€/Ws€€r|€€€+€€R€€€f€€€€€m€€l?€€)€€€W>mT€€€gb€€€€.Ù®Y€€]€€€€€€VP€€W€€€ n€I€~€€€K1J€Y€P€€€€€€€€L€d€€!€vVAa€w€Ì€€ޙ€X€ߔw€€€R€`€v€p€ q]ڬ€b€Q??"€€€€m€€^ט€€€T€€4€31T{€€€9€آ€I€€C_֬€qT€€8€€€€(Òd€€€
w`€x€`€<€€[w€f€"€€€€€-€R€€fI€Yf€ +€€L€€€G€€v€`08€€€€1€€I€2ÃŽmS€€€€€€€€€en5.q€A€W€3€n€€€9€€^ +€€€u+<€/€U€j€7€€[€.€{R€€/€€>8€C €Y€€;L€€€h€€d€Z0n€6/€7€ȕ䒗¶j9€K&€ȴ€€€€KpV@Ö»2Æ¥X?p4€#€s€€,€4€Ï€P€€€=€%€€€€KW€ǜ€ɳ̲d€f;,s€€m:€€㼳€€€€Z}€V~€õ€€€€/Kfq€{}ք€€€€€€€<=€€w€€€€€r€W€-a=xP{€€k€^€6[x€€;€€€s€€€.Zl;KÆ Â€0€i€m€n9€€€Q+€€Th€6€€y€S€€€Z€€w€€€€1€O€?5€؋€€/€€€}€b€>!+€€&+€€€€\€€€€€t€yp€€€€G€€€€hI€_'q€€€g€ +€€€€]K9€€{€€€
€]:€7^€ozjblX€€€J3€€€€€Ϸ%%s€?€J€€cÄ€€4o€>€=€o5€€€€€€E€€Д€€_59€lV4:D€€€€5€€€J€N€€JÅš'€_€Hz€€F€J7€€€2ILP€€,€mK€€_€uuN€€€€]€€€€e€~.J€€€ǞP
€€2W€€€€€€€#€;:€hH€K€g +(h€
€)S€€€,€€r€]€€€€ +€€€€4Qzko€€<€€€O€€€€€1€;xZ€C€(€"€&€v€iک€v3^€m€v€B\€`=€€€,`€L€€€=ќ€~"1E€ñ€j#€€€€€k€[o€n`€dzˊ€u4€t€€€ѣ€+-~NL€€tbfx€}o,€€3€€t€€}",€€€Թ^κ€{€f€€]m€€(€€€xj€€}€=US€v€€+Y€€|€T€4€€€
cycle.awkbtixlsc€€€6€€€TEXT€€&K€€&LX€€a +€€ €€rz€€ԉ=€€`G€#3J€€Q€+ó#€x=]߀{€€#+Y €€€€G€'€n%FP€r€@€ҋ€Z€ ieB(K€€€€€€5€€>u€€€€€€7€€u€€ٖ€€\€€€E>€€l€D€a€oW0€#;€€€V€v€€7€€€hV +o~€€ +€3€"^€}€€Hx2€€€€}€]mIQ +i€}€M€,€&€€x=O€€>€xw€%Öq€@099L€€€*€R-€ +€O€€"~o㈾€€€*f€X€€q€€€;l€ +€x€pxhH$:€IEmycocjҀ€N€€€>e€€€€1€1€o€€"€s]d´텎€€M€zx€p€y€z}€€€€€#€€X}i€€^oZu€s€€Qg_€€€XG€e€€€G€jx€€Z}€€>€€I€€€~l€~+ZÕ¢|I€€Ƹ)€P€qF€€€Z€€q?€.MRHpy€&J\(F€Bv}\€%€O€€q€*#€o0@(9€€€€€T€c€€s!P€€<€cm€€T€€>€F€€€Y€€€Mbya€€b€=€9 € +0zfY€ʸH€A€a[€€€€ڀ€
cycle.webbtixlscb4;L€€TEXTMPS €m5!€m5!€Q4€.~NW€x€`€~€€z€<~€<€[€€P¼:J€ €€pJ8€'?€€€Sz€€"€€59€€€€€€9€y~€89Næœ f€€
,€Em9wz€€€€€€€Ժ"1t€^ͻt6€{<Ѕ€*qiF€€€T'A€h€.-
M€€€:r+€r€J€€'k€9|>A\X€H€I€€t€+Ec€+€xv€€€€?^BO!ST&N€@#€T€€GQ€ݑ +x€fB€<͑
^Im€€€€€1€Ύ€0€€€€€€€€€€€€€%͜Fm0͵be€€€|.€t€d€€€r€€=€e€€€€qiz€'€€%€OF€€yJ€(r€€.H€Y€Ы€rAA +€€MR€€J€{€ɸv€€G€€%€Ps€€`€€i€€Rnm€1nzWLJ?/{љQ€3;€G€€PjMP€(€̞€€ €€€€@!K€R€€€SN€'b€hR€Dž1€Q€}€
í½°`€]€q0v€hg€€d[€u€nGW€F€€€1€P€€€"3<f:€yS€€yngL€€3€K €€€€€€€€'€€€€€$cE€m€€P€€L€T3€A€d€€X€YmR[pN €_€S€€W`,`€€€€€:€€€V€€#€*€€/€x8€̺;€€[OEa€'€B€€]€€B€-€€€Nh
o€€€ݦ4€ I€<d€|€H€{RL€f{zQk{€`€€8:€€€€€5€€€€&n€C€X€€n€:€c€ވ€€€€€€€€څ`56݈€€gj€€Þv&ο (€€EB€]jÞ˜f€0€€€Z€€€€һ€€€P:€ˡy€a{€€.€€€مs€€€€€a€€€#€k€€A,€€K-o€€^€€€€k€€]€R?&C}Ê°s€€Z€€g_5ۦϲ +€V€o Y€̀€€Tk€UX€Q€*€y,(€PY€€€+g9~€t:s|€m€ء€U€€'x€b€*Þ€€€€$M7€ G€*€B€€=€Y2€?€€€€5€€€€S€M€Z_=€yI*€€s€t€Z-Q9€&Q€€qQ€€€nu€T
,€n€€€^€€;€_€X7+€1Ó€ f€s€€uX^ €€kأ€€€iW€€€€|€€€€]€f€g#€€*€6€€€n€q€€NG€Y€[€]€G{€n€€t€€u€€?€€€@€%€€€+€€€O€$€'@€€Jc€7€B€8€€€€/€€€€€€€€€€€€€
junk.listbtixlsc€q6€<9€€TEXTMPS €m5(€m5(€}€>€€Q€j€6Ri€€ZA€€
6€0€€€PrÔ—.Z€Z<€€0r€€A7€€PX€€|€@€0€€€€€€€?€W€%b€0€€ plN€v€<€€0€ꇼ€B€€ܘ€€HNz€P€!b€€€ËY€ZZR €
Make.prettyixlsc0€;L=€€€TEXTMPS €m5$€m5$€}\=sQ€€€€ȟ€`€€Qk@z6€A€€€;+€˖€7;L€€€}n€a€.€€€€€Z€A€pa€d@P2€þ0€€`6€€€"€€g€€~€€€€2€A€€]€€€m\$€€Ö|!€~€€`€€€€N€V€€€€#E(€€rԗ€#€"€€>$&€u0€Ì€iZ€€€€Ar0€€E>€€€€€€0Â€Â€Æ Â€8W€Ȼ€}n/€-€A_€?€€Q<€$w€€€€șN€€<c M€€|€
€€€€€€D'€€€€{€€a
Makefilettyixlsc€s<9?€€TEXTMPS €m5'€m5'€€€€Z€Q€€€€ȟ€`€€Qk@z6€A€€€;+€˖€7;L€€€}n€a€.€€€€€Z€A€pa€d@P2€þ0€€`6€€€"€€g€€~€€€€2€A€€]€€€m\$€€Ö|!€~€€`€€€B{€€F€€`v€5s!€€€ €€€€€ +€€(€3€4€€€7'€'o€$o€€€€€FaRK9ߓ€{~I€ة€x!€.LJ€5€Rm€B€€€€|K#€0̱>€ÂJ!$#Þ‰4€€€€%e€€€
multitang.chxlsc€€=€D€€€TEXTMPS €m5€€EH€ +€€€€X€u€vb€€€€f€€t€Ǒ€€€! €MC€|Y€2" K€€€€€€gv€aO€€€€€ze€€€4: +P€ql€</ϒ€€€
€€€€M€8X€€J€€€€S7€€€S+^€IӺ€€9€€aw€T€€9#)€€(b =€i6€€;€>€>|€S€"€€V6*w€3€€€c€€€1f€R€€€€FB€3&[NW€€|%€o€€€;€€€€€a€€焓€#O€€`€€`€ӕ€Ϩ€n=€~€€€€€€€rr€€8A#9}€5€€€/€€켲"Z€O=€A€T€)€€DQifx1€Nu,€6yI€€u€€€€?€€€v
Ò–:€hQh€€€&€Y€Y=€€:S€3€€S]Ò*€T€€<[^€NI€€ +R€€_€€€€UB€%€€€`-t^Z%2€?€€€Pd%-€ €δ6
€€€€k€€€q€U€eV€-I€Aذ€C€€2€€€€g8r€€\p>[€€q€$S€ +Xo€€€€€€'€€€€> Gٙ€b,©€€€€€€€"€€̸€€E€P€€hn<€€€ڊ€€€R€€U€.€€Qy2ګ€E<€€€€c€€}:€8€,€Z€֊L€€€#/€€0b€W€€'€€€€€€o€€€Y€€ED€d&o€€X€€>€ g€€&O€6t`C<Ҷڤ€b[:€ X€€u€a5€€R€6W€w€HT\€€€Ý€€5€H_€€s€^€€€€€€Âf€b€<€"€€€€€€$€~=k+.I€؋zJ€rq€A€I€8T€ +cf€g€B6A€€€$€€Cܺ€€€€Po€E€€43€€€€^6€}€€a€€€v€€m€i€!€€€€€€€T€yÂ€Ó y€A:€<€€T€i€€4ӹ€€€y€€€€X€€€7€€€€:€W_l€€€qĵ€h€FQ
€€]a€jv€€€7€€€€€€.JlE€€0€d€€dgL€Ʊo€€€T\4€€€€8€\€€€€€<€€i€3/L€p€
€€#v€Blť3€a9Uc€)€€c€@€m6Ԏ€€甌€€€K€B€€€€€sOc€€~:8hs˔€€€€2x\݀7 ?€€€%€uޥ€€e€癡€€€>€߄€€€€€83€ +|5€€ S€9€€€)np€z!€€.€F*€̂€€F€€€Lʎ€€f€€N[4ִ€€Ʀ.|Y=i}m€ƚYA€€€€€€€ €'€€%€͖߸UB+՟€€€bt_€€€`€\€€€€К[Z}~C€ €€€,€0€€€o€€€Sf%؆EC?X€4Q€.€€#J€€€€€U€€€€
€€€e€€€€€€€&QW€€Z7€G€GT€?€€^€€G]€Oj7,X?_€€v|~€'E,A€N€S€},s€€€ +€Î€€€s0*€€Ek
€€€ٚGu7€€N€€€€€)€€€€c€€€€€0^([y€3€€I€€€ !€+€€h€I€€oQ|€
newdefs.awkhxlscI€?E€€€4@TEXTMPS €CD €CD €€c€P€Q€j€a€`<0€!`€,€H6€w2€a€€€/€€c?€y€€€€>€
x€<€€€[z`€0)" €7Km€Mm&€v€€€€)€ €€o€LT€+80€€€(7€€€€€J@3b€h&"€€€€"€B€~X8H8 €<€
+nodups.awkkhxlscÝD€F€€€TEXT€€&L€€&M€€?€€LQ€j€6€h€€ZA€€
€ €€!r€5€"€ d€|!€Mc€^€€K€f€€؇€ᜀ€€€€€S~€?€g€k€4k$€€!€€!,2"€x96€€€€€€Y>€€v€LC€€€"€€)O€E6€€€Ï€€€AB^€^€r€UKK€e€€ obj`€E€G€€€GC€€€€€AFp€c!! SpiderWEB €ourcG€ +F€F€€€€Q€€Q€l€€€
pathopen.choxlscČF€KE€€TEXTMPS €€€€=€€€€%€€€€€€€vbU€D€*I€€6€t€€€€€2€€F:€€€€ƣ€€R€<N€€€3€€#E_€a€€€T€@αN€€DH*€2€€€)€€€ʙiD€0&€€b€€GR€€p€€#€4€€YQ*p+€3€ ,€R&Π,€:€€€"̲2€9€*€€K€€L*Mn€€€vў€L€€€€€I€€I€&€O€L€€L€L€€mN€)€€€9`€g€Y€€'5{€€`6‘€€€€€t&ַ€
€ €: +u4p€&€€1S€€€€O5Zj€~€ +N)y€`*9z:€€€:2`€)>€€€€c€(9€J€#O€J€€€€€€p€sek€€ €\GOF80ÂŒ0€F@%Ì£ +€@€BIs€€€B€#€€€m€€ʺ{€€€€€m>€J€^€q€_€€€€€NV +€€€€Rk€!€ǬR89€€€€€€&€€€kՑ€€3€€t€=€€IB€k€Y€ч€€A€0€+X€)€€ €€KS€f5€${€EK€€N€€Z7x€T€UJ€;€M€j3€€=€€ܽ l€]€€~€\ h€€€fIx*€€€€€€€*ë €Â€h€€%€€€€€z€€O€€€€€€3Fdb^€€]€p€0€€€QPР€#œ€€€w€€€!S€$€€8€€€€€t€z€E.€€\€_r€€C€ľ\€G/€€€€€€^€€€Ú€€p!€€Fo€,+'€€€€|€€zDE€S8€ѳ€€€€t<€c€.€€€l$€4€Ş€!€€g€€€€,gS7v
~H€oq.€€祗\€€Qr€R€}€qk1€W€€€mQ€€€mD7€9€€竫€€€ۼ€vf€[€ـ€y3€€~€€€€€v!48€€@€Ү€€€?
pathopen.webxlsc€+G€V/€€TEXTMPS €m5$€m5$€€€ }€€ks€y€vbUw€€D€p€€)€€€€0_€K€"€ˑ€g€€€ƣ€€€~5=€€PRÏ?€N:{€€~€˨W`€€N€€Y2-_'€IN€)€€€F\'"€j€-Td€F€kÕŠI€€€€ɔ1$%€€€€€QA33€€jp€h€€x_€Z€€€€€<NT_€€DefqǢ€€ÉtMw€c}€fÌ™A"€ *x€€€€€b€ € +@t€g€Y€€q€€E7p€€€€€€€t&€X€Õ€78 +u4p€&€€1S€€€€O5Zj߳€NW€€€;u€V€eG€€le€F€t€€lFX€Y€w€€€l€€€s=%€€€^€Z€€6A?Z€€€€€€€€€Fn€M~€€&€M€€'€€€€[}IOl€)€*€t€€_C€zn€u€€€h€€fL€&€€R;€qJ€€€€€€v€Kze€TS€tBK[R€.)€€€N;€y€€€€m€€€س€€€€€€ִ4€€'߾€€€€o€€€<€TS€:€€€R€ޖ€€^.€€€€81yb€Ea€€€€€|€U€€y€K€T1€€W€qÐTX€/&€:O€€€€€€bƓ€€F€€€"3€8€x€-t€€>€<È€\€ڹ€4Ù¦u+€ʃ]cuZ€Bg€€<€0^\j€€€͂€€7A€+tl€€&>€(€QBvIÞ¬5€b€GY&€%€€€€7˛€€b€i,u€E1\>7а[ƒ¾A=Q€F€€€€€€€€€L€N€G€(€€€€€€Ƨ€5IO0;€€(€€€€^€€€€,€"T1€€€V€cb€U.Qtt€I€+l€Y€€X€Ľ5€Z€qFz.>:€€ٽ€Y€€#zj€F€YA€€E€€{}€8+9Ω€€2Jt€€_L~€O€&€)fTo€b€€N€Wz}{q€mqt̾69€€€ >€€q€€€ӟYÄ¥Zص€€o€|Y€€€%€4VS€5EyB€"_€z{€Y€5€J€€€.H`A€€/n€y€æ’€2Q}P€V€€x€-€AU€€€8€37UxH€€€€"€m€ +€8Æ….€€€€b>€`KQ€U €€p:É€€c€B=&€d +6H€F€€8]B%€X€€E€€€(€U€GI‘€38h€V>N€€€D€€;6R€d~€€`€€€.KS:€ƪZ3fab€€€g€j€€€v€#€`֘€€׼7€awlqp€6€€oW€€[€€€€i`4€€€̶FH_€€€3hR€€J€E€€€d5 €nZi€€€€€€_=€9=8b€€|@D€秈€̟€€€]u€g؃>E€ţ€0J$6€ܰ€€Æ€%a€X€`€@€)[€€€*$€o&z€%€€€€?<€P€zQ€sꣻG€`€€+€1e€'G€Ch;Ѭ€:€&nlM€€€Uq€1€€`9€€(γ€N€a€zLj€s€€U€vWa€€VZ€€҃€o9€€ɬ€€\N1€€€€̞€q€€€nM€€<€(j€€2)2€m€4(+UNX€%V€+€€_v€n€€wÞ¡`_€€)wztZ€€U€€$€€€2€A_€€i€€€^aO€T€D`L€NvÖœE€ +€3k€ʥ€*€L€Z€=€/€J€€=+q*XG€x€՗€5€j€€€€Xh€ș€ !'&€€€+€€€"€€€1€€€Ky€BSNe€uu€n€€#:€2€€Lo٠€u€X +€.€|zu€€€€2O€€}€€€'A>€€€Kt€€€€]WOH€=€€V€a€€€€!nR€€€Vb€R€jS3€€€K[!Y€€E=€6o€"K,€€vlt€_€U86q"}€[K€€%Ҳ€kz€K;QuC€Cg€€€€€R€OQl€€̸€qcd3Z€€€×€7€u€€Z€€€q€$€€4 +V€ )=€A6 €€€€€)?Ap€*€€ nk€€ €N.€€€S€o€KS€Cà h€M-€€D€€€g€7€ѯ€€€€0v€€W€€€€yg€€y€€O€ + €c".%€€ٽi;&€€s€€Aۛڀ>E€+of€€€€€f€€¦€€€€€Y|m€G€B€.€€}€€€4U]€A€RG>€O6€€sÒ©mO=€c€z€5€8U€€~€Y€T€"Y<€qi4}€€lV=€€IP€€(5t4€&I€€€€&€€€€z€y'€P€€€€f€a4bU[€€€€€€ €h€€€ZN.{€J€c
€% Jnݪ€܄€€€Z?€€€,F€BM1€x€F€l€&€=€L&Çf|<€€€_€5€8u€€T€€O?nݧ۷%4€x€1€zʟ€€€-twx€,
€€€y€€pK€€v€C€O=΅€&€€w€€€€ϾtM€€W€҅€€€€`l€u€ã†:€-CxrÇ€r€€d€€€€AÊ‚{7fG€{G€#Q€*€€?€€€€!
€€H€Ή&€<N:€a€€%€ޕe€xH!€€Cg€€
€aBl€@r€>€€K~†jh€€€€y€ۜ€€€\€€K€T€€^€€{€'P€5€N€€u1€z€. Y€!€€€V€J`c€€?po€'ق€€*3€€4J€PLB(€€Z~Yn€€€€€ۓ€€%€B(9<€ €€Ä€€XȻ€b€€€€(h€ucD€€€Q€€€€€€€N€~€l€l€v€K€ €Hv€b€q&€€B€C€o}€€,๴€.€€€bv€b€€€UP`i€}€€K€a3|€€€€^€€€€A#€€md€è§.K€C8€ +*{=€<€€€ʃ€6€\B
€e€gz€|b€$}€€Mv€€`[€I=€ʊA\€€€€z€€€ÐF`
€qPܣV€€c€?6€Q€€€m€€L€€€˟€€Y€XS€X'€€€€€€ €€€G€2€b€Kx€rfp€e€€€$D€€€wy€€€J€€
>@€EN€€€(
_9€O p€c€€€i3€€€€€€€€€€€€ +pretty.awkebxlsc€ +KEV€€€h@TEXTMPS €CD €CD %%€nx€/^\\Y/,/\\par$/ {print; next}
{next}
+spider.awkebxlsc€WV/€€€€TEXT€€&€€&Jy€,Q€(€€d€€Z/=€6d€q€-€,B9€€>᳕€ +€<€€€€۲zq€€l€€€f€]^€4€'۫€/€€W[jpG€€Su€du5{ee€€€€€€R]g€o€€s>w:^€€€€۟€ݶ3€€ٽ€m€€3€€€€€8€€€€w€~€€€g+€€UÕ‡]€€€€ڹ_kw€€=€€€Râ‘€€€€*~€Y3€€r2€_k€f€€4€€€ €€€Ρk€€€A€€€€€,€€֣€f/FU€/€€4€b€€€ϟ€n/Hݹ€ €€Z^۱€€€3hbr€€€€€^ë“>|€€€€o€vT+A€=€€xC€6i€€€€€€gC€%6mI€lIy€%€_k€|€€€K€F€€€€k€€€/€€=?€X1€€kv€t€etdhDyQ€€h~€T€€€€qN€S€€€p€€€€€€€€€
_O€H*€ E€I€.€Z{€€v€> €q|T?€€~8€€6€Ͷlf[€€mn€€A€€۟@€'€€€ҖiV=€€€€€€'€?€€€€:€€2ou\?3€Ќ4&€€€€€€€S€€€q0€€V€€€€€(€€U/.ק€O€€k;AZj€€€~€m=€€€€€€]€&€€€i€€€€s௜€€€w€€ĀV-€€ +€5€€:€€€1W€NjI#€j€.Ts€`€€?H€]/p€\g€zX3O€̷LF€€I€€W6€A€€ƻ€€Ņ€€#€€€€€4€~€€€€Mz€€€€€v€€€/€j€€Î€Ja €s€€€k
€€Ǖ€sGLa\€A€€%€€€€{8O€€€z€€€^€€€€L=x~€€*pU=€€4€}€d€?YU€€€4€€€z€'€€€€€€5€€€€u€€€E€)b!€€€P€€€€9€7€€€€I€S€€z*|€€x>€€:€k€€€o€#€€€€<u€$jٕ€€F€€€€%͙€€<€€V€Y7€n>[ᬉu5€#䕞€4€€]R€a€j^3Y€€6€€€€7 maʜ€€ `K<€o€$€€3€N€€Ԉ€€€€,€€+FRp€€!3p€€"€$8f
€se5>€Qr{€€€~€ <z@Ô‚^€€zE9€€€s€€j€€€€7Xskf€€€€{€o€?[q€֮€5€ĸS€fcc€W]€€€€€K€€€6€jv€€€\ð€Zֳ€r=Ã’jgQR|s€€U€a€>€€€=€€€'5R€€€A€;x€€ְ7pZ€~€€#hR€q"A8€}6€€U7€€z€f*}€€€€@/_P€9€Q0 +c`P€€L€v€P€9€€€j€iGd€€€€€n€î½Â€
€€€€€€€€€i€|€Z€€€m€F ؓ€(€€.E"j!WÕˆ&€€V€€€(€.€B)€ì©~€€:€;€€9~€F`5€€€a€€](€<)€€€y€€D€€i-€€€'U{€€×€€|€ܱ€€8€n€€nG€˩€€€€€!6€XD˔€\@€€€t\[6€€N €<€€€€E)F€U;f9€W€S(x€Ը€kÈk0Z\0€#
€€ե€€:?ɉ/t],Z€N
m€HP€l€€"z€€€<€€€+€€N€Z_Z€HU{q€C€y€€€m€€€8€€۶€€€>X€€€(D€#€v"Y<>€€Cohu€~`í»Ÿ;VS€€ €]Y\n€ު€R6f€V€Z;]X:€"€u€5€sv€€€€€^€8€y€€€€u€€z€€€^€`€€€€€c€>€FT5W€€Z€€Rä¢j€/€+€6=€P€€€h€m€€€K€}€€k[\8€o\€€€€€ۖ۳hU€O€€€€€€€Q€€^€€€€€\"€€K4€€sIgt€Ž.Y€N€LW8€€€R€€€€€(€€Z€y€€€€€U€€_€€€€€I|€€€€€F€€€€>?€V€t>€IY€t€€-41€€.€'€q0€€u)€€€.€€€€€ج€€X9Bc€€€;ö€€€€+HNͯ€€֥ȿ:€€€,D€F 9€€d€8LNb€YL:€€_€€€€x€@lJ|Ox*Ei1Z€€€€€€€€€€/€€f€76q€€€€=€ \€€€€Ȟ€d€hq€€.€€0V=€Rd€€jG€@hå¹S€€€€€€(5€€i€Y€€€3€€p€zZs{m€隮€N=€€€<€€€W€€cj
U€Բ€0€€€€€€. +€ +€iT€€€a€€EuSV8€Y€a€€€€H€€€R€€GE€>€€È@W0ZZi€I€#F՞€)t€C8_X6€€j€OnܹsC<€8€€€€=€'R€€€#€AVD/€€€u€
€€€W€€Whk}€f€4€\€ÈS€Ⱦ€€@T#QR€€j€L€qj€€€1€҈€Ç€€%€鵺€€z€€_O€;^+c€€€€k€,!€€€Cj€€€€€t€t9AS*>€€€€3€qÍ¿A€Qr6€6?€€€€!€€ۯ€€Rx€=ۚ€'hz€'n€€p€UmLWE€l€€9€€=g +€^€<€€JRw€€7j€Oe€7€€€€D€€€€€€9€P0€€KЦ€k N€
€%B4?fi$*€€4€€~€€%€`-€€D€€T€y€€4€|Ԏ}€€€€€€€X1R6@€€€B^ o;€€€€€€€J€V€#€e43>5DhׯE€€բ6ת€.`a%r€d€€d€€V€€N€€€<€€p>€ʢ€€€bd€O€Qu€f##<€€e€Q\(!^Y€qۮ\P€(>€€€€QGq€€€8€€€B"b€€@e€4€e€G_€iRZ=R€€€
€T{€\ݼ~€j€ʟ65xf€€€R}P€mT€€€€W€߳€hs€[.€€4€j€€Xr€€€>W€'Z9g`€#€=€2u2O€tz€%€NÏ¿#€%C€(J€U€!R€8€€.€€€a|5O€€|€€€€ѽ€€xE€€-€L€€e&O€€A€-C€80,€€jR€ȓͤw€€€€€)€|T}C€( +€K€€€€p€€€€€€€1-€€s€€€!T€#FG(d€;Gm€1€€€€SS1wb€9M€9€aπq€/ €€pg&€€€€6Û–:Gt|€f€;DyD€€€H΀1v.€"€€€$€tD|QH€€.6d74€€€€|D€€€€}€ €€F€s€€€€i€€€€€W€€€׵€(jÜŽQ5€9€5€€€U€2"€€Ap€€€r€Xh€p€r€s!€m€€r€e€j; +€m€€€€8"€€S€€^w{}€€€€3€9€B=QYFV€N€Bt€* b€€E€H€~nG€6€€֮€€€€n€€€צ€€€€x:€€€€€Z€Q€$1d€g€J€€€€€€FA€ìµÂ€.$H€b€€€%c_OIh€h€LL€€€;€<^€€v. €€€p€€€J=€L+€W<Y€€o€.€€€b=f1€;ws`€€k€:€€dc€€€+"Ï´\€D€7Þ™.€€€€€!5M€N€€W€/j€l€~€€€€€€€8&K€€€€€!€ENBz€!€X€€8€€€#€X€€6€€€€Z€€u€€€€€-€p3€€€-߀ .y5>^C€
(8€F€€€€€}@€€€f€€Ŧ€€€€€,,€€€ €z€€€€€6€\€€B€€€s€h€€*€€>€€€/€(cC$2d€€nlߺ€€x
&€€€€.€€7€€€€Ց +€€€ڨ€$€€RH€€€)€0€€#:ndi€V€y€€z€€€€^€€0€€t0€€9€€€€€Ò€ aio€€€5VÂ€Â€Ø K€€8z€x€&€€i#4h€/e€€sY€€"ؓ€%€€b€c€6 €`T€€€€€2€€P€*€€_€€L€€€@.€€q€€€€€€R€€€€€€€€z€ €|i€€€V€=W€€
€L€€€r€R2A€€€€$€€Y'?̛€S€€\s€TE}€€v€€YR_€€鋦€]€w€€NB€de?€x€C€€€€€V€€G€燥€€Q€€A€€€HW€€+kp?{€d€€€N€€€€€1€€;€€€€Obe€€4€€€AC<€HO&[€5€ױZt€A€€~€€PQ€M €F€€Na€€€Sl€?`€€Y€WJs€ c€y€€€2€€+€I€€}€6Ir€e}_@q€€4€€€€j +€€f€€€€€€\€€pEA€€€€€€$R€y$颧€€C +͖€h€K€€M€'€€€€[€€€G€<€€€€+€x"VJ€A€Z€R€€9ë€}€=)h€€€/(€€ qa€.€€-€€k€€:б€€(0€€€3Ç“;€dt€€€€M<€€a€ٵ€€~}+B€>+]€€N€€€€€-ړ€@€* €€€€ LEXa€Ш€Ύ€€d€€]€€H`M$ u@k€SI€vj€Y7€€$_€&€s€€€€i@jD€€8€€/h€€\ai€€€€U€€ OTP€€~ߤ€o€؞€?h€0€C<:x0€€€z€M⇶€P€h€?K€~ʼnoN +€B€Π€V€€€€€g€$€b€€€u6q7M€0=*€€Ȅh€€7a€€*€i€XL€*h€-)€mK€€€€60€€€['€ZC€*g€'m뚿€J€€t1]€"€€X€bz€€€€\Y€CV€€v€pa€€€€!nf2;€€A€Atq€Q|>C`€€€Äw€€€_d;€€€€&~o€G€€*€€€
€€€€GM8€€€€a€ChQ€TJ€€6€€€ +9fU€€:€€€€Ë€€ €€<€0€ +€€€?m%€}۫€l€..}HQ|€€'€€€t€F +:Í€3rE€€bI€€j€€€€ +€Y€n<v€q€€€€H€€m€|€+ى€1€+t€@€€D€Q€f[€"u€€€wfpB€nK€$€€€G.€€Ӹ€€€€!€€l4€€ӕ€r€€]P#€€€'JǤ€€€€"€€€a4#€€8Q`p€€l>vX#Â€È {^3€€<€4€8€€€:€a€2€€N€€€€8F€€€€€&{€ǪJb€€€€€€€€€>€k€€€€o€€%€HU€€€€X€€€€q=#€*0c€€I€S€L€S€€€€€((J&1€p€€Ð€9€€L^@€€k€€€€*dŽ€€X?€BL€V
mu€€[_€€bWdM€€€€€Z?€€_€€€Ĝ€
€bJ€h€€€€Q€€€€yz +€M€+r'0€w?O*QaN(€)Ժ€€€€N€€E€€|R€̈řW5~€€6€4€T€€Ȍ€A1€q /v€€;€€,4U€
€€€ό€€ID#Q€Cd€D€Hv€4?ϯWf€€€!o€5H0€K€€.€€G€€€€€€€€€€u€fe€€€WTK€F€€j€y€,€/h +€b€€nL€€€`M&/j€ wU€€(Ʋ$€€€)]€€R|€€€€/€€1i͆€Djn€€€ €
€€?#€sr€k€v€Wh€a€aLQ|>€€€"€*€€€֔€€r€1 +R€J€€K_YKQM€XE€€€H,_€€Ö_€n("€€B€ €z€϶kÝϘ€ €?€€€ €€€€`€9€€f3€HC4€E€€€€J€{V €€:}€N€€€€"&c€\€8&€€€-€€#,=€?.€G1€Bv€[&Ñ¢n€[€€€€[M€€%f€€€€hIl1€€€€€€eP |€€€€ϡK€€€€€€€€n€€€€(€]€€ʒ€€€3x7:€[€\€dg€6{€€[€6€€€€N€€€€€€€€€1R€€€!€€€-U€€€€€€5€€m€D€€A€€€ |€€#zj€ €€€|5€P€T€€SxmdGwq€€€f€K€\€(>€€€.c€€X€€rH€€:€J€€€=X€9€€€ +€€]R€€€€L€w0€€€nq€€(€[)2$€G€D€n€ˆE€K€2I€€€€v€€xt€H€1í¬†6$€V{g$€€xe€wF€[€€€€€€€E€€ًlsdE€€J€1€j9 +€€€/€€€s€}d€w€€e&€€€€ȥ]ׇq€€€mkσB€h€€€€A€J€f.S€Ix€€_d€€€V€€€8€3#€€\€€€€h€e€€Ø€€€€x|€€€€>Rh€HZIQL`€€€€m€€€l€€€X'€[d2€r)€€D€K€h-€U϶}tĿ€Բ€! V€M€€€€{p^Q<8V€vb€]€€€4€€_8€Qa@€€Y€€,€9"€€€R|{€l€KC€€!€I)€t'c_:€Bz€PI0o2€€€I€ƅ€&7rs€€h€!€u€€bWH!€`d€€kbHd€Q՗€€P€€€e,(W\0€P€€€L€0€]N€V€\€h€t
GS€}d€€|€/€^€
h€t€)`b€€€€w€€€€`]€€`hy€р€/ͻ,€€€~;€€€€€€-:,+€€X€2E€B€Og€€/R0NBȲ€€€€€€J?€€L&€nl€€€€i€rw€͘€O€L+€€
€V€€€쉖j[0€M€İ€Ǿ€c€
IR€€*g€Q€36b€€|€:k"2Ӛ€€€€€.Kl؆k€€\K%:U<€\€F€[€€+€€,€€€$GbjU[€V61€€bd€€"€uhUk€n€m}eؙ€€€
€\€;€€<f€€ €w€€Þ€€€N€€lą€#€Tl` R,D€€OH€=€€™€g€)@*€&C€€€€€7ж€€B%{yڳ€€€€€$8 Ǿs€N_€^,@€€+hd€€; +€€€€€K€x%€€M€€S€€€U€ڷ€r€€c +~2&€o€€€yŇ@/<;€€V€€W€€€€€€€€c€€q€€€آ8Jr€€%€€€h%€€€9tۧ€Y€c€€֓€€"kVÛ³(€2g€>€k€'a€,€€€€€€,€ZRO€€€b?K€€r€€{€€€UF€€|Y €Dk~k€d_h €h€€U{€*׀€€/€bGPn€€)17€!$"€R€€aw=€€Bt€&€R;r€€€€w€~€0y€e€€€€ױ( s3€wvj€"&€5וev€J$€"€€I€€|€€€)€-€€Al.€d€€€{€jZ€3€k€€€€3#T€'€€€BY)k€/€€칈+gQ.€D€L̶€&€€€î€Oz€`€€(QL€3€c€2u€ +X€9€€€ v_54<€€r=€^Y5€`D€d€L€€=€@ԡ€<{uG€ϰ;FP€0( +*T€P€}jv€6]€'*qzY;€€€i€€ަ€€€J€€A€€APb€/€+[€oÃ…BT€G€jpLH€c€`o%A€€€€€0x€չ€€"€o +€,€ز +€€ZBW€hvU€7€)€7R€d€h€a€€!€eÜ€€€€Ւ€T€€T€€-.€€`€€H0*Q€€€€YJ€€€€€}>€dP€€€d€€f:€€xا€€H€4޴€= +€Yߚ€%€€€ì¸ÇµÂ€Â€b=€€€,€€;€€€€€€€g54€€ऱ=€d€^€€€DN_€€€€n€}€€a€€€€#€@NaJ€€ILd€&O>Fq€€€€Xo€€€€€lzmy€DÈ¢T€€€€€€l€細€w€€oÉ€€€z€€€^9€A€}B€+Ö‡z€€>€€€€ +]cE)!€Ɍn}[€€η3€"€€€*€€(M4u€&€M€5YtMd€€€€€!€€€€%€))qLua€€€€W@Q{€&B€€€€€?€€€<ze€€q3€5€!€€8€€€€€=J€€T€€€8?€€€€€J8€M€!b,€€KT€€€€I81€8€bi€[€€€Ѷ€€Q]
€€`€h€€€€t€n€eܙ]€ >=+€€€C€)xq€€
o€€79€S€€G€€€€%D€L€/€B(€€/-€€€€d€.€_+€€€QeWU9eV€tU€€€€LRT=OR$"€~€-Q€(€_ɎL€€0€€€€C€€^0€AO€3€€+€ۃ€€$€€€€/!V€€€5N€.€€?IG€'8€нx€5€€€€€€€€'X/€€k€Lo€B€Z2I€€=€€€€€;ö€€€€€€?2厾€€€@€i€M6€#&D2€?€€€€€<€ +€€€?F€{?€~€€:€X0€
1€€€w&€€€€€P€€ً€€€x€' +:€Ÿ€dp€€o€€ €Ŷ€L€€€€€€€A€rc€'y€32R€€€n€^€o€€€€€€€€6ב:€€e€€<c(T€€€&€€+€w<€8/y€͔€Y€|€€€$€d€4%5€ M€>€€x%€€ +x€€€€€€U€#€€€€€€€€€€j€G€۞H€€1€€€GB€€q€€V€6€€€€C€€?%i€€€6€€€€€2€€l€€Ab6€)p€[€€r€H€€€T€;N€ C|€€Ds+LA€].Y€#,I`2=”€ns̖€1wk
€€€€1€€€€w€͉.kK€ک*€€€R€€!X€€H€A€€€€u€#€gjF€R€€€€€R€2c€i€€o&€€a€Q€€€€€€4Ϣ€Y€€€@I̥€
s€€€9?€€R€T€,!.€bp€€€€€3€)€Ϙ€€/€W€€5€F€nt€€a€/€€D€I#€Jl)'€€€€€d€h|Âœ0€Dw/€v€€€vY€12xw€`@*€‡y€EE€{€€:}€€!t€€€€@ǥ€€€#L€aF€€h€€ۼ)0DDIZ €€€€€4€(=€.>€€<€€/€€v€€]€€€€@€€€€€€YwB€€€Ia€D€€€ƀY€€€&Ȩ{y€€f'l€€ +e*€0B~€Q€c€A€€€€7€€Í€σ€€€€6€~€ 1€€0€q€€q€€G[€7€sL=€€Np<`€H +^€€,e€€€K€@€B)0€z€n€€ €%€€€|€y5€O€dp€0|€i€€€`€€€€#€ґû€-€Vb
y€vlb€6€M€vu쳊€X&
kۀ€€hL€E4&€X€€€!€€A€(h€€€€€g€m€5 +€€i€c€€/€*~€Y€Ǥ€€d1V€€ +9€YL^€l)N€s€€€m€O`€U#rz€€k€9€€ã”€ހ|2rq€^€p€€€p€I€€IW~c€1€€€h*€hЋ€€€€t€&€^zhp€g€ѦnBr€€€WoئT€€U1€|>6В€€€€€n~€€ €2f +€0^+€€x€CEC€€&}€€€€]€€€X€€€€€5€€€G€x*€6€€Jy)€€D€FT)€{:w€€zMK€+JJFf€€€€4€€€€u€€€(€CG€€€€ +€€€€R€i€€ݱ4K€€mC€]€€@€€XV€=€€{w€€€€9€€<B€€€€޻€x€€€ko€€Y€V€€}+b|g}€€qkO[`€€f€€€)€€€{€€֙hC€€€aօ€6h€€H1@r€Y0W€G€/€.j}R€€
€€€€%€€€5"€€€€^d€^€St€€q68€€-k;€)€€{€z€€z€€€€1€gg€V€€€gz€€€1G€€€"€"%}€€€NAq0€€€cz}€*&€U\/€X<€s}€€mY€tZN€1€_:€€€\ +€J€€€€Z*=}tZ{€>J€€*€"€c€€€€Vao€€/€6d€'C€€€2D€€€€L€ €j€s€€gJ€3vL€,9c€€C€<€€\.€€€€\€΋€€y:}2€R.€q +@S€f€€C€>€€€`6€€€R|,s`€X€of€€=€€pڢ€€€ƕ€u:€€~€€€d€€€k=;€<€€:€]€+OÇ°&€€U€q5 a€€gC€€_€€€€€€€yds#€€e€€1€€€€xR€€€€5€9€s€}R€€€€€€hI^€7€M1€€€€H€€€€hyy|ܱ€_€€`zaÂ€ÈŒí§ˆÂ€Â€uu€€€€D€€n(€€l*È–_t€€€€€ol€S@€€?*€;b2€€Y€€ÄF€tÅž{V€(€A^€{$D€€€L€€{€€1'€
tj€€€)€2I*€Q€T]|~€€€qm€€€€(`<<€z€€€€V€€G€L€0€€A€2€}€ᔨR€€€(2€`K€€F€€ޘv€̸€€nj€e]€e!€x€1€Q=f9:䀀崴~€傳AV€€€€.€€€x€€zi€g€€€€}"$'€+䟒J{€€*H€L€ 5'€A4€)€€€€Y€k€^.€S€€s€€ß)ʰ€
€2AFD€€€€€N +T
€{{€€€S€€€rS€&V€G=€€'+%€€x€€€!€K
€f€€? €€€}€€€€€Њ€€Xi€?Îh#€Ƒ€ˎ€?€x€€€€€€€E棎Ӏ€4€€>xX€t%€E€€€€€€€€€$L€€€€q€€yÉ•}€€Y/€€g€ඎ€€€TK€€€R&€€€€5€$€eZ€K€]€n<€€4)€€y€:€€3€]€q>n€d~€€؈mwCL€€^€fN€ezC€P €%€€G~f€Bz€X(€2€,€=P|Â€Ì Â€SSx€_v€5€€€K;€€€m€€t€v€,€€iÚ‹w€€€E€A€!€€j1€€€~z€€€€O-€€€€|€!M€~|`€€€€€€€ۂ€€€mA€פ€<€€ H€€€€_n€x€€MA߯€|m׌€4CU€€€sQ€<y.s]€€8yC€€$ժ€€Zy€€D€~)€R€@€€{C€€6Q€€€€€€S€€'€j$€€€}€͆€€€€q%B€€vq"€ug€€€(€2€y=~Շ€ȒS€€€€€€€€€.J€€CG€€I€P< 0€€€€€"h€8€ +R€€g<J)€B-€Ո€€:B€7Ύ€€ݾ€N€>€Ex€_€€€€€€€€O€€€u€€K€€o=€@&;Da€A€€+€€ku€€€8`€^y€+?€€R€d€€€€`7h€$€֣1Ë¦Ö Â€CM€€€€€d€O€&€T2]€Y'4R9€F€€w$€h€A`€!€X?€B.\€~€Ew€€`Zy€!Vd€€2€XmSКd€€€€~€€€€€O€€un€€€঄įGhڂ€B€€€€?^€Is€)€€'€€d€€€6€€:€J +X +L€]€NW€|nU€€€1ti;€€v$€a€€€€€€€j€€H_U%€~Ua€€>V(J€€€€L€€€€WM^€€€€TQ€€@K?ߩ€:K€'J€€€€o€z>€!}€k€]}€€a€€.€pd€<uZCr€€€I€|€x€{Į€V€_b€€€€?C€€34€€u€f1€€e€a"E€€A€€€€$€€€[KY€€€Y€€€!A€€€€€€€=€u€€€`€€s€\yzphN€0Z€~€€%Þ†i€ABV€n€$€€&€€€€z€€€۲€i€wl,"€Y€B~€' €p€'€€€€€q€€ØdZ€€€aÄŽK€€€G€€€€d€'€€€€:Ah€(YY€€€$B€S€Z€ +€€€a,A;e€ +qVRY<€T€me|€€€€€@v[€8€€'€€-€€x€€'€€€€%QF€€€"7€€€€=€i€€/€€R€€yb€%€€€w€€€3Z4ؖ€
f€db€ €€Y€$r€ +€€€€€€€D€€€ۋ€€€€|€S€>€€€€€€€6!
€€€5
€_` €€_€V€€q6€€̒SîŽÂ€K€€€U€/A(>€€€€r€fќ€ +€€€ZeG€€h€€€̰€c8ٴ€€€!€ރ,€R2€€L€€&€3F€q~[]|.€€€k}€€c€vģ€POͨ€€€
€斸€]€WN.2P}€%€g€€#'€€€€€\i€ªمK€€€€€€€€€€FU€€N[{€€ €,T€€€
€€-Y€€€€€f€(€SG_€€!(Q€€€€åŒ}K_€`€€KZ€3?9]E€b€T€,€L[€]€8 €€#€P€€YC2€€€G€Awj€cD€€9€jt€t€s€8€1zh€€˫€€=p€{T-jOG.V€k€€1s<L8h€€€އ^d€€€'€*€ t€€m€Շd€F€€”€G4;€ +I2€L
€€8"`€"€eA€J˱€QÖžC€q€€mX€(€/€€€Ð€€€u=€60€€€€€=€eA€€D€€u)P>€€6€,.€/€€m€€G.€€i€€€̚mÃ’h#€€€.i€?/w€8ބ€Mf€F]Nu€lG€€b€€K€€ϡ€€,-\`%€€c€I€ea€zP€DwlD΀a;:€;86€=€€O€P€€3€NB€€c€$€D\€$W€Ϸi€€€v€NZ%}V.K€V:€€X€"€^I€ €€€]€^€Q|~€_MX9G€€M€R€#r€Ã(€€€W€€€€€Y€€€€]€€K€€[€wa€€5nrG_€€€O€ ʯ€€
spider.chk.oldsc€LV€€€€€TEXTMPS €€€€E€€€€€€€€€€€€vbU€D€*I€€6€t€€€€€2€€F:€z3€€0€€4x €€3€€€}€€€€2€r€€€>J€€"J€€Nq€W€L#€€1€€,€h4=€Bd€€LaX€Q̊R€[q€Aa€€2qeY€1eN€`€€€€€PA}]BgRir€€€€€€€fz%€~€H +€€M€6€~"eZ€d€d€lsz€M!'€@u€€<[€€€?€€€ΎWg€€ }GPz~ +:€[€€€rJt€h€\M€ c€(5+€€j€ 48c€ +N€€2€ €€€€€€€€€€€€k%a€€g€hQr€€q€€('`=€€8B€gG>€€€€€€@5€€8A'€€€{€oGF€€€fŎ|M€€cr€.€€Cm€€6$
]4M€t)€€€)1#\€WZ:€€l€B€€€€€?€€Mث€€B€€€€€?€€€€€I€{a[€$€€€%[6€d€€I€€€€i€"€`€+@€€€\ML€^):€ʲ€€hړ€HY€€wv€€>€OE€CvVw€d+6`€5(€€D€΃ +€€€q2€€~€$T€Ai`€€LK]€€€€€ +€€L&€,I€€g︟̢€D€$C˾€€€€€€€/V€ϼ€,€3=ʦ€€r}C٧€€€]U5€T€ƫ€w€nET€5;€"Z€€€t*€€"8€ €€5{€T€€.€€Ҧ€€€4u€j€€€€€€€]2€%G€€0€€€xo€€<€€€€€€"€;€€?D€€)€2""€€Z€€€N)€€€€€€€_€€€.T€'€o€0€€€e€6€֡I€6zӦ€€Wi€€<|[i€€F€€ 2|€€€RÚ Â€w€^EM/€W€oN€€ik€€€€€€4€€)€>€€€ӮZ€_U€€€€€9€W€€€€€˾€€A€€€€!€€}€
M€€Zb@€V€)€€€€v€y€Դ€€€€]€€!}€€4€s€€^ХYz€Rk€D/€€Y€G€N€€e,".€hP€€€:€€€€€€/ٲC=S0€€€€€€€€€a{j€09L€€>€€ǎ€€€€a07€vR:I€€`€]€€I€
+spider.web.oldsc€2€€€€€€TEXTMPS €m5'€m5(€U€€d€@UT|€€vb€€€€€%€€€€h€€4€€€#U€€h$L€o0€€Ӓz€€€ ֹ€€€€/€^%@€^t:€€€!(€R€2N1€x€/}€:x?h€€\B€€€€`€
€g#@;€€9#)`€r€€€a€9€T€€€ +NC€€Y?|€€=€i6€€€€o€K_@€€f<€€t€€€€€
€B€屫 9b€€73€€€т€voiNy<A€w€~€€€*3M€z€]t€n€€<€0<€€€€€n€O[€€€€A?Z€€€k€̺€]€€,€€€"€€€2X€€€)#€d€€v€€€p€Jrܓ€€€€€€€&€'€€t€+s€ÉN €€€€W€€€€€}€]^€,€€€ʗ,€^€QBU'N€€3€c0LE€€W€Ew,U<rCq€€9€€׽q€€#€H7€€b7I€绩L€5q€DW€,€=€W€€€"Y€D&B€€u€€ǻ*€€Qg€M}€E"€€€€€^€€€€€€7'x€O€RDn,€T€€Xz€€ǖ€€d€€9y€m]€€f€€€$)€^íº©7€€l6€3k€uwd€€:<€A€+€Ù}€R€€d⤩€
ݸ€~€€€€€€;);ͩ€T€€Õ€€€€€€€]€4€)€€LG~€€€€€€€G€€€~€€€”€€d€€Y8€€€€%€.€€€D[ۡd=)€€€~(€0Z€(€M€+€*€:€*€€€€€€€j€7€€1I€€€€4€ɦ>€~+k€sqM#€€
€a€^€J€ Vfp)/iV€]u€m€q€A`€€&€@€€€3'€gW€€9T€
€t€€lk€3€€€€€Z€€€€€WN€€€€
€€@€M€{=L€3^€e€d€'€p€^€€[*s7vG€'€)Ü¡AO€€d=€#*€W}<€Z€8=€1€}€€€€O€~€)€_€€ޓ€{t€p€€€€€g€{M€@€€€€€u€€|€lj€s€€펟€\e'€6€ԅ€€€|ߪ€j €€P\€€P\€€€€D€]€tÍ´vk<Ä€~1€€€X€€8€y<€q€c€€€€€€p€80voi€2€kS€€G>.M€€DÆ•D€€€€€€€€€€{ꊖ€_€&--€€t€*c[€€€ca€d€€rģ€€_y€€€€F€_,Æ€?PY,€€€=€bq€ڮ;&€1€0€€{9€€€€€€€|\€
€€€€€` +€[
€p€€׸+۴hbVR€€U€€€€€€Y€€€€€€€€€€€P€VS€€룓€€C€€5€€€p6z€N€€€ Ďc€lţ€A€€D€0€€€€#€€€̇;m@€nA€7T€r€}r€3ؤ€n€€€€X€€h€G(|€€€€€€>€€€€€€€[1H€lK\I€€€€€)€€!€€€€ς€€],\€€K6€€€s€€€€€4€€€0€b€؂€€€[}0€Z€€€€V€M7€€z€€€€9B€€€€d€€€€€YӢ€€€|€€d€
?YR+€€.€e€%€#=€€b;€<€u€q€€€I€€€€€k€€€€€€€~€€€0€€€^í¹‰>g*€Sw€€K€0)€V죢p€F€€K€€€€€€€˃C1€J€€€6€sw€€€€€€€€JËšY€€(€€ €
]W#}€€`wp€€€€€€€€7€€€_€€€€"€€.€€q€ +€X€e€€€€8€t-€€€t€X€€€€€€€€@€€€€€€€6€€€Hߦ2€D,D4€ŎԀ€€ԅ€€MlÖƒt€€€€€€€P`€€M€€€€*;PP€W€焯u€€3€€l€€€l€E5ߵ€ݎh€0€K€€€€€̰€v€€€<€<!€. ω€l€€Ý}tA€€n€€Y€Z€
€1€0€Wç—€+/€N·g€D€>€kO^€%Cq€%€€€€€€€€3€€€€€h€ €Acƀη€€€ڂx€€w:z€:1€€€€$€€PC€&€7€€q€ C; `€j€c7€r€@Â€Â€Ë Â€Â€;y€€{8S€gTF]xk+€*UYTWt3Im€€a€€€E8b_€C`€€BK¢€M€€m€6€€% €€3€0Ñ¡m€ ,z€o€€€€4€€€loe€€€'l€€€^€ۈI€o€25€@C€:€VB.€€€j€vÞ‘?€€H€€€07€.€€Z€G€€õ€€9|€뒹€€ј^€€qv€MC€.€~]€7<+€€pN€l€Oq
/€€€€€€=Ѓ€&6€K%a€5`€l-€€€}B€€.€€€€3€€U€€€€T€€(€€€K;4Z€5ps=3€+€t€;€)^{€&֤€c3€€€]€€4€)€Aͣ€€jR€€.a.€d€€{€-q`y'+r€6€f€€€v;†_€€€}€€€|€€€ӟuV€k€€m€€€L€€€€˲€€€2€€€)#€},€€<€hv€€€€€j>x€w€€9€g€A€K֕՚€€6H-€u<#€€J€x€C}0<€1€َ5€o€€€H €€d9€€€€[€€€€€e€€ܓÄ€hE€€7€t€€€€€€€t€7=€€(u€/€€Ӗ€{€?€'€r€€a€€€€€:€€v€€z€(G€€€9€€€b€bW€€€€[&04F€Cw$€ы׮W/€€/|€€9€h€iz€€3€€u€€€€d€PWC€0lf!€]l€U€€sݼ€6€q€€CN€oȂ€€€€)€Op€4ݫ€€€=,€U€€€BG€,=€<€€€;€V€€}€Õ87€y€7>€€?€€s€€€€>€ȹ€€€€ߦ€€9g€€W€=€|€J€t€RO€@€€>€R!€€w€€€}€€R'€bnؘ€€F€€€Hz~€€4€€€I€€2€€€€!
€€€€€€€LXw€€\€d€1€n; +vu€m€€€€ g€€u€€O€f€€€&VoCv€€€˓€€w€€€€€€€5€€hy€VÆŽa7€€`Y€€@$2€€E{<€€€C:€i€€V€l=?i€x€€€€m€U€€€;>×8€.\€V€€€€€€€€€.
€€
|€€€;€q€€€€€€€€{ת€€€€ԑ<J€€€€gr€€fs€>jr€€fb-~un€=`€!߃€€€€*v€mj€€€€€Ikf€n€ $€€€x҅PG€Sf'€y€€9€j׀vW€k€€1€€c€"€2€€€)€€,€€€DnG€€h\€€z€v9€€9€€€Hg€€"lMM€\€=V€€€€€€
€€C €$€€v€€M€I{j€|4€7€Jc€€4Ln€i€F€€ €€€€€€mH€Ӿ€€€dR+Z€€ę€€€~L€€€€€BΡWeLH€€f0q€€*'€€€€€€2aH€€i€€€€€4€€€€u€p,&€ '€€8J€€€q€:€€€v#€€€;€-P€7q€A€€1٫€€€€LV€y€Q€̃€m&"€Z'm€€%€Q~€€B€\2€€r5ЈCjё€€€€€€€f€€€+€Ges€z/Ñ«$DQ€€c€Eh€€€V€€€q€=€€€ŕXe/€€r€€€€€nr€ǂ€s-€0€€€€€)€€€i€Ð4P:€€€*€€€€€€`0d@p€€QÝ…l€€€€~Ga€8€B"€€}€€€'€t€€€(€:`f€€€€h€6ި€RFz,€Ȁ€€E€'€ +€€€€i€R€%€^W€I€€€j€VKt~9€1€€^€^C~€€w€€€u€Jn€*HK€€&€p€€0€HD€Q€EVJ€€€€@€€R+b(c€J€€KR+i(€mi€[€F€€}Èy€M€€€€c€€~€7€8€r€8dqJ
€€€€€I€€€ueܙ€€4€D€€t€€:P۱€€€€F€€"-€€€>N1V€€S€'$h€c€q€g €Pa€€\c#€€€k€nW€:;2€9-€€€B Q€€˕€€A€((v€P€€ʊhA€x€€
I> +€'A]€‰FX€€€.€€€i€2€€€^€€€9-€€€J€¨€O€€h€€FC?Υ5v6%€€€A
€6
€€€ +H€jU€ɛ€߷€\d€(=€€€€€€ݤe€8€€€]€€ף€€T
z€€€疸*IhÛ/€l€€E)€r€^€€€€P3€€€€€€33"€
€ +€=C<€rԧJ€€*€>^€,€€͛N0˦€Ry\€€?8€€r€f€.€f €€€€€€1€OG€Xh€x%€€L€-U€d<€`€6GL€€€4€e€&€0€kk,0xM€Z€€ fT1€€t +l)ɉ€€€X€QhT€l&€L
€€5€:€6@O^i€€€€€€G€}€€J؀€€CQ€uL€€€€H€€@D€l=€:€€€€rWL€€}"€
€d "€€€q€€€€LP€\€ku€+€V[I5€€€M€\Q€€qJR:鱜xN€Ê€N€€U€€
Hg€6€€€€X€%€
h€wؾ€c€€a4N€€H€JmÕ¡*h`uИ€=`€€~Ä€€l_b€0€HH€€€€€€$€€€d€0O€_€:VYÂ€Â€Â€Ô +€€@FB€€€€€€O€ +€€€r€€X€x€~.€
+€€9HB@bZ`7€$€l€€3€€€€€€€"€é™Â€hT<R €€6€€€C€3€<€"€€€€€€Y€Z€//€O€€€€€€€€€€3€€C€:€€€u€`€€€&€€]€'@6€
O€€€€-€€€(€VdY|t@€€€s€€ +€l\z€4€€ʇ€zˮ€€€€€k@€€I9€€€J€€F€€*€€?€F9€rm€€€L€€{kǴ€;€;€о€1~{k€€W€N€ucp€€€€Yq,D€€l`€€ "=€€€W€€n€€[[€ԩ€€€Nx=f€€O€€€ٲ€x€j€€€€]€[7=€Y€8€NK€X9Ğ€€$ދڤ€?K€+d"€€€€@€e)€€$€%&q€€4€Xg€K;€€;`!IB€€ €Qf7!€g€+€€€ €+t€€€€&€Op€€j€w€U7€ϞA€€€u(€^}G€X€y€€€€€Ӈd~€€Q€€F*e€€€:€@€%U€|V€Ó€4€€X€€€€_€€€]S€€€€?€Ara€€%€T€€€€€€f€€jQ€€€:*€ۯ€z€G€€€
<€J€€Pr%g#׿K€$€Ay"€€€,€€d€Dv€vß Â€Â€f*€€,€M€€€€€?€€€k€€h€€€y€Z€€շ€€€€€Ǣ#€€€G€t€q€€:Y€:€€Fm€€S€G€€€€€€€y€€€€&€:鼸€+M€GQ€€(€€€€€";͈)€€€$€z le€f€€;€€(i€bX€€&fk@A€€ZB"€7€€€@€ +˘h€P*@€€i"€2€@€H€€€#€€Z€€€ǡ€c8+LsD€p.B€€€€€@€€€a,D€€>cE6pK€A€v€€€€€€kO@ +€€€€€|9€€$2€a€P€4;{€l€p1€€€€,&l?€€€:€€ǗMPs€#€€]L€€€€4€€€2~€;€€G€€p€€%€€ZΡ€dH5x€%l€€€€N€€€€€€€^߱€Xpqp'%n?€.&€€Y€€|}t€€Y#€€;€€X€€p€€€:€€€€€€J-€16i€n€5€€*,€!€€€N€ €€€€€€s€@mR€~$€€€€o€[ϴ€3Ï€Ǵ@€7Gjn€~€a€_€Ŧ€€€E€€€€
-€P€Dg€ +€€Z€3~€€P€€J€y€€'€6€€ 2€bf€Fxn1€€€€€ €z€h€€€6€€€ӹ=€T€3€€B€€€€R€q:€:K€0€€lj€h_関^w4€sV€€€Ҫ€€€€€€Lހ€€l€€g݇€Ht€1]€€6€l€€€QY/€Yɬ€\8
€}€€C€5[RV€[€0€?€€€Gq€€ƺ̼cx€$€WY$ €€&Q€€€€1KS€€/€€F€p€€sr€€İ.VǞ€€€-8€pNWUu€O€^€E€((€sL|D.€V€€€â‰3i€€€iÇل€d€#€<8€€€€€€e€"€€€m€8€6€Io€€€€€€€p€m
€€/E€>aW0&€L;€€€€\€fKhm€P€€€€€€rf{ €LI€€EP€€€Þ€:g@€;P;nAb'€V €€Q€€€€€4-ÄŸ^2€€)I×°e€€€€€€(€i€Ã0€i8p({€h€€€F€€q€€€f€e€g€€€SÜŽR52B€g€€€m=€€|€K€€2€€€€€€€.=;W€s€vÝ€Fړ€€Ȼ€€€y7Oa<€€€[{QR3€€d€€ׄ
€K5,ڸ€ϟL€Aw{€2€`€€€€V
[€€;€€€€r€%€Ϙ8€€mRB€€€|W.€€=€€€:)€4$(€; €k.I'XC.€8€+€€)€e€€ € ee€€B€Dx€€x€€€M€€€r^^€
€€nZj€"#ȋ€€ +I€€€f€€L'€€€€!QÜhc€a&ks€€Pjq€B€/&/BM€€H€€€i€40€h5jN€€€VC€€b=Ò’A:Û©!€€€€$\6€€$€}Ҽ€€@€~€&Ƹ€€€l\€€€€ǹ4Z€\-n1ޕ€€€l€€K€€K:€]82Jb€€€V€g€d€漱d€kLz€€13€%€€dґ€F#ej€€€€qA€€e)]*;€€€d€WN€€€€b7€€€OrX)€p€€aCG€€
€Ζ1H€nC €€€:€€+e€€H&€c€€m€€€€€\€€F€.€€€(€y€q0€€b€€-f€€7€>€O{€€€€€l€€͒+€€€3&€€Kkt€.O€4Bq€]€€€€€ €$€€€P €€€0€€€$€€j)€€SOKW€esӽ@J(€%€€w€'h`€€€N€K€}€€1p€€€€€€ӎ)wE€>0=€lK€6€€€€€
6€€}k€€qc €€€A}4€x~1€T`€$€V=€D€€€€H€€D€7€֢֋€(5€
,€|€/€€€€€€€ &€€€<€s£$9€9€=E€Ŷ€€<ۉ`€€1%€€D€ VK%€'€€=/€€€@€%%€€€€€€€€-€\€€6€€€€N€€€€€ɪ€`j€€+€€̞Ȝ6€€h€€[B€J+E€€ϳM€€€€ v€€€€pcY€€X€D1,€+P€T-{e€€R€6€€L=€|€€€€(€€E€€?D{ +€€€€F&p€€€f€t€€€Kw€€Z€€p€՘€€^>€ç»Â€UNo€ã±Â€P€€I€€Z€tzâ›H€VS=€ʥ€=m€/i%€€Q€b€i€€|$€j€€€'g€"8P)€€*€€€€€L€€€ƌ€€Nx€€i€€€{€€€iÉ€"€Cx€N€G$€[ €€%Ï‘b€J€ؾ€.
€€c€€bH&tr&€=€J€kpz€0€€€@[H€€%Q"€€€;€v€e€€ #€]x€€12(WX5€€8€
W€€#€€€$€eC€€€€€€€€€€€€€€€J$7ۄ€c€)t5kt€ e2bd€1)€V€0€ +€€.€:̆-M.€€<€€€M€]€€€پr€€€€€€ä‘€€2€€€\€=B€€ˀ€x€€y€8€€€€
€€€€%€ziF€€€y; +€![€EZ>€€€€8ldO +=€\€lm€€€P€lp€1K€€>€€E.€€€[€W€€pG€+iC€!€,V€
y€Ӹ€g;€€€ן€€€€fA€€€01Ւ€]€d€€€9>Ñ€€Ø
4s€€€.X€5YU€€€€c4CaV€€€x€€€i€€€N€€<M€UÌ治ɎY`€X€4*€/ty€€p€L€ €8€-BHC€k$Uv€€p€0Q€€€€ЌI€€}d{Q€€€p€€€€€bv3€z€€€O€>n€€€4[€h}€€€€
á¯Â€Â€P€e"&]€€ "g€"f€\LE€.€h€€M€9€*h€v€4€U€K€€g€7€{5€;O€€€€ԅ€€ᕦ€z€?F€€E€€€€V€€€qi)4 €e€€€r€"ԛ€~€€G€͵€e€ÂÈ“%€t€€ €2ߦqP€ᨰ€6M€€Eag€{u€:€_yD€€€€€۰€€€ /€€*ì“€€{T!€€’€€€€€Er1€2\R€€SVNT€€)€b€c€€!€€_{ؼb€r҄€€€€€Df=u€ȑ€€h€€€€€€1€€Z +€€B€€€€9€€cc€€+€€€5y€€€$4€qHQ;ط€€€€€€€KQ€J€€ €€`€N€€€€%{U€€€€iq€€€€]€
€AM€k€ze}€]+€€ҩ)€€"€ZӒ€€€NI€€k€A€€v€€€€c72€€&€ěpάL,QƯ€Ȝ€ti€&?a€HLU€€€€€Tg€€O€עY8€€LrܱQ€a€k|€€GԬ€vģ<€~,€€€€€P€
A&€v€3€€;O-€ʓ€)€€6)ETS€P€M[<^u86]€€)€$€€€.Ï€€ +€T€|€+h€€€€€€kX€€c\<€ͧY€€€K€€muz€€€€€€O€€€K€€€€€5€/A€€€50€ 9€€MG]z2K€€€7€d;0#€T€€`€€€€€€^#'*€1y€~€€€S€O1€5fE€]€Æń€€k€!@€#€-s%-}€B€€€<€j)€bS%€€€(n€ 2€€€€€5DԳ€€€€€JC€+€€€€€€"€€€€€ϡ€€؄+€€1X.€€€€ €a€_PD€€#y*b€€ 4*r€€€€+j
@€n€€€#"J€>+BTÚžD€€ѧ€€€€:<dz€'l|(€|€€õk€€€€:€ +G€€€D]€€/€€€ (€€€ €*)€B€̌i€m€Դ$€1€€€ږ€`€<M€#=d€€€y€€€N€€ +€>_A€€€ €€<€€Q€ €€€€P€D,€_@€€€€€€*ZB7R€€€€g€€ӻ>yEKê§Â€Â€ .€I€Y€<%{a=€5€'yp€€m€Y€€G€€€c€3€€ɸ\=€=€€'O€€UK5D^cv€€B|€He€€H<€&Z€;€z€€€2G€€7€p5€€€ҽG"€D@€ €€€€iDa€D€C^€€€€غ€€A)Sv€u€4%X€€€€€G~€ +ß‚cй"€\P€c€€[€€B=€€B€€€€€€ €€X€'ZB€
€}SM€̀€€€€Y݆€€ܨ*€QG€€€Hw €€b€€_i€€€N€€€,W€€
€B€?€€K=€€;h囙Ta€_€fs/€Ү€€MP€n€nK€o€€-€€€tT€€v:N€[€E{=€]a€€~€:€Ttu€€P€"J€€€€€J€u€€ކ5a;€€U€€?€;€]€6€V€{€V>€W€€€€J@€€0€;f€]€"
/O€€€€€€
\))€~€€Z +x€€€W€€~€a€€€€€€yҺ€|€ӛBs䵣˄k€€eGCLJ€€€€<€z1€~J€€€€€€d]€E€€€X)g€Æ€g€€#€l n$Ev€€€z3€܌€J4€€\€€€€T €€_€E€€€€І€€<u€€z€F€€~EC€]]1€€€t6[-]€€,€D€cᲄ€€ €Ů;€€Q €€€€пb€€`€`i€€v<€€[ (€€ťݫ€$€€€€S€ f€€[} €% +@€.€{gF€.6JI€Qw€&€€7€vx€D€=ZY€€€€€!€@€€i€3'€€6€!y,$P€>_€%€2€€Ǒ€p€€?€€€7€€€"B\q€,€€€€3w€€E ?€€4€>€I(€v€D%€€€€€.€MKʢ€m€х€€B€€C€A€€!€7€SL€9€`€\€(A€*€€€€€€€N€bY€€T6€€y8€3€€€*
H€€$€€f€€€x1YU?€B€F€_|€;z€a€€|€z
m€€=€€€u€Ѵ€,€€€$€€€€€.€€€€€S€€Ķ€€Jٶ€M.€€FJh€CI€m€€€"€l€W0€G€a|€€Y(J€ВƤ€€€h€2€€`'€€t€z€€€€€C€€€€€,€f€o€F€7€og€b +tۅ€€€;€*€€d€Fo€€ h€€s.€3棒exzb€W€€d€€€<€€€€€€g€nBI#€,S€€€€-T€€€3€€€\;VF +F€€€M€vK€€j€€\€)?9Y€x€ֆc23€ݟ9€o(N71€X€€!7€q€€S".€€ؕ€O+ų< 8€€Ja€€€-€SRZӳ€€€3|4€€€9>€€€€
€C€ym€€€€€ф€€Q)U9|€€€€ZRa€€€€€PPż€OB€€c€~UU€€M1€$€€€d€€]8s€€b€f9€€€e]€€˨-I@ €&€€V€€P€I9€€€€€0€€€x€€\D€€W!毉(€€€OP€€€q€€(€j)\`E€€€p<a€@€SGm,w*9€€€R9*<wJ
.€€€8€]€€[€€*0€:€€€€G
€#€€/a€ܑ€ʮ€€€k€ +€€
€0>€+€€€€€€€[€€€ڇ€€hݹ€€€/€K:€CoC€€@y€v}€W€tZF€€/&€ں€+€€€€[.€€5P€€€DÆ€P€€
€ €NiO€gè±a€€T]vJͦ€€€€=€€i€€€V€֩@€T.P€t€,r€ָ€€ti€€€€KqQE€€a€€X€€\€€}€€€k€ᶳ€]:€€€€€T€<7hپ€si€ +€€€€td€€gq€€n,/€Ž{K4a€<€€R€€l1C€D€m€Y€€€)€€€€€€H€€^€5€€t€€f€€ɴ€/€€^€d,€€Ҭ€€€€Qx€ͥ€€€0€€ €D€Er€1Hw€€O€€€$€Jg€*e1€€t€D€€[ÂCd!€€&V;€b€V€L&€8l€pRvf€€C€€!€f&Σ€NNb€€€€$'€€€xb8P׬€€€B€5€NGya€€J9€ؿ5R2€#€U€Oɺ€nd%€1{€€a€Μ€8e8€6€]!€€€\€w€E€pʙ€.€€€ÓΪ€€€W€r€€€6iUR€*G5K€€A
€€S€KI€€I€€F€€ €D€€X+h€€aXdQ53€5€i€€€€€€0€€€€€GG7 o€€€€€€€€T6b€€€€€€v€€€⹂ذÖ€ґ€€B€"<H€€}l€Xr€€:7€€€t€€ڎ h€Y€#€t€€[bt€€€q*+€G:_D.€y€€Vd€€€€€€]€€€f€€€€[1Dh*'€€€€%€T€dٺ€€€€ €€€€€a€€€€€F{Rd€ŵ€€€€€T€wn€w*€a€)Fe€7€€€MZ€OW€W€3h
€€u€€0@6\j"€€€€€€*l€€€,€M€€"€€€€`vkp€Ć€>rnB Q€[€€ €€€rjQs] _€€܈P€€€lH€€T#%}€€€€F€€€€uh€€ ;€=€€€ɾ
p&€܋@)6&?€€n&T'_Cs4€€/€|{€€€€G€f€$_N€6u_€Tδ€]€€€* +€슞W€€Z€€T€d€N€€r€€ÂL6€€€€IßAy€€€€€/d^€€{Ov&€g€€€€€m€t{€S€xRʦ€€€€€€tE€{QB2€
€€z]g€€€€SiÂ€ä ±Â€T€+S€?€T +€#4€€€qQ€p€€Zg
€ ]€€€€"tO'€5M€€€€€€[€?.
Y€€€€€E9iNb>€€Sft5€€€i€?=AM4€€€€€x[JC€€g€-€w>o€€€o€€k€
€€€^{€O€€H€€€%z4€€?€€€€€€€P€q€04rsֈ۸€?€€€€3
€€-i\€€"€€)Ú Â€q€áºD{€€€ej€€€9hjr€€€:€\;kt,€€€€X2€ok֯€€€s€€€€%€̗€,q€ɱaݒ€€€k€{M>€€€w€~€€?€€€n€A{€€€iM€2€J€J'€?€ J-.€€vAS€J.W€€€ڸ€Ś€€€"[€€/€€L€€DN€,.l +~R€u€€Z]€€rV€€€€€㚦€€€b€[€€S?10€€ξ8€~€€€€€€€O
€=€€€4€€€CV€€/€}€◧€T€€€m€h~€T€_€ӳ€q,&w€€}DA€=L釒Vh€'{:€€JH€L€][3€S€5€€"j2ԕ€€€ ʵ9€Jgx; dDj€YK€:€#Cb€€[Z€€q%€€€€is€€z<€⳻u€€€€€€}|€N€€€€=2×›7p€J€sY€€l€u€fæ‡Â€Ú¬Â€Â€Û†i|q€J?}ܬi€€Ky€€€32æ±M€~}€jO€€€0€€>'"€€€.!€)1€€€.€1H€0>€]g€K€ G,€b€€€j%o€“=€lia€ J]މ€}€€€€€_€€€>Mi;€€€€GN€礻8€€L€€T€€6Z€€€€e€K€r€Y€€€€€€€€#€€j€ގ)d +~^\f"€*€€`g€€ɟ€\€€€€ €€i<€<€Ye\`€@in€N췕€€p €€mBj€€€=f€€4,IO€q€s€€I€€€€>€€i€m€-€€€€*€€€€8ծ€)9€ZP€N€€!Z€yi€€€€h€€b€W€€€=€€f}€:[€S +3€Ξ€€<€F€ +€h€b;€€€€dPh€|t€AF€4㲸w€*€W€dG€k€€L€k€€3€€€€b2mv€€l€]€m€€€Ә€Ҿ€€[€0!€€Q€AS€c€€€€I€\€xG€€€€€6€€€€€.uc€€€H€€€}ly€e€€€˞K€€€€o€€€b€y€€€€€ w€€3l€͕€H€N!€€BV€€€€€5€=z!J€€ޙ€4<€€€La>7€LF€s€d€G€G€V€€€€.€<€{€b€€€a€
€89$W"€€;€ғڬ€p€Ք€€+t€^E~€'€
€,<ۀ€€5€€a€M€Q€ǹB€€~€€o€1€€\€€7,€€ t€€€€f€)+<"A€h?K€€ +2Ѻ˅1 €63€€.,Xh€QyjU%r€I€€ €6Gn€€€޽!q¢€}€m€si€>€€FK\%€TN€]€J€>#?€cv€€€€€€C€\P€€zOۗ€€/€*]~€Ԍ€f€}€+€€€Z'€9€€V"/€1€€2€€€>€€€l€Y€€ +€€`Rj98€
MS€€ +€p€€?\€(€~*M6"3T1€r€€6]t]:Ճ€€€u€€5H€o|W€€*9z€R€€y€€€€€€€€9€€ +€€5€€6€Y€€չޔ€€?
%€€€€E(€€6Zc€€\2€€€€€€c€€€'8€-€€B€€€yP€€€(€€W:€vz€€H^€/€€€e88!ԟ€€,€€€±€€€€€}N<€€j€\e'€€€€w€€1kfZ€€~€fB륛€Y>Uf€€
n#€3#€€€ʤ€h€?x€€€€^v€€S€j:€ Lx
€€[€y€€€€€€1€€€bm~€E€d$€ +€€€rJ€ K!€€€€€€(€}60€€:d€€€€€€!ڮ€-€€€€€Y$€An€€n\€€1€€:€Z€[€€€r€G€€€D72*€€€€@+r€€O€r9€C€€€ÒQ^€€YQ€€X€€ƸË\K€€nU€%€€J7€57€d6€€Q€m€4R€€€€M$EQA€€€[€0€N€€€€€p
€Aa€4N€€:+5€Å€€ռ€€ɒ€€€d€€)w'L=€€*u€R3F€€z€O€€€un7bnp4%€€1rP€4j€€€€l€€n#€€5€€€Ty/,{€\v.€<€€h€€€ĥ
€€€M6€€Ȩ€€€֨خK€€€€€€%€1%€ؚ€C€+1-€€WqpQ`€l6€B€YC€€0€|CR€0€3€€t0€9pZ€q€D€Â€€Q€€€€€€\ +J€)€Cy\€€ €|€€€[€~|n€€9€#€€€s€L€€`kS3€L€€€<€€?€Ό€P€€€]n€€(:`€€€€LJ~Qщ€冧{v€*€€+֡€€€€€€€X€5€€€ۥ€y€t€€y€€z*€?€$U€€f*Z:U^i€€\ 7€$Ã’d4€€€€€€Ë€€7€`€€€€€€€€€[6;€q$~€Ί€€€g€€$€€/Հ€Ɠwa€€aA€P€€^€€ޥO6€w€€€€€.€e€€€€k€H`l€b +€€"Ra€n€€5€4<€€tM€^3I€€€€0€€HG6o€€€H0Ε5€lM€n_<gR€(€€€=€€a€JT€€€
2`€€&m€€4w€€.€>€€[LÔg€€€€pD€ޯ€€J€z€€€€e€p€€<€€gu}€€€1]€€AbSڑ€€ k€€?cvx€€€P€x€€€€%J풛€.[l3[)€€€€K€Cp€Zh€<€€€O€Sn€%"€y€M€€K€€€c€€c!€€qܒ€ €€€€ƹcK;+>€\€!㡗€y€€Q~d€€Zj€€€€:U&4g€€v:V<bUPg€€Ó€€2o€€n€€}€^€€<S€&€€€€€€€€撄€8€€€€€€€€€€€zp€X€1€re€)gf0€.€r€<€,w€Π{+€€€€6€€UL`yC€eQ>hM€N€€<*€9K€wy;.€5€€Í&€?€€€€€€€€)€€a#"€d€€.XEBa€1€,€€€~€€€€€€;c8ÏœO€€:€18€€€i€€€/€€€€UTR€€€Y;€€€¤€€˔€B€€€V€d€€€@€€€€=€S]€€€€d€€€P€€€€€€ȳ4M€Lb€X€p€€€]€€>€:€€dV€€€€€€€€€wҹ€€qԀ€€rЀ€u€€€€u]MY€€€}Ih€T +(€e€€€ *€€€€=€€S€wr€ĜS €€e€!bb€&€€€=€€€€I€`7!€v€€c€€}€€AE€€̟€E|€€€=€X€+€[g +€Ϛ€€€€€€€ђ€a~€T%5€8~€t4ż_€a€M€€€€€ߵ€ѹ€€€U€?€/w€€uW~||3*€>$€€€B€3€€€W€꼣€€K€€o€€M(€€€,V€ٞ[€K€€€€€€'€NaQL€€ d3€€€€(€3bM€€€E€€€€€<€s€€€€6]€B€Ć€€€!ej€€s€€`€€€m7\€€a€€€€dK€g€€€€€€eÙ³ +€€t܀€Ҩs€€€%€ַ€€x€h€€€€€'€€€€~€€€9€€€K€€€3€0V€€€,€€€{€€€Gbt€€€ᤧd€€S€€€aa3€€"eAU€s a€ݥ€xh€,D€€Ð€l€€]Iy€€€\j%€€`€€€;Û€€€E(f€Efki€ٯ €€0€q€` I€€€K€+€€€€€Icf
€<L€€€A€€€€f+vd3{)%€;€3&€I€P€€€;€3o€€#€3€X\Ñ¢h€Pn8€`€|t€L€€s€5TKit0BKS€€€ܛ€€€€€/€ofj0€€1€€#(€€€qÔ‹4Â€È£Ê Â€P€iW€€€N5€Դ€€YU-€& +€H€€&$Z€{€€€€€DsJ€€€€€€J킔€€)€XY€€J뚩€€€8€152€PF€z€€€€]V€€€€€L:$;n< €\J€ D€m"€€y€€-x%€€0FAk€€€o€.2€APbs!a€€,€wކ€b9€Z8€w€w€O€wÓ®H€€9b€犑r€3€Q€<€€€€rG€q€€Ç€}€x€X
8u*€]C€€€€UP€>Co€€A€€€8bZ{€`€:€€€D$€VPь€€€%€b€^€!E€5€64nÝ¡`[€€4:€€€€_€Y€€|€€€I)€€L@€€€€€Jr€v€€٦€€€€€z€#bҕ€.€ɔ€€w€€€I#J€H€€€€€€\€€€€*s€€€€c1€€€€tip€yZ€€ €r€빘,€ÏÝ¿@ݿ€€€€€€Ø€€B
Y€6€}€€~€(€<€G€€~€€€)F€<D)€€€gt[&€VO^€8 €€x6\€T€€€+eg€U€`.€€€oi2<Z0€€Gp€Yu€€€€€€€;€^5/[\€€€€e€€€IA€€Q1-;€ͦ€€!P\c€X€€€€€wY€€K4€€(€gw€€bΛ:<€€€ €j€€€€i,wÓ£rÖ5€€ <Z€€v€€€€€O€I9ÝŠ_6€€€_€€€€€€4r^€€€Qk
€€€€€€]:€) €€\O0?€€F`€€ + :c€€€i'€}Q€z=€{€€9-€*€.€€MoÞ¬6V€€jb€#€€€€€€x€`Fa€€€€€1€ 919€€o€€€+€TÚ„ä €)QWJX€€€€€€f €j€€ +pD| +,€€€2€<z€€<|g@\€ä§PÚ€[€€'€€)x€€}?€€€J€€€B€€#€|€€€^>€€€€3]L€€Իl€E€€rx€€ c€€y€€n€€u 1~€t zˋ€€€,€ +e€€<€_€€€P€€€h€€ef€d>{:{<€#€]Ì©0€€9€€<€]€G€F€€J€%€€Zؒ€0€pD€€!ӷ€€€€€€x€€N€2€ €M€2Y(ϖ€€€ €5€+€$€]€€4F{:€€s2€|{i€hlX#€€Z€%rV€ 5€€€€L€V@€b€10$U€€€€)2Yw@€<€€w€€€€(€S€€€€€$É¥z€€€€\z€€€*€!€$€/€€шG5#_h€€[€€Xup€1KM,€
N2€€3€€ʢ€F€L€H^~&€
€€Q€~€€ەJ銹ٚ€巙W€:€@h€
4€ٯR€€€JG€€=K€sH€n€€g€€Rr€€:
Z!4€vƌ€€€N-
€€:g€w€M€i +;€€€.€2V€&€\Ç“{lTDj€*€€€#g€€KL€€€€m€r\€€Ѐ8€€W€€€s€€ €€K€t@€b€€G€͟Z€€€€€P8€€f@€€€C^D€t€€!€€x€€€7(€€`2€€€€€€JOێ€U€€€€:!5€z€€€ɤ€k€€ֳ伯€€€€[€€€Kir€€€A€€K€Ice~€€k€Up€ß奀€€€€I€€€]€C€€€€F5€sV€4€€W +*:€€G㺶€1*€g>9V€c€€€€€<€exv9€€Q€-\΋€€€oꞵ€€Pv
€€ӗ€i>€€J€.q€€|$cA€b€2ѹ,€€&$€Z|€0d€€€f€ €kbI€€€€€€€€€)€8€h€&€)A€W€€€€/7=€€€€€€€
h:€ +Ur€z€€A€p?€5€ +\.Amef8 +€€6€€€€€€€€€rL€€€€T€$F€€€€6
&9Zz€€'1€*€€^€€€tXX:€H€`a9€\€€9\€€g€m€{7b0b€S€fp€€jE€[G€€€€`wn€€€€f€5Ы€-k€CI€€€€€€,€€€USsq€8G€Y€p€!€#€€€ޤ #,Zm€YXffm9I€&€;€]€€€€v;€*€€Y~€u€*€2'€€E€€€€€.̓PBg€P€€
Í‹q€F€€/€€€€&€@€€€€€€€€ц€€?q€€lJ€€k€<€h%€S+€€ks)Wd€€€€€€Su€€#>€€D€€H€ €€r€€!<€s€*ݕ€JA€Jm€€(€Luv€>€_kC€~€-€,4*€€Kb1€E€ +)€h€ǗMr€€€P€=Vv€€ηK:€V>c€€;€€€Ã€m€Aؿ€7€€€|€€€:€€€€9WÍ-€QØ,€€€`I}€€|"ɇ€U€J€ ;-€'€€€\ͬ€€€€ɴӕr€€€€€€€€€M€ +€e€€€l€x€J4€{€kC€€€€PM€A€€.c€m€€ΈC?oFq nC€}€ڮ€€€?Þ‘ +=\€€G€L€%é¢Â€~bR. +x€)Ф:€€!&5€H€€€e€€0€€X€€C€l€E~VuK€͘>(Z㵳€G€ă>jdM&9 +MWޑï€*€€HQ€+,+ B?€€|€€b!d/ŋ€|$€€€€€€€g:(ju.€(€€`€€€F€k€+|C43,ut€€€I +€!€€€.€t>b€kÈ€€€}€n€>P}€1€€_€€€€€€@v€€€€X€q€d.€€€c€d€(%efm€w€€{€-:€€€׵€€6€[a€ϻ€N€€W€€y€€€€€€€€U€欕[€€2€€+€g€1€€€m€€j€€€:€€€€€o€ڎo€V€€€J`€i8€z€€R€U2"o€€\Lr<ц€€€Mh€E€€€'€[€€€\4€€ €ńgt€€€€€€€€€n$ +Pf€€.€€€"€g€€!6Z.a€ €L<%€li€=B +€€O€€€ɄY€)€€|€T€€€€7:Ÿ€5}h€€+€$
€B€c€€€c€€€?:€€€GD€mv€€€€7€›€€é€€€€xkf3€g€J_3€€€€€€l€$#€€€MA7€S6€I€9€XØ„uM€u0€€€M€€9é£Â€W€G|;€€ɕB€%[=€€,+n€y91(€€€€€€€€q€€;,)€U€€QO+€€F€цa{r€€ɛ€"€€€€€€z€1€p€ܾ€€I?U€M€<T€1€€<$€v€€€l€q€€#b€€xhG€B[p€ 9€€€:€0€€1€7€9.€n€€pj€M€€€#4€€€€"€€`€€r€I€1@€€€"+€Ԋ_€_:wV€€-'€€d€€O€b€OcE€_)€.BÂ€Â€Ò Â€(€>€n€€m€€€5vP}€€&>u€€€€6U€}€€€€€S€z€€g€ܓ€€€€O€X€"€h€€€d]€€Vlk;`€€J€€€€€J€€)ڮ€JXں€€€<€V€€€q€€p€q$€€€€}€€€6Ä’.q€@€€.€F€€O€9*7€$+H€€€N€h€ €y€: 7€€#€€c€;€€€\ +€PjxV€€^€€?€/4€€P€ +f€2€]aØ€]€2€ɂ-iLRj€€€€€€€€€u€€€N€B€€"~€ €gM€€€z€cnZ€|€E/n€۵€&̑€€€C(€€b€TG€R +€%{JQ4€T€
€€€€€€€M€ +e€€E€Gm€€f+€€3"Q€ (€paOWY€€Ŷ€Ү€CG€E€%€€€D#€€ +€€€t€CF_#a€€€€€L€€€f€׷k€H€
€2€k*9€t"HH€€t3€€2€€a€WA€€€ߩ€€;RD€)€7€€€€€A€y€G€g€€€?€€+AHֽ€€d>€<2^€€€Z6€€B€43€ߵ€€e€d€€€€4€€K,M€X€ń}Q€UDsYO€1T€€€s!Fj*י€€€€1€ +~r€€€+€€€€2Q€@€ޮ€€€"€W€€€€€1€N€D]€€€€€€(@€€€(€€€AD€?€€€€€€€€€€€e€fm€K͛€€vf€€€€Ow€€€€€*€*€€€@€€<iX0&€€mn€.€v€|4n€€}€€€-?]€€€€ajV€€p€kEÑi€JXd€€€€2
€r5€f€€H€Y3Ó‰p€]oeHStCe@€ℹ€:€yP2=€Ù€N€€€pI$€yWÚ†HԘ€]o€$ €€€h€@€0
€4x9HgCxc€€€FN€€Vh7€€€€€€ 'ÓŒm€€Cm€Q€ө€€€€-iN€€€€€O"€k$€)€€€v]'É¾Â€Â€Ú Â€Â€2)
€€hz€G€2€GNU €"€€€t<€€
€D€€Q6€€c*n€€q-䒳cv->€€<Q€Xf€A€J€€€7€k)€L€ORr€€D€&LИ€T^€"€)€8d€€I€hV€0€O͙;€ڞ€xY€R}vp€€€7€€VK^€)k
€?h€^€8j€:€vT€BVhʤ€€€€O€*€/€€ €q9A€|€€u%€€€€1Ƀ€€!€4;€5€€Q€|,&€€ؽ€6v€€€€€€€€3€€V€w€?j€€=~€€€n€€€€ї7€G=€S€€€K€€BG€j0pu€n6€€BgV<q€€jt€€͹&€€;€€€`z€€;'x€€€&u€€€s€€€a€€PN79€g€€€€€3_€u€€€<€>J€R€i€€€€€!€6€€€6Q€€€€@€XF€€,€€€€€H €-%j€€€u€H'€€€.€€€€€€~€z€w€?€"€k,b€€g€€KjT€€€ܥ2€€€€" €B€€€€=€€€€k€ml€€C€/€€€Be€€G"€eJ€5<^€€€\4€€5€€6d^
>@P€%E€G€Nn€€p€^€€€€€e
€iL€€@+€#€€€
€€z€€>€@?€€€?:1€€ V€€QRvf€ €€ m\€€4%€€
€€b]€€€€€€ !8€€€€€€€}o€€~&€€€ރ!€zz€€€€n€r€j€Uw%€€€€ܿʔ€5€Ξ€[P€w€;€€-d€€€€bs€€€%€;€4€€€Ýd€€w€2T€€|€€=€€€€K€dKD€!t̊€B€€F€€€€€€V€€pW€€€€€€d@€€b€X€^-€€M€€€€+Ʊ€€€s€€3E€uɛ€€€mK|€€€EF€F€€8€R€€NaN€M€€€"€&WЀw>€dg€€€€<3€U€€'€T€€7€(€g=w€O€€1€`assjL€€€0€h€€_€4b€€€€D7"€d€€j€E1€€r€€k€€€<€}GgB܀€C€“r€^[€€s€€l4€€€Y€M€;€€H%€€€r€€€*Cv*ś€
€€+/F€€z0猧€€]€€&€?€€€L%s€€v€€%V€€U€K€€2%€€€u^€€€^€arh€€~€>€€!€€€lÔ¶rn$ +€$€M€ژ +€€+3€%C€87€ve€¡*€€XOS)€_€Ga€I€€€€9€y&€€Q€4m€€€ҳ-gX€B€^.€m5€n,€€€€4€€=€€€ɤXS5Z€€ۤ>€ok"/|€.€€€€€[€€w7€A€$ve<u€L€€€€€,rC€Y€€€Π€€`ÒŸ]N€f#z4*€ө€[N€é˜Om€"€€q€[d€q€mwd€Og€+C_sn9}0tÏ•:@€)€€%K!?€Sh€€+€M€;J.€»o€"€:af€MmHײ €€€€&0€€\%*€€€€€&i€,€€€|€r:vQ€Bb-4к€€€LwrÖ˜W€€€>!€3€€€P€€€€€€y€€q#€ظ€€L€€)î³²I€€€\€cp€€]i޵˒Ɇ[€sR}€€€d,h€L1a€€]7€€)€QJ€?€q~3ᜈ#U€)€€D€p€sy€S€€x€€€€,J/€$|€€IG€€x€€€o€/€ϗ€>€%€€tM€€)€€
J€€.dC€s€%€Ш€{€c.vdy€€Ei€€>€y€€€€€=V€€€€€X€€6 ſ€=€}5€l+w!U€"\)-t'@0%€€€€w €€M8rTy€€€h€p€8€(€€nOĪ€ e€32*r€ €€Sm€6]3UQ€€bH,X>€e€€€€J€3€€€Sp€€€€<[€yQ€Me€]X€>ÉŸL€汩<-B€€?€€€N +7€€CH6€?n|.j€2׉9€ €o0€Px5€k€&!c->{€€€€€i6€€€€8€€€€€!€]€aHn6cÞ3bZ€€A€<€z1€ O€h€Q€€€9€€€€€€-L+€€€€€ZΈ€€S€%€*Xv€€€i%/~€J€€?[W€{W\€€€€€aa€€]€r€k€€€b%Jm^€€€€€8€N€€Ær!€€ί6€€nA€€A€L€u€€ټ€€h€u€+C€E7Iw€€]€!)ZOC:&I€m.E€U€€€j€€u>W${€X€€eL_€€€€KÙ¬S€Hq€€9€€€€€(€0o€4€B;€ȡ8ߟP€€€^lm@€{€M€€€r€€€€€€€Q€€€@i8€€€€€€€7€Жm€|€Ǜ}€،g €€€eB€€K€;ZED€€rB€€Z€˴€ZUx€€€H€'1€ڪ5}X€ôI€V
€
€$€؅€€:€€f€€Ù€€aπèi%$-i:€€€€cWZ€C€ڡ€~€&Y{p€2€k€cn€C~€R€K~+€€€€€€€€€"€€?::8<9{€{RÝ€€€ݾ€€DzUÝ«!%R€}€'€€^M€_G€€ݮB€k€[€JO€€€K'€€€€ +Ë«X€€" +*6{wTe€€E>€€€Z€6€€€€€€€€Xm
€€2€€r€€€€'k{2€R€€€€€€€€?€+€€€€€€%€€€)€%]€€0€€€x€€4€€€€y^u€€€€u€€€.|€mj€JN€€€({f0O%€RC€ȸͅ€€JOY€(Pֳ€€8€Â€W€€€€7€zD>€E€>x€#J:+G€Hi€&€€9€u€Ý€u€p€€€I؀€€€o€F€X€€€€€R€yQ€ +4€N€D€S€t,UҞ€W€+€<€e€W€€€4€bŽ€s€€G€€{@€€€€€€Rb€_` +€€W€€€€\€€*#€€€€K)hZ€€炪%i€Q€€w}HE@€l€KK€^M€J7€`I€€€€ &€|€s€Q!€텱)€c€䞶€0z€€.€1€a€r€€h€€n€1#€cL€€€3€€d€Av_€€T€o9Q€n €€xXE2w€N*€€l€7€€€^\€뮣ӽ€w)€5€€€€1L€%€?€R€€€€l,Ӿ€€n€€€€} +€€€€€xM€ w€€p^€€€M 2E€€p€sz€tW€€扯'€€+€€ €€-€%€+t€€d€€€€€€€€7d€€€=*f€&V3fcV€€I€';;€€ή€nn€€€s€€€€L€%€çŠÂ€m€€€€]€€€€Bk€\Ó¦YX +€c)€Ȓs€€^:€€"€P€€`€t€H€€€€€z€€€;D€€;€he{€€€'€l--€֫€€€€€€!@€€€dd€D€FÈ“g€;!€/r€I€w +\T€]€+€€€2€ +€mH€ 8gN;PSH€\€e€€i4€~MCc€€€€~*€(L€€- Y€€R +€Ü€€K?Q(€P€d€€q€y€€€Eb`€€f<€€€J€€=€€€€€€€€€Glp?Q€€M€€€€6€-€?€IÂ€í¹¼Â€o€€FS€WU€En4n€Rx€€Y7€€&]|€Sn€€
€i€€&\ +7€^€J4€€*€q€piI€€xRc>{€9€€w€3Y€؟4€€€'€0€R€]`C:€u[rij€}~0€y€€€#-l#€€€u€C€4CF8€€-€[.€@F€€~Du€u€€€€€Y€Cn€t€r€cҹ€€€€mn€€€€€€$€5€€X7€]أ€(€RC€>r/"€ը\K€{dR€X€€€ˤL€€€€!€gnي€}€0"€€1€€€}$€€€bj€€€€1h$€[€٘€€€€€€(€€h€n€"z.ÈIA3€4€WQ%€4$9C€ʷR€F€€€€€n€€TGU€€U€Yoȶ€€€=x/€ +G#;€!€J-€H€€o€€V.8;K,€HD€€€Uq2j€€T€C€€€€4€€€|€lu€€-€6€w€€K€€0wt}>xȯ&€,@\d€Њ€€\€D€n&€€~)€K€J€€~C€@€OQ€€€\€VË—?€€w+{V€€ΗzǶ{×€€€7€+€du€€^€M€>€€&K:€€ذ€€€qM~Q€6€€,웊o€€t:C€{€*€i€€8mM€€mj€€€€€@M€€€€#€€LÂ€Ê $8 ϶.$€1 ]€€#€€€€€}€0€€#K€!EC€A€€€€€E€q€€€€â’5Q€B€ȉ€,€€I€€€€€€"€€}'€€ن3€3[F€€€€i€LM8j€€€€€Jnx,€fK€g€+8a€€€rC}€o.͈€€ +wa€e^2% +&€6€€Y€!€€j6r€€€€€W€}€X€€€N€€>Rs€X€€€|€-€/€€€€A€#]€IR,€v€€€gxlÆŒJ€€€:€€`%؆€f6€€H*€€ÎXD€&€u€€zR€_€*€€$€h€€€ €€M€Y€?€€€€u€ˢU€€€€€€€@uն€C€W€{€€T€€€'V€€&€€€€τ€K€€€€€E€€ɺ€l-€€*€W€€An€€€×€€€"€€€1€n'7˛€€4€Pi€€[/W3€.€V€€€v€€€€ӎ€7Z€€|€€^4t€€o€€€2€Q^_-€# Bd€€k€€€€€€€€=P€l€Ë€€€a€$€h¨€5€€T€+€_D€p2€€!€€`€€T€bR€€7n€%[`k)€€€x€€€€eCR€€åªÂ€Â€*€€2€€QIO€l€ǿ˚*€€d +€d€<7€€€€€<€€'€h€v€{€G€€€P€€|€ûSv€a€€€€+€Tk?'€y^€`[€€G€ԣ>.€,€jA€€{؄€€€€€€c€S€z€€€|h@$€€€€€`€:}i€v€y€$€€€ݲ€€€€+i€(J;€ԩ€€€€€zu€t€~€x€v€ߩy€?€4€€€q€X€&€y€€€€2€€€WmÝ´(%€9€€€{€€f€h€€~)€.€Ws€<€%€؟€€z&x€w€€€4€€S€€€Ҝ]Ly(€c#€C€5<€€c]€_€e
m€G€y€*O€€u€€€€€W6kV6€ €K€€€ +l€€€@€֗f€€€€€;o?€€€€sv€;€^€€q€€ߧ€€€y€€0MѱYs€Q
€a
€€€q€a€Xv€€€€L€đA€€jq€{`€N€W_
€€€€ <€O|€Z€d€A€~p]€€R€"€l€€3€€€€0|Ԁ€~Fb€* +6€O4€€€,U€€×€€€e€€~[>€€J€€9€}}ae€€]:€Ɠ€e€€d€€€€+€€€m€>6F€€Eȱ@~^€€@(€€€€u€]€ay€€'€€€,O€/€€€€l]€€€'€d4 €€<€9MB€€$€€H€>W€ +O뉘€€€$€€"+^!M€3€7€h€€?|€€l€\!<€P+|€&^€€€C o/n€€S€€€Dj€€€€€2a8oy1?€)€l€d1lN€6€€ €VA€€{!€ €€€€€€"?,€ €€I2€€Md€6€€إ€p€€T€;2+12€{€a€PJ€€= €€€]!ƒ<€]€€,O€€€€NK{€ʡ*€5'€1€^€€1㸬€€€kI€/s€€€tÏ•É«<(}6ÏŠ!È€€wG@-€€€Lb€s€/€@<€€{€@N€€n[€€(€€*aQ€€€6€€€ꔢ€6€€€5€2B€t€8€7.?F€vݤ€€B€€Ç-Ó¡`€X€€̚K€&€€€:€1C€(f9€€†€3{€ev€a€€zX€kSP€-9€H€€€,€|€€€yD|€%€B\€€F<€s€€3p̋€[€ƿ€ Í£oA€€¨€ }€V€|vj4pdQ€€0I€qWt€U€uéžÂ€Â€Â€3Ο€€Q€€€€€€9h},€Өá¬+j>kfZY€€jN +€€€@a€€€e€h€g€€`.u€€sP€ާ€€|€b~|&€Wk
€_3€dR:€€"€UY €€€€*7€ܒ€€€sx€€nz€p€NoΜ€€t€i€(€€€€€€€€yI€€Ӵ€1€€C€€&yIb[۵€]€€€€€€€€€*Y€mgr-€h$^€€)€,€w€€€=T€€?g-€€#鹒 €€€_{€€0€6Yc6€e€€BY;]>6€q0€€€5€a€€ܞ€2€€,€€)"€€d€€&!€€u-kb€0€N €b€€N0€.€€€€cc€OZ€}x +€€€('€€€€#€€:{ +5€€QDOi€€€€&F +€/€€A:€ot€€`1ci€L+c^€€U€€€"l€P€€¢l_c€o€ ˓~\€€y1€€v€.4€€@€~텦€€€U+€_€€4€2+€c€b3€_S€€€€|€L%€o!C@%oO€a€i}p€>€0€W€q€8€€t€ˣ€X.€€€;€€€€s€€€€€,€€€3m€€>=Ҳ€€Ll€S€€€€ά€€€€€lF€" +€A€GF€H€Q€X€€"€€€$NG;3Y€€€Ĉ€XsO}R€€€€€PM€8€Dc€S€€I€€2€€=:A€€€€€€€€€€€k3$€€€€€b~oGI€Jy€I0i67˛€€€€€M2€7€XCok€R %€<,b€nǣ"€€f€€€€=k€€€"€€€€€N0€j!€à i7€$€o悛u€S€}r€€e€€€=9g]G€g€€€€D€€€.Ӽ€€q€!`o€Q€E
L(ր€€!€A€€€pE+3`€8]8T€€~€\=z€燱€YCe€€؃g€)€€€€Nn7€\€€ί€>#(€a€j€€€TGκu€€ɻ_€€c:€êŒÂ€Â€Â€Â€a€€€L~€€0B3€6h€JMbf€[L€#€c€€'
€€v€;U€€€{>€O€€€€)€€}|€€w€€!Ùfly€@'€tY€€F€€מ'€G€?€Q€€j€3>È„g€€!€z,f€€`€€€€M€€p3€ʡ:l
€"`€l€r€€€k€-(€mk=di€è‚2€€o€K@€€€€€€t€€€8€ޫ€€Z€€N€€v€€ +s€€Č)f?€y€ӷ1€y€€€>€€€€;?Y€;Yub€€(€€>M€€q€€€bzp€7€€€o€%:Ѣ€k€€€C:!^€€U€€€€€€€€[,€R€€:{€v€€}€€€€€€€€W€W€€€€{€ €€€€€€/€€,€€pK€€€€€€x€€~€4€L€ +ſ€M€€€W€€ڎ€VX€€oj€uR€€+ֱ€€p€€q€€€JÔžeg€r€T*>€߄/}TEݰ€x(€iu€€x,€€l€e€€b|1qe€Ah€€€8€=F€€€k7&€€hckdFqG×€O€q€€€Ʀ€U:[ +€€
z3Ҝm€#€€qV8€€€€u€€4€j
5€€BC
n€€€PΘk4€5€€7€a3€€€€τ}€€€€:€€؊ €€J€}€€D€€9y긓€€R€€H€€x +r0€O]^€€}L=9&4uu€]€€K€#€"N/€㇟Õ€€6`/Ǽ!C^€=eN€=€e +€i]?€€}€€r[€
*nO€€€|It€J>€€XD^HښYh|ۘ€n€8€€oq +Z€
€ bB€B€€€€T€€€.0€€{€€@€€€€ƿ€€€€_€€€€~€€#€k€H€ €€€m€€
€€€e€Q€O€:€x€+€€2uH€!€€UK€w#dH€€4€)W
€&&_€G'€€€€€€8x~@r€g€€€#€zD€€_€MCZ4€͹€€"€ʼn€h€€ €€'anNÓ€X€;7$f?€%Y€€€€`€g€y€z€€/€;€\€^€€~n€Jt€\€f€€c€€€fG€ٙ€y%p?€ €€€€2€W€ €F€€€€€K€!~€/€€P]€3€l€€8€~€;€$OQ€€y€J0€z#€€€݀€€€[€€V€؜€€€0€Z€€€;€W€€€€€_€€€€%€€K€€ߑ
Ж€€Z€E€€€Ǭ€0p)X€€^FG€DK€y€€jj€L€E3€y_!6€€€€C€€y[€nZ€€€|/p9€:!€=€€€0v=€<1e€€|€A.€(*€I€T€LOIӽ€Q€€51€m+0Ej€€€€$€47€Hs€a€€!%€€:;€}g>€€€2€a +€€€€€es€€€T€€€€N>&E`€€֥€€€€%z€€h€€a€€€)€oL}*m€€€€€€,€€X€€€€€Ϥ€S€Z€K€<€_€€OH€€€€€€0B€€€&€€€€S?گ(`€ €€€€€€SR€€O€$€€=4€€(€T€€fb€3€k€€JNU€P€Y€ +€€`H€€a€D#€I€YK€Nv€,€€€b€:-h€~€y€r€_€€€U1€!€bnqB€MD;€}g€€€ ǹ
€€c€€€p€ 5kI€s €€€€€/€Q€€3€#~€1€K€€€€t€€€€€o€l€AVa€~€>€G€޻ˢk€:ʿg€e€[e€€e#^€€0q€f€€€€€€k€('D€€€€€5n€€6Enn]€{€€
tangle.chb.oldsc€€€€€{€€TEXTMPS €€€€L€€€€A^€}€€€vbU€D€*I€€6€t€€€€€2€€F:€z%a€€ԗ€€€€z€€€ v€€o€c€€€T€@€3€€G€€TD)#€€)€€€ʙiD€0&€€b€€GR€€p€€#€4€€YQ*p+€3€p€(€€€eUÇ”9]d€YVF?G€B€u q€I€É€z€€.€3€€€T€€9#)€6€€€€€i€€€€S€€€!7€€€!:€€e€I[€€€€zW€#(=?€^ߺ6€€€€
€B
€€ 9b€€f€€S€€ghN)€€ €€€JV€K€v€$ϩ€#+#€€0r€#€€€yN9€s€ճ€€€€$#€G,€u=p€d€'Ç72á„“1#€Ʉ€ €d
€€߃€+€\€€€€5€€€s€€ `€(Kx€bQ€W€^€€€Ƭ€€€s€€WpX€€€υ€cnVW€x5€€€K€€€K€€€~€€3€Ƌ3€€€€\€€€L€i€€€3€€€787€糰c€€€'E*€€ED€€ǩ€JÂ€Ê ÍŠÂ€Iؼ€€€{OK€€€lR€€€€€4O€€Z€€€€S€a€Y€€€€Da€u€€€I"פ€€€N=€€poN\EZ<€€€€€€€`19€€€E€*€;€U€0e€€x€€€3@
#{€€€€v%€.€€€.€A€2c1€y€Є €2^,€ +€€€€€€€Me€G€[ +pu€a€9m€€e€€o€€'i€€€€€€€
Ö€€CQ€€4$€€€€€€€€uy
x&C€j€%>€2€0},€#\€;€?W€€€&$€W€€€€p^8€€͑9€)2€€nh€n€S€€€€€@€€-@;€€€9€m"[pܤ€`Q-=-lt€,€€de€€€UqS€BCa€V€9€€€N€Y€|€€€€ +I}H€%€Z€€*NdÇ•R€€€€pZx€€€)€;€ Â€Ó Â€Â€Â€Â€Â€hy€€€€€(€e€€€0€gf`Ï*€€
u€c€€Jbh€,P?€€,€€€2~Ƴ€€€€t]8€R"J€ln€€+€€h€€ ow€ђ€€NZ€P/€€€€€ι1V€Db€€|9€€€ךQgAu€6€€€qk€ €€€€€€€?}ckk€€,bÒ {Rl€ %ShՈ€€€8C€S<€€J€U€H6$?€€€E€{€€o€I9€(3f€3€6X€ 1]€€€ܬ€3€v€8>z€ +€fPVzU€}w1€€€€M€;W€€€€;€€_p€€€€G€€€N€€<€o€5€€r6€`m"n€7€:€€ €€€ +€€€g}|€lݞ€#%€Io:€N€€>rn€%€pA| +€€€€>lÜ»_e€8€'€€)YI#E +€Rt€%'Ew€€€€<i€€€%hݨd€€:€€;Ý‚?€€€Tb€qT)-€€€\€€km#pf€€ѢJS€\€:W €KT€&m€€€€jA€(L€TG€€O +€6Ù•=Ø›L ȀhWc€€þ€€>€€€tG~A€€*€€€_€€`€MP€€K€€v#R€€€€€€=N;>N€€M|9€€ݽ6€ݹ~€t€€€Q€M€5%jXj€€€mÅjz)mÒ³W€1€8€Xs,€u€c€ +€€€€8s€H€x€i€[€€€g)\€h€c€vK€C€`gX8€5€€ܤU€+N€€€€€€R€ڨÜ€@€j€€€€H€pX€€H€€€
€ff8€vG€€€-€/:€A€€ov€€€€d0€€€€€j€<#€€€R6€2€€U€€W€€€~€[€;۴€C€€)k€€gR€€€€r@e+U€.€b)€€€56y>v€€€€€E€€>€€=€mc>d€?"€€֟€؄Ù6€&€ۑ€IY€€€€c€€€€V €
€T€€Æ{€€組M€€d +€€}€€€8\Z€A€€h€€€6€U€u€€€F€+€€€M$€€|€b€€ €€€€€|€T€€€-€€€U€M€U€<€€Rܴ_€,8/€h.€&<E#L€€Ԅ€€Rp€U€
tangle.rsrcoldscL(€€€4€€€€€€rsrcRSED€N€€€N€€zI€Yf#D"*
€€2€Tsi$#ǹ€€€.MK€€€€€E€€€5^€)€I€€tC€9€€}n€€6< \ft€M€€€€Fԛe3€€€€€€€€€yO€€t€€€€€Y€€%€Y€€p€ +!€€sEˤ€€&€-'jM=€€g4€€€$c€€K€€H€€€4?€€ћ€e€dZ€4L1L€I€€P€€.E€
u€€€€Q€@€G€u€]€+Q€€z7€€QW€~€€{Q€€"N€€lvM+€€€€⦢€€€€€€&7€€€V€€€.€€O€€€€ؿ!࣠hϿ)€c}qϿ)€c€€
€ÛM€7|€€€€€€€€⤞ €€N€€|€9€€€=€€€€€'€M€€o +€€€Myk'<€o +€8€o€€-€€€€€€€3€Y;€€q}€€_€€€}|€y€€€€€€€M€|`ͪ€=€ܿ9€c€€c€pOk€€ﳎ€€€€`e(&`€ˊ+€7€€;Bi€€€€r€=wа€€h޾i€śF€>QG€[X4€€;
#€€ؓt€€-v€.€€€€m€€c+€€O€,,€€€b[O€X€ €w€Ct€€€:h€€,€€t€€= LGW€w!]iaY€€C€-€>`€€*{€?UAW[€€€w€>ba€€€€€€€G€€{
+tangle.webcoldsc+q€{D^€€TEXTMPS €m5*€€lR€€€J€€€%€ub€vbS€€€-€€ŵl€&€€€|€€͛ŕ€€€€€pIXj:€
€€jx€€€€! €€l€€€{_F€€Om€€>€?€׬€€€€G€)€J¸€€€j͸€€€c€8€)€€&1N1€€i€€AR€шdicY5€€€€€€€€€€€bF€ȹ€s€€WR€€猤p€€€Gυ€u€A€€€€'€€M€1€€4€€€RzW€fW;€€€€€A€€)€L€o]T? +t€h€\M€ c€(5+€€j€ Ծ€iNy<A€k€€€€€€:€tYË“?%€€€€~€_€4|€€L€ۂ€wS#€G,P€w]N€r__€rd€M~!A€SJ~%€XYp€€€€€€nHh€€€€ؾ€C€€M € €G€R€6€€€lj€€ [A?b€€o€€Mʦ€€€€p€}€€€P€€r)€€'/ÄŽJ&ip6€E€€7_€€D€€4€bq€E€€4€€p€€C€Pf€K€€€€2€^.3€€8Vb E€ɡ€T€€€q€&*€€Pq8A€€€€JĨs€åŠÂ€"€R€€P€€€€~9€€€€c€€€c)/€q.€A*€\€€z}d€~€€€P#q€C€N€€€۲€q€€R/z&€ny4€€€€€ €€€A^Ð F€P€€D€%€€€|€€€€€T€€s€Զ€꾙Sw;A€€€€€€€;{€€€;€€€€€ۇ€€€ǿ4€€J€$Ø‹DI€!U€€€i€~@#€'Ik2€€g€E€M/D€€\€€<€eJ€€Fx€€qR€€R"€w€~€€Fg€€€{€zH€€D€€rx€x€?€hbk€€€€€;r€{€€5€Ú€€~€€€€€Fpc}lj€€€€€€L#×ү€~(€~€€€Q€€€€0("€{I€€ۖ€z€€€xp€€oM€€P€>|€€€A€€€4€€#€4t€€€€€€Kk€€_R€€1€}K1€6€^|€€€4€m€XR€'rt}€r\€=<9€€€ы/€€(€_€5V€€€€Ë€6:€€8JSuyW€€u€€€Ǝ*8EV€z>
€P^ۋ€€€€€?€̼€1€€çŒÂ€h €€6€r<VE8€z4€.€5€€€€€"€8{€!t€{^€I߀€J1€€0€€€€€M€€8€$Ue['Tmo€€€3z€€€€€€€€PW˂€€A7ON܀€J€ €€3€€.€€8Oհ€鸯9€ֵ-€€˄'F^€€€[4€€x€€€€"€€€€€%2%h€€€€K%€€;€€?€€€.€`€c€€X)€€€HbtA€€€€€|€€Ķ€€€@9ؤ€€3€€€€J+暎€€h€i<€VG€*b€g€e;€f€€€s€c€€€p€8€€^€€eM1€€€}€픡€€€x€x€€F{9€€%€?B€^€Ĺ€€€Fl€€x€.ET?€[ÞŸW2V€€€`€€€`X&€€€€;s€€=s€€€Vwo€€(€U€6€€€wz€€€€€tr€^€m€R€€P€€€E€\€€€3~€€€€g€€`€€X€€€€€€€w€€\€8€€3€€€M€€€K€€v
s€€ǒ^€€I€€a€€y€j€/€n€&=4t€€8€^€€€)֖€€€>€W}€%€€€€€€€€T€Dy€€€co€€X€l֩€B},C\ +€>z:€\€€F2€Λ€Q€f솴7€€ttNyY€€'€€€ Í’S€vO€€€€€D;€$.€€€€h€€9(>.Ù§CSN€€r€v€D6q€€€l€^€€Qè¹Â€Â€Â€58&o€€D€|x&€4€€N€d€1}<ʀSB€€€€€,€€€rIo€€€n€cv~€€€€€k€€/M€v€€z€}W|€€?€+T€€€99̃Q€=Y€N€~@H€$€€€\d €34€1€€€€€}s!€ql9€€€€6~€tY€/r€M|€€€:.Bl:>4#€ +,%v€€€h€€€Ɨ€€€€;€€€€€@€€€€€€€€€v€2€€€_€€n€€€=€€=€€ +?€yl€C€€7tX€c`€=€S"n€€q4€x€~€€ *B€€]Ud€€€2€€€D€2€35€d€€>n€a|€€X€€
€XÓ‰~K/@ €€G€3GkB€䶇€€o€€^€€S<€H€xߖĮ€{€€€€g8#€€h€€€v€€5罬€€($€€+€€*€€€pB€€ h€€p€€ö]ݽ€€€&€E€€€€ʹ€€€€iÔ Â€kbpÅ€9€€€€€€€8nX€{v€€v"€ €l€S0€3Q€€==€€5€€€ ^e€€J€p€€C€€€€&€€€l€,€€€(€D€€X€€€9€€€q`}*C\€'cBX€N€€:€€€€€€е€€F€C€€LM€€&€€#€J€€€S€€€€M€4Jl7Fs +€€€€;"{€N?€€€€€€€ +€€€€M€viT€W€k;k!€€€pX€ȼ€E€Tk€y€€M€x 0€v €€\_€€ƌ€yÐ 8€C€€€€€€€€p$X€€+}€€f&€€€€Y€;€€€€ۙ&€t€€€€€€c€y
€€€3v€N'€ €[ݢֵ€C;€gq€F>n€€€€Pa€ϒD€E€0m€€
€swx€d
€j€@€€€€€v€€€q:€€`x€€€&€€€t€&Y€€#I4*P8€
@#Z@q€€r€/I€€=€s€€€Z€€€€€M€qp€0X€t€€€€i"€€]wV€€€ €€€€^€€0=wAÔ€€€€€€€/€€€h€€%6€€€€rYp€€€"vWskNG€P€€t`€ea|'l$€€€€t€€€€a€l(€YLk}=€€€Z€€€ʪhR€*F;€iGn€€€€m*€€4 .€€w€€€€u:U€e|€€€Jd€.€$ዛ€€€h€€€€n€€_€^ €1€<€} >=pl€S€€QW€€€€€€€+€Β5€€€€`€€€€€M€D|V€€€€€ޞXn€Mk{E€€€€c}}Τ€ ukc€R€A~€Ey€y€€€€€€€€€k€p +€€]"-€j€WdB€IVp€o€`#€+X€ufv5€M€€€€€€€€
=€X€€ +€€€€8€€Ҝ€€€Z€€€Ù#€€d€€VF_€€K€€€€[€G€€€€€s7l`€€€:+€v]€QRדĕ€€}€\€€€€€€1€€€€&€'F3€€€€€€€€€1€€€qs€`-a(€ṋ€)€€չ€€€@E€€E€€j€,€€P€€Ei€€a€7€J€€׈maQh4P€€و "€?€m$/€€0€W6A€€€€>€€€(€A€€_€ €l֫€€€€t€€€̛€M€€$€€P1€€€K€fwf€x=
8$€"€€2N€sÏ ;<y0Z€%€4bAW€i€€€&€€yw€N€ +€€€€€€€˃€€
€zEAtl€€k6€€€j&€€€B€׺€d€'€€& A€t €I&ϴ]@{E€€S€€€&v€ܷ[w€|€>4Lq€Uz€8P€€€€€p€€€-€`€ €€Ԝ€3^€€I\€€€€L'€Cf€€y@€€4a€€€J€€YL€€€€|€lY€€d¨֦f'S€0#ʺ"€€I€€ €d€dl€q€€€€€€€€€V€€€€p€€>€K2ť2€G€€sa€:€€R̶€7me€€€€nI€@b€€=@€#
€$Y 0€€ -p€€w"G€€*C€€€ʂ€##€€€€€]€€@€€C[€€€€\L<#€€€ӯ€v€>€a€€€€U~€€͗€o€aN~€€7KÝ€€€8N€/€€[O€€€€€7l+=€€€€€€‘ܪ€8€5€€/€€€€Z€€€^^€€€$쎱W`€ €€€@€\€€€€h€0€֒€€€€€J€€]€!€€€/€TQe€€ЂḒ€Ƕ€VAa€€€€W€€€€#B€€€€€E€€9€€€#7@€€w€€`€o€€€€€OU€€J€€!€€€€€Fj(€"€4zD€K€D€1N€€ଇJ€pv€b€'€@A €€7€w@€lL€€ ,€€O?€.L@€€€€€€w€€€€€€€p€vTu€€RB%€€€A€'€€€_j€€5`T€v€€€€€1€H€MB€€€i`I| FØ´#ْ€€ڢ]€€v€€€ +€i!Þ Â€<€€€€rA<L€€^€€€€€z€€)€a@M82€.€>€€>sC€€€€ׄx€€)C€€:b€€S€%êˆ*$\%^y€€€€j€S|Îl€4€€€Jmj +J€XP€gZ€€U€€0€hn€$€€€€Lt8€€(@ٜ€0€€€€X€,€€€{€€€€€€Z€€Ay€}_€
€€^€j€€T€€TEo€N +€x,€i%€€U€€€€riL-€j\€€8%€€€;`Qq!€0T€€€T€€J€XAP v*C€€ڢI€q€€6€c€€3)2€€€€.€€€€€b\R?[X€M€€€_€آ€ɚ€uÂ€Â€Â€Â€Â€Â€Â€ì¼ 5 ^€SDã—€€*€€C€P€ܣ€€€€€€€ܫHF€€€e€r€r€˽p€W€̎€€C(e€€q(=€€€€€€€€V€%e€€€ Ýœ[c€ɇ€€LDY:H55€€7 0€€eT€€A€FK€Dq€7\€€€T€€€~"€€€€€l€€€i€x€
Ľ€€5R€B€<€o[€5]€@h€€€y€€o€'^ Ћ€€]€w€5'€€KB€€€~p'€€€€@rř€ݣx2€,€€€d{€€b€€H€r*
€Fpl€€€€ oD€€€€g€€€+cL€€€9€:€€^|€.€€€€€ ×¥x€m!]lÓ€: 1€~€HK€€€€N€€€,€D€€€€N&.T€€€€_4€`€t:€€+g€^M€€B€ȫ#6} +Cla}€_6€[%X€€ٱ€€UZ+€€C€€6]Ö©T€{€€€€}e7uׅ€|T€€€;r€o€(€mU€Q€€RE€4Ixwp€s?\֦€€€€€\€o;€€€€€N€€€€$;?€€ڦ€€€\€€6€L€肽6€€"ܯ€€€€R€)Þ¬C€€):€@€!€&€tm€XHb€^€€€t€€\M'0€€ǜ€9"3€€b€€»C€€€@xQ4€Z€€€€€€€€€€€€€ 8e€+€6€€€€8€€€€€€€[h€€ٿ€\€€€<€$€A€A€d@YF€€€DVJ€"€\€€$€11U€f€c€ e€x€€[€3vC|€€€Z€€]€€7€€P€f€C€
€€"Ňq€€VdgOx€€Π€€€Lr€nh+M€€€€1€€€Û€€€+€c€€€€G€€€€Ή
0€$€d€€€jx޳<^ €€6€€ +€&€[\`$O€€€P/€r(/Y%€k€T€Kܳ€1T€I€v€€D$|~€€z:q€g€€€R€€€<€S]€<€>€>€f€€€A€€€0€€t1€|€p{€w€€€€€€Ѵ€-XHv€€`€a€u€€s€€V€A€€€ly€>€€€b€(€9B_€€€(€€[€
€5€€€€,€€yz€0€€€€€€€`€j^€€?€'€€€€€lC,€€€F߀€€€,@ǖ€€9€€€n€"R€`€?M2q€sI€O€€c2€€€€u[ez%@€.€€€€m€€€€P€9K€€bO€€€€wP4O2€€€€YHN€#;iNF€€€€G€€€"h;f€D€ƹ€€m€B€€€€>€€Lj֘€€I€n€€€€]€Vb g6€€€€T€I€€#H€€€€€%€Ö€€h€n€€ǂ€ʆM€:€:€=€€O +,€Fl7ol;8€€€€€€€"ɫ€ܞ€€|2|v.IOfgW€€€€€M€€€€er€H€&€€@€€€€€Nxdu€€€€:€D€€€ޅ€_€€$t€€,V\Ï°B>€&Ș€`€€€€€py€s1<€€€.Y€€€}uZLn5€€€€€A)€m€€€€€g€#f€€€(pL€W€.m€€€€ï¶N€€z€€€€€€€€€€€.w€€€-ZK&~Q€_p€€~€€#€ €€€N€K€l€J.T€€€€Zv€€€X€Sj€bs€G€i5€@d€€7€!€€I€€}N|و€€€/5?m€€€€€_c€€€€5€7p€N€€E€`aJ€n€€€lT €J}€'€yh6€S€1e€`s6€c€?€€!€F1€€k€@€ +€€€%f€ɤ€E9€8̕€€vö€Z€j€€c€sj€€Ac/€€€€-9?€I€Q€€`SƸ€€€Y€ь€s€€€€Įk€Ɩ$€G€#sH€€p1€`€€%%/n€€ +€{€€€g€SD€d€>€€€K€˰€€€€€I7{Â€Ü êšš<9€ u€€€€RE€a7€€j€€€&€fUUO]€B€€€€€{(€€mQ#€€:}q€ÜOLNE€%€€VÑœh?€1€~0€€ |€€€Tis1_€l€€کH5€zP€p €€€7!f€H€€d€^B€€t@€€€UH€M€€Ƹ*0€€€~h€€J€€S +€t€€€xIQ€ €€[`nZgA€€R罘€a€Ey€Zǘ^o-€6€€€2€X€€€cr1€€-€€€b€€€BO€€€€۽/w€
€€|i€€^€ G3&€f;±K`€€B€€6€€P€N€Z +€m€dh€€F€€€€€0`€2F€€ jy$ҫ€€yr€\>[€X€€&z€€xx_€€M€)4CT"€€8q€€r1€nV*€€Yp€_*b€€€€c€€N€g€€
€.€La€a+b3c1€I-€D}€A€€%€€h€ Ȼs€€€ѓ62Y€€!lc€€€€€P(`€€l€€€v€=Y €:T\V3€b6D€€€k€€€bF€K€€T€Fd;W]0|€Rt€€fY
Ylf€kOA€€€ €Ҥ5€x€€"€€#
7€€€€€€€ϵ€€€€l€Z5c€€€€V€vD€I€€€r€ €*r€€€€U€wu%`€܈€€xP
€xډ€ +!G€€c€€€€€€€R€€,>d€T€3F€€€€€صE€€0€Z\€0€tD€a)€€€€°€€€H€ÎO€€€€€€€€€u€$€€€€]A€-;r€€€L€€€€c€>€€us€mV€iq€_0€€€€Fp6€Kz€€@€R€€€A€€vt€€€€G€g€b€i€€€3€€€Gz€€#€*hcQ€€s€€&Kl€|€€€€8€o
uP!442€€a€}K€.€P€€€U€9€€€pV€€m€<€ €€|€€€8Yi€€€c€€€€Yy€7€€h€\€ €€€€ޱ€ +uiű€#x€€€W€E€€+A]€R€!€ €Ы6€€6€Mچ€@€€€€€(E€€ؓ€€{€2€z€€€/H€D€€A€€_dJ4€€€(€|€h€€`S€{'€{€Hm +^>€€€!"€€€.D€ €€€€€\LV€€'v€k€L€h€z€€€€€€j€ȯ€T#€bi€€€2€jm€l`*|€€U€€€€:|4€n +U6€€€€€n€v€€p€€ʿ€ a3€€3€€M€€€w€/;€/3Ì€€€€ƨ9€€0€€O€S€€`t53€€€€€JY€9/|€€€R€~'€'J:Ȫhb#€c€͸C€€€A +dS€€v?€k€XY€€LQ€€f€D€}€€3Jq€F+s}€€3\€M~<X0€€ӷ@€€€€ €€@€€ݙ€€;F€€K%SY€€DX€€€€O€€€€€€€€;VX`€€€Z€€€ €e€OvB€€|€€€€.€v24€e[€€€€j€t€€q>Ó¨v\€€€{€€€€$A€;€e€€€py€$\€F&€G€e€€nn€jxy€I€€žj;€€€€9Y€ϫgP6'c€€~€€€€@O?€]/ؚ€&RO€€€iܾR€c<rk7&€€€€€€*Õ€€€€j€€G€€€6€€€w€€g€€€Õ€X€€dt€
€€€€€ֺ€:È€€€)€Qv€dy€xn€€€€{臰FxB€n€(,t€€€]r€€m€€1.$€9U€€€€ã²Â€&€€€0€OM€<€€€
€j-*€u€€€€xAk€€€€c€w/€€€€3SĶnz€€i€PU€8<€b€뵫€o€T€€€l€€€€p€€€€€<[[€€€4€_N€€J€i*€€;T€m€€<€€?€€#€€\df€;€€Y€€Kc€€V €€€€€1I?D"€€?€€€€€€2€1(KP~€€€m€w€8M€uk€5€/_€€€€€€Q€a.€€€M€';H€o€€d€.€€Z€ €>€G€€€][d€Ȟ€€€x*€Rk4€2&€꺿ۡ€€€€$€€?€e€€€|1€€漈€€Y€€€€7€y€ҩ€v€Coج€€^ \€€V€e€€p€iD€€€€c€€€C€ԽEa[€J€0
€€€?.M€€Ô1w€tJ€€v€6€€€ε€€€€5€€oh#6LM.€~,Б|H솹Z€Y€€€€^€/.€r{€€a€€€p€€€€SÚ€3€Ň€~€€b€€€bI€€6€U€€Ww*€€€`€€=€€T€€dS8€€€€€a||€€€€@ÕgI€Q€(€€[€WM}v0€€€€€d€O€e€ȵ€O€€€€€€€v€S€€€w|€€7@€U0pÃ¥Fx€/€nvV€ڴ€€j€€T €€x€€G1Ù´`ʱ0z€€ŤLL€€€€C€€€&
i€€€7€€€ €DpR€ߦY|€d€€
€?€€€€€B€€€€~€&€€€€€€€€€€e'€!;€€;€]@€€\€€€€€]€€€€€€€€€€0I4Y + $0€V^€\€€€`€€€€€€Ts€€67€y€bf`T€€€€(€€€Ov€€У€€I5€€€~>€€n€€v€€€€L€2€€jo€€€ €€€€€€€~˨€€€m€$€P{8u|/5?€=`%€€€Ɵ€€?l\n€€zH€)€j€€$@€€€€E&€€\D€€3€€Q +€€€€`€(€/@€ƫ€ L€€3.€€HjG€u08€a€&0€9€€€"€,@€u3-€t€{€D€B€Qe)N8€x€€€€[€€€€€e€€-€L€(d€""S€u}/E1Ե€"F'€n€€2l€€of€;€|3€b€€€€€€؄€€€0Mƅu€E€p€ €԰b€€>@j€l`i€€€€E€zr'€€#R*€2`,Չ€2T€E€€€P€$v€x€D€€g€t:€`€€€Ǩa€K{€B€1.€u€€CK&AB€Jw€_€,€€€€€€3€R€€>€;P
€IȬ€~E›€g€€€K~€z€€R€0€ο€€Ait.€€€a0 €kZ €0q8\Ö Â€p€u€H€5LmWoX‰€ +€P€€€€€Cia€€T€ғjf€
€ô%€p4kCI(B€€cs€€YS€v€͢€€€g$€€€5m€쓓Lvc̾=€,€;€€€€€€m|g1€E€€€>€ €€0€ӵ€€€Ø€€;€€€
?€€y€€NmNg$b扬q.€㉶U€ €Ԕ€€t"p€l€f€c€€€€€W(€Û€€€Z€€9€€€3-€I€€Y€€€~€€€€#P׶!.{€]`iD€X€€ +€r€Jd€kܧSÉ€t€€2€€\€€0vh€A0€17 €Ú~€€€€€[€V€€r€€€D€€a8*€€€h€€An€,ˉt€PG€€x +8ç€[Q#(X€Î
€Au€F:$V7€€O€€/€ȹ€pQQОm€€"€/€Kgbg€Ͳ5€€R!6€€€€€m€€"ұ€S€"€Zyh€€€j€1€€۽€€€€€dxÅ€Y€ @€F€Ѕe
€ +€[h€€{M€€T_v€€P€;C€y0€€€d€€€€v€Ök€€.WÉ—9€we +€״€€€, €^Tzy€]€X€k€%€€B€\I&q€s3v€€
€€ri €€€T#Y€: .€K€q#$q€€€ʓ1V꾆€€€F3M€€.€~€|up€"€€€€€€1i€(mg€€k€€4€j€€}&€\€€€€€€J2€N€€³k€€9€@6ɱ_OnC€€€b*B€lË®&;_sL<* €"€D +4€U€Cϻ€€c3€€7j€€ +€€€*\;4`ÞH€jY€€€sN€€6€ì¿Â€=it,€g€P€€€*b€y€-ž€€ke<€€pUfR)7€€\€xa€€-7€uj:€€+u|€}Q€҂€€€σ€€€x€Y€€f€@Â€Ú g€С€$€€?f€€€!€y€Wk€a€t€c԰€U€.m€€&€m€a&F€'se[€'€€€E|€Du€848€Z+€]hU]€€+Z€:€T (}q€)|5€I@€P€€€*JF€XE€hУ%€€D€€€FxD€€"€€S€~€|€€€€€€€gA€€(,€e€€€è€ǯ)@12€€€€.€Y؄€Xv€M€L€€2ri€€€€€€^€H€,E+€3€ €€€€2<d€Z€݊ɔ€€€€
€0€€€!.r€i"€€€B€3;€r€E€&x€L3sm pRa€@$n€€€).€:€_0x€€dSLp€€T€€€.€FÂ€Ö Â€E€EË‹{Õ™G€S€f€€€€*.Q€€YT',€€€€€u€€M€€Χe€곽€€p€.€qp€€€ +€@x€EZ€r€€€ €-Bp€€;€ß€€M +€p€g€€€\€€0€B€J€€€gW|;€j€c€@€X€€€€€k€;€_€f-o€€€-@C€€mu<€?€ɕ€€HRWnSR|2G€€k€Żn€Ozم€"€€@_6v`_€#Z€€8^€d€€+€€€S€€lw€€€€€b€@9mX٠€€€C;€8 U/€^vng€€O€Z€tff̀G€VG2€€;€$€|W€D~€€€ti€m€?€€V€€€4€€€S€€p€€=cS€>€!Z€i€€€7P€x€,5€€c€`€s€€€9!€,×€+z~€€.€$t€€i €€€Oլ€u-
"!€€w?€J4s>'[K€€€€2€:D^€.€€€€0€€€€w€€{_€€B*€€bлP€s€€€€€€&€€1k8O€€z€€vw€€€€€€C€&€V€'€c€y€€ +Ò€€€€€Y€Tn€QWZ.*i€g*t€€€\hl/€w€€€e T9e€+@€€€T€€€\"€€€€€€€€4€€/{L:QM:V€€€€qi€Y€€€€€/€€6W€€~Q€€€€€'€€غQEj€_€€€€po€ۧj€$m€{€€€T)€€€€€€€€€S€|KM9€͜€€TU€1c65€7€€j€€>€iG€€z€€€€+XK€Q$ +€~*€€%€€€K7Å° €no€'€€€€€wh€FË<€€[€€I€Nip€v['€j€€€yÙ·Ó´S€|&:/€T€/€3€€k€x€}€B5`€€€m4€W€€D€€B€€f€+rK|€€T€^€0€€€€€€€€€G€€€ΕW$H€€€Ҹ€€MA€!fA€€l€SvM€€:€ǿRl€I9 m$€Λx~€€y8d/5€i€€€w€€n€*c€€€2/<YG+€B +€€€"R€€€&€€86b₞€€6€€€€€*Lx€€€€€€€l€€€€€€˷s€€C3&ه€€;€€ k€۹߮€€€€ €ӶO€€€,€€u49€i9€%Ⱥ'Z€€€E€€2€y,€"g€C€€€֮;€/€€€-kk€uБ€9c€MPh€Q:SO~h€€|V€€€€>€YG€Es€}€J"E€+€€€?€€€,h!€€T9€€€€\€€o€|ß“Xm€€€€€€S€o€ئ€3O#%5€€6P€€€i€€€€<,€€€
@€=€€€M€ w1€€€X€c€z{k€€€€€€"€x€*€€g6€€ٮ€€€€€y:€€€H€t€€€Y€>€€*€€€`v€€€€€€#=€Il-€c€€€€€5€$€:€€PzM€r€1€+UD€e€hw€€|n€€q€€fyKAAى€€%€^*€Dmꑞ€€C€κ€z€€8 €€€tPa€ut€€F€A€€>*€€E;€€€b{€€.M€€H€€€€:€[!€€€Eu€МJKN€€€€€S€b9€€€\2H$€9 I€)€€€€FjQBh\€€€K>€\€€4Â€Â€Â€Â€Â€Â€ß Â€Â€%€€Ħ€P€€€_€ӃQ€6€€€€[€€€f€€€€€€a€¯€Y€€€€}€€€€€€~Ë´b€ě€€€€€€€€€E€€J€|]v€,k€>€€V€€?+€€€€€€hY€€€€€{€€r€%g^V)€€€n€€I€€K€€€5€€€€€€€-€€n>€Aϕ€€O#<ZK"!̪Hm€o€O€€€€6€€€Q€"לw€€mr€€€€€
d€€&€m€€>q€9S +"=_€€€?€X#V€ɹ€€€2€€€I5€€ֺ€€ 6€€o!Hjf€€F€€w€_€ŧ|,`€€€UE€€€€&€€€€€€9€€YU€€€€/U€€€€Z€€€€€6}*絴€7xJV€€vU€֧€R€*€€i{€K[5€r(€^€€€[€€€>hI€]€€O<0Y€kf€'5a€F€vY}€€€*E_€€€P€€q3pbX€^/€€€ c€€€+€Xrc€۵-€€:n,€_€€€:"€=E^€=€€c€€€}€1A€€~€€v\7€€€€€€€Bݬ>€V}z€€€}|€J~i֊i<€<€~Gjy3€1Y"€o!€p€?\j€_/6€€€€€€=€€Ly€lz€€2€€6&€˃€@€€LYzy2z€A€BA6€€uE€xg:€€€€D`€€i€< +Z€c1€~€€€ȇ +€€7€"s€hq€z€€bg€ €€v'"̃^€Ԍ€€4H€ &€pzp€€5€(€#QԨK€€€}€HqՂ€€o€\?뵬D€7€
€€w'€o€€€€€€€kV\e€N4€€)€€€€v€€z€a€€|€#€Y€Ðm€zݗ€q9€BJogŀ€9%z€)A€L*€€€c[5}9
t€€Cev€€&€D€<€A€€d€3€#O +\€#8z€€€%€€GY/€€0R€€€ͩ€€ۗ4B3€€€si7€€€4€t{€8€€€4&€=M€;€yA€H€qA€J긕VKqu€€€€U24€€o8ib€€۬€€€%€ +€ +2t3€%€E{€€€S€`V€;K,€9€-€w€€€èœn€€Ò€۸d€€€{*€R>€I&\{€€l€€~€<jE€€€€€/ +~hԎ€€€Ɉ,ѶX;hÖµdJ€€€l€€s)_K€€€€€<€*€€€€g€€ȖI€€8H€€€3j€n/އ€€€€G€a€H€F.,€€€€n€€܄8€܈8z€8€€w€€€€"€a€€€€2C$(€24+e€€xk€`€|1€€( €€€€j]€L6€€€€€l€€€€ +€z€€€€^€Ƹ€€XT€?€€i<P€€€€€S +€€_€)€€€x€€h€O€€!ga`€€l€]€€€Z€R€@cm€Gl€€€€PekO€'€ +€€€€€€È€Ãa€€0€!€s€€€€Ħ#€g€€€€€€6€,€€B5€€PȧC>P|€R
1
€€€Ԛ2€ko]yH~'?€B;€$_m,€€€€]€€G€@€-€S€€g€b=€€4€H+ €1J7€i€i€€€€oS€€4:h-7€b'€€€€€A#€_€€;VÇh€€ T€€i
4€€xɮ€l€H€€U€€Z€€,{€^€K+}ю€€€K€q€€€€€€
€€݀€8 €€xj€Ei€зSV_,V€Je€w&€xj€€Ȁ€€n€€7€Jyr€Z&b€L<€€(€€€€J€€€-€̡Y€} +މ@€€€Us€€€ǎ.€€€€5n/€€€€7€€.q€ËZ€iUE-O€v4a€€€€G€-€ߋc€퀋€€€N€i€:'#€1x€€€K€€€€€€€3^4€7n'€€€|5
t*nZ€€€€€€Mb€ÖÓ¢h€Km#€€€€€*GF€€w€€>€€?Q
€F€S€YCʦ€|€i6€H€9€/€€€t€̓ €€€€€Ui€€(€w€€€€-€€€g€UaT[€€^E醟€r€[HKY}s€R€!`8B\!%€#€€€&0€€T€€€&€Q€€1€€F_€;V€$yzx2€€Eش€-a<"€V€ETa€€>\€€€pm€€\€<G€١€€€€N€€€€€l€lE€SI3€H2'€€€.€WG7€T€\€€Y€€€MOs€&-Oc$Ä¥{$€€. +€]$!€4nw€€€lg€,A`€}€€€€€pV€€€8€€r€€€斖5€€€€@€€€z,BaTit|€€€€'Ϲ€€g€€€€€5D€Pk€€€7lI€€R€t€W<N€€€p€k€Sk€€L€DX:€€€€€€Hq€€3€€X^1'PkR@€€€ +A€€€€€€(€=-€i[€€18€i=%€0€€B€€€€!€[O€/€e€€€€0o€2€€€€€H€X€€$Y€~Yj€=v*€Ǯ€r€rPP€zP€€€€€€€5€€( ^€€C€€-j€€€€L€€€€]€€η\Ô¯[€€=E€ߴ€_.€€€Í€Rs?y€"€J1€€€]>.€€7Y0e€€€̺€€re㕡€€1f€A€N€d4€#€d€!€€C€U.U5€€€I€€€€€u€u€,#€t€€€€€T€J٧€+ €€€€2€lq-€@VF]€€l€€€E4r€5g €~€€s€b€€€€€ +Z.΀€€?€Fp'D€€|€h€{7Â¿Â€Â€Ü Þ«Â€Â€Â€Â€d€€G€€e€H&8€Q€i€€9€V€ +€>€€E€+Ogk€ˎP€P€€Ә€€:€€€+€€mi7€€€€Q€€X$€ +Íš9U€€n€*-€`VA7Av€;Ü©x+€€€€A€€€+€€Uk€<XS4Vj%€€L€>€bC€y€€#V€€3€sÒ½nd€B€~€€JÈ©4€€€z€€7€€€€7Óžn€€ܻY€H€€€s€q€€f>€K€Kf€€rA?€€€z|€.€f€€`€`=€>z2(€€€€€€7€€m€€Ѫ}t€€NO΃€^k2€[y€I€|€€€€€cc€G€E2€€€V_Vy'JA€8€€X€W1€€ݳ€}€O€€DT€€.9y€€V€€€'€.€7H€€͗€€Z€e€€€€!€€€€4
€€€y@€}€6Wm€€€$€1^U€'Ļ.€=T€€€€€<B€€F@€'€[€€€_€jF€$€M€€/€€€*ik€€-l€€€€€€€'€€ɱten€=€€y€ €€€ݎY7€€€ŲR€€€Zq€\~I€}B€հ€r€Z€Aq&€g;Y€'€€€€˥,€€€+€€u5€€/&€QX€#€€I\gi€7\€€€$€€8€Ή8€'>€€€€€€€(g€€€cm€g€€k€
€m2€€€€€}€e[€)€Kzݣ€=p€9
U€Ioc€ȑd8€€€€€f€€€>€€2€E€€€€€€€€,€€{T€}€&o€€€€u/€€%z€}#Kܺ*\€`h/€€ruGϨQ€€€@€ 0%€€VJ€E0€(€€€€€€8s€ laW9$C€ァ€€€.€€C€G€€g€ư€Β€€a=^€>s€=:€zHo^k€9€Q^'y)€€sk€w\ps€€€d€À€€⽎B€€€€&Q€D€/g€[€€€O8€€g€€€:€+
€€€H€w€€:€A€k€6 €`€€€_d2#q€P€goI€>6€€€^€€H'€€€
4€[€N€€AÑM +€€€€€ €€b€8€2ѧA€?€€Ǖ8 +m(€€t€7€E&KTl:Mebvo€€L€€ux€d€€n€€€€€€B€€€4[ޜ€€P€€'€;4@ŮcB€€€€G€07+€w'd€€€€€€€|€-[€€BnLZ€€€
€€€€g€\€,€i€`#Xڋ€b€<É·,*€€%€€]€€kj€€>€&€€€$€€s*c€R€€E€+€€_"€BzF€€pb€%S aʶ7é ¶r€€€.€€€A +€:€€K€1:€€€X+€€:w򀀀h€#t€晋€f€}€€~€׬B€€wJ1€y +€€€€€€€_€€€€=€.Ұ€Ӊ€KÖš~€€€C€Ay€yICQ€€-ت€€{`€€YT=.€€y€:€BdOÓ½V€I€l-P€<€€tk€~€€€€€h€€.Xu<HqJi€d€€€€`€w€A{€€ho?€€'€OË”c9€դ€b€>€€€ €€€€ɚ)pȓ€€"E€P€€€€€_v€3aÅ”9/€D€Há’Œk€<€.1I€E€€λg€€tl_j>€$€ G€~{r€€€|"9€,€€W€€fA€.O€€€€o€×Ԫ)€|€.€
@a€€€G€€pt€;6;€aH€€€Q€͗,€€€p€c€C|L€`€€j4`€€€JY€Q€€€,3€!€kJJ€€€€ €€3n4)€ f'€H€Y€€€N$€€W€r€8hw-€€€€] zdж€€€€H€t€rf€.€2ls€€€}dx€״X€S€€!€/€Ӵ1€€€:q€;€4GXs€€N`€Ȣc€`€u€U€€iA:D€€€€I >7€j€[R€€€€mТW$€ܦFÔ€\ݳ@€6€€*€€$€=l€3€€ N€€$€€6d=y€h ц],€m€4:FL€€€K"?c 1U€€r€z^s`+€&€€€€€bDą€М€€€̒߀€fs€€€d€U€€=€€t$tu€!€€,€/+=6€€€€€M€E €€ €€€(€;€€2€Į+S{€EЌ€€ L€d€€Ë€€€|Y€€€9(€poZ€€Q!€K€€€Fg€€_€"W€€
€N[QV€€#€,€€€€Ke€€€€)=€€Qj€€€€€V€X€[€€€]'€€€€(€߫€i€€€€€€€€EU€Qt€3€€Yen€€€ii€€€[H€€€P€€€€€lNݘ€$€Z€g̶ؘ€T€€w€C€€J€o€Y€€q€0€y(€m€Sܕ€^r€€€€&€€€€i€ €€€€€€€+€€ _€C2wK +F€€PU€c€€RY€€d
1€€€€]€€€'€,€>€€(:6V€{E€€,v€X€€€€€€I€€'HÂ€í©½Â€r€€5c€€Z€ɛ€Vy€?€T€€€,#1€,€7€4€€€€,€€€€€€'€B€€€[€€€€(€€€6€C€€ݘrJ€HX€Iۢ€k€€€€|B€€,€yD€€v€€I6€\9Z€8L€ňS€O€3g€B€_€-E&€f€x€€p
W<ÓcJ<€F`€€@€4€€/;é¬Â€#m+€X5€>
€Xn€€€>x5-1€*€
€gD€€ETAǃ€€€s|€̻€€€˒€€€€€€€sw9€Q€€<T܋€[€-f€Y€€T@€{5l€€-:€uP€Q4h€x%€ڂ€€ V€€€€!€r€3€€X$ €0€!€G€.€I.€€€€€[€&€€€c6€€€ج€€Xi€J€_;s€€Smcޡ€ut"=H€^€=;[€O€€€€€¯)€cÈ0€€€€Gd€€Q|3€€`p€
S€€€ +2.€€:)€2€€F)€L€0€06)€€8€€F€ €</€`k€S€qFwN€\N€€€€"€€€5€€0€7O€€\€€l€k€Y€€Ǭ€1S +€U*€€€dO€v€€€€€€t€}€ܧ5€€€€€€<I€a€* +€€SS€@€€€?K€€€>iH*0(€€€€€€€|€n€沉€€:~Z€m€€_€'€v€€€€'€1€€€€(€€>I€€Q4cuWˇg>€ȟ€c€-€€€€€_€€€€€\w[x€r€€X{u,U€€€€h"€x€;€&GJ€€€€aÊl€€|a€€€€G€€,r€€€a "€f0EÊ•i€)R€F`€j;w€B€5€~€€€_#€>|5€€J€Q"a€€opV +€s('€P€€€€€€€C€e "€^€Q€€€€€€}€€€€w€€€€€a€t€€€,€]€€R€€|u€€9л{*€dj€e€C€Mq€€€€€}€€_OC€€€€L]€€r€y<€€€€€`?€€$€aY€a€Q€€n
€ge€€€€€€~€ѿ€$€€€€€€€t€€€€€-€€]€€= R3€Zg€F€€ԡ€a€€E5€ڷc€€€€€ؒ:€€*€€€EK€$ITH€€€€apv€n €€0Q€€€b€€^€;Ԣ€€€€J€y€&€€>€€)€€U`€€€Vq€>OÎœT€€€i€€ļ€€€kr€~€€€€€€ €€h€€:t-E€€€=€€ +€:z_€9€€€*B€sÍš1a€€€@U€Q81€.€€f[€€.€€€<ǘ€€t€€€€"V5€2Â€ÄšÂ€í¾¬&€R:€U€Þt€}€ke€F'€ @€€€K*€ƃ€€€€€]*€C M)€€;k€6€Ḷ€€€c|€f €€d +K€€ྚ€t€Ԛ€b)€{ͤ{ە€€]9€߻€؅€]q€k*€|ïšÂ€Â€]€Xg~€Բgq€€{O€€€:€۷€€€3%€Ǝ€U€€n€u€€:€W€€< €€D2€€€€1€€€ +c€€€€(5€#+€A^r€€€nı€€=€ė€€miSGT€Vݾ]w€€D_6@Z€€L€"€t€k€€€l1€S€'s€|€€f€€ +]€lc€€f +*€€€H€€€*_]2€€€€i€\J€€6€n€€,{€2^€Fz€€}R€€€gj€C€€_€€5-€€€€€ie_€-I€ٕR@$M\ +€%L€€€ +g&M€€#€€€€6€€b€€d€€%€r4M€€€€€€Hϗ€€Ho€€t €€€/€€=Ƭ€€`=€€€€€2?€€s€Ì€xp€€€OupL€xFf€€€1€€€€I€€€€€€€IJZ€€€€k€Ƒ€€€'€€~w€€b€e€€\€€ig€€€YxL€{€ +€€:€$I€m€€€~€)€U€€=F€€€-€€€€઼€€€E€€€5€j€€]€ޚ€i€€€KA€€^€€€€Y€r€ʖ€9-€j€€€7€v€€€=Kh`€O7!€iR€€€y€€٢€€€93j€€@€a€={€e€n=€}ռ€€€€-&e€€€]'7€f~€a]vlL€1€%€€"Tq0Dڋ€€i€€T6€€yx€H l€€R2e€ą€€€=;VN€€ <€_{€€\3€€€€€e€E€Ϝ€€€€€͎€€€]€v€€ +A v8€€€R0€D€T€_3-€Nl€€r€€€ڣd"€f€~#€]€Ðcq€S€.|Gt€)€€€7€€€og€j&UU€€T€€Y€€+€P€€€€€€€oQ€Ü€€€€€€€€{Ϫ€€.BC€< €h!€$㸀€€}€i€€€€€uz€~€rd_€Jt'€€u€€€€€€`€€€ +€€€€AJ€€Nb€€ًLl/€€z핆€P€€€L5{BBCz<€]€€€2€ Q@€ZRI€sM€€*€€€€€j0€!1€€Lv€%€€V€#3(3\€€€€€b€v€€T€}€€z€€€ݶ€mäS€€€€q€€€J€5€€PS€€)e€(€€5~npY€€€€€€€€Ľ-€/€X€
e€€€+$€€<€3€€bF€ +€d€q€€҄€€€€€O€€€5S€€̞\#€€€€n-e]c€€€€€€€€l€S]€jc€J€WR€]h€€#€Q€€€€f€{€Sz€€5̼Ԭq€€-]X:&zOL€€Vн2€^€8€€
iB€4€€?€€1k€<:€d€€
€€€€7_€€̦€€€€p€Na€€w€X€€iv€ī%€€a5A{;h€3`€%€€[€€A€v#lm|€€€€€5/€]q €€€(_€€€p€h€U€€G€€r€€%P€v€€<€4K€Ѳ€€€€ieᛊ€!€€)€€2€€|5€)?JU€€€i€d€€€€H€€]rO€@€€€J*€u€€D]N€%€€p€O&€0€n}€€€€O8@€€€€€64€&<$€€G€ft€€M€€€G€*Y˰Y€'2€€VsG€€=ne€€M€:He€€T€€€5€4€€K€E€€t €€€O4p~€€€9€€€€<€9;-€€€€'uy m€€€€s€j€*=€&€€€ŗC€+W€€=€€"€x8€€€]7€S€7€L +e€qJpI€]8CtS9Y3€:.€C€€H`e€24b€€x%€0s6€€zH*€€7€M€€E=€ZW,€A€%s5€€m6q€}€g€€:€t€)€€€€€O$€)h€D€)€S€€€a.E2€€€y€€€€Q€d+€d€ۆ<€€€€€y€ €
k 5y€€€€m€#€€€€瑌2€5€%€Jg9€€€\€€€=€Id'€ݛ€€H€]oX6€FYqj^€€{j* SH€e4€€k€ +€4€€€€€€
€€6€Z€jh€(h€€"#C€€€Ë€e€€d€€n€€€€1,€€€f€€d€€Q€l_€-XV0' 7 Ç8€€<M0j€€7€R,€~d€€€d7€TQ€€Ջ€<€d}J!?€i%Y€/ݻ€€€VQ€€r6J€9€€€€€Q€t€o€€զ€€_€€ +[ +€€€^`.€ii€m€€€BPM€€€ €€;€€€f€€€€nA€€€€bL"€€€€€_€<€1€€K€€.`€ €:€€€€" @W€6 €€E€`b~2€`€á±`€€€€€g€€€€€)€m€ϾFÒœ&€€€€sɀ€€˗€
€X€NIi€€}_Wn|€€€€y€ՌjM€€q€6€Gj R€€€JM€{6Â€Â€ÜœÂ€á µÂ€,€)h€€€€Z€}"€€1Rj€€€gr
€]€T€8€e€€€:k€
w€ +€F€d€€€\€ €€€€€:€c€€€€€€J€7S€€€a^x€€€,€R€yϣZ,€€a€0€€€c€j€€€€€5€€€<K€"9(Z€€€H€#€€€€=O€8€=€x€€€€H€z€e€R€€€>X9ڎD€'€#Fo}!€€
transcheck.awkscNT€4E€€€TEXT€€&M€€&Mv€€N€kQ€j€6J€ +€€€€€(€Q€€€€€€!€€am€€€P'_€6€€>€
€€€/]€€€€€3B/€€ +€€C€€ +€€'€€€€€c€?C\;€€€€€?€€X$H€$€^€€€R€€€!_?L^€b€€€Z€T"€€A€€j€€D€0A€ €€€€€€~~€€^_39€€f€6À€ģ€€UKK€Ƅ€
transcheck.listcB€D^FT€€TEXTMPS €m5#€m5#€UͻHQ€zF€P8€€~ +ӑ€€f€€0"€€€g€ʽD,€€=€€ €€€€€^€€€€B€€€€€3€ɉC€€=D€€€x€€
weave.chck.listc€€E€L€€€TEXTMPS €€€€P€€€€Rm%€vbU€D€*I€€6€t€€€€€2€€F:€€L€ €KI€€€€z€€€ v€€o€c€€€T€@€;€€G€€TD)#€€)€€€ʙiD€0&€€b€€GR€€p€€#€4€€YQ*p+€3€ ,€R&Î ,€:€€€"̲2€9€*€€K€€L*Mn€€€vў€L€€€€€I€€I€&€O€L€€L€L€€mN€)€€€9Pm€V€€€Ϯ€@€۳qj€€#(=?€€€€k€€Q€€€(€€€€€€ €LQjV?€hAhpf€NW€x€`€dez€€'€<_€€ʲ3B€€€pr€#€€1rx€z€€ ;€€€€€A?b€€+€€@N€€€F€'.€M€pr€€O€J€€շ€€E€Ԍ`2Hٜ€€€€€9d +€€€y.9|€B€LV$^€k€€1€`€€\€0€F +€€d"D€€&€€€€NO^€駟€€€}.%d1€€CX€->€b€K2€!/5€€ ̊€€€d€€D€N€E€R€8(„€€G€K6€g€€€€€*S€v;օ€+€€€€€ +k€€Z€?z`€F€qg€€Ú€€B€€
€€€n€Ü"€€€€€Vjc€f&4€ȪȽ*€€H)9-€2=€Sɋ€ܛ€€€,xh€t€€€€€€絮€ɻf€€AÃ…G.m€€QD€,€€€€€ €€VHo-€€€€€1€€€€€€
I€€€€BÀh€€A€€5oC&5V€u€iܚ€#r[€€4b€€€ڑ[:OրBO|nR€€€8€6
x€&%%[€€)€c"€5€<Cm,Q€9€M0€€I€:RQN€€€€+88€)iH€€K€y2€Y8&€P€"<€d]€€€\€%ʚ€€XJ€€U€€€€€€€fP1€€ +€;
€ﬤlO€€JÂ€Ó m€€€K€z€€€Q€€€€Ö€XJ€€€€€€€€€€€T€wm€ €€€€0€€€€{€€€;€V€€€N€Y€aj՞€€€$€;€:€€Z€_€<€h€€N70r€׽€€o€€1ß²Ù¹c€€€€€ź€€ +:€€€€Xu€€€€u€e€#q€n€m€U€€z€KM€€€R€€€4€T€7T€€€/&jAu)}c€€€€sN€˲€s€o3€€€|€Q €€€;€0€ٜ+€d€Av €Ў€€7j€€€€€€€g€€cIN€o@O€€G€€€€RS|awz42@,€"!€€k€€z€€€R€€t€€6ٷ€€€€€€€€
€€m€€€€<€€2€`€.€=@€€€2"€€T€€€tt€Z€8€€€€M€QM€V€€€^€ݺ€€€{"€€€€€w_€[]5_€€
€o€$€€€€€€u3€€s€€z€Y€€ԙ€€€€€w€€€c(j€
zg€€϶V€JT+
z€€Q€€€€#€€€R€€€€6€Gu€€€€€ +€~€€?w€׎`V€€c€v€€€€۫&€€y€U€{€P€,#D<7x€?€€€|€€€O7€€€€€ΊȆ'€€€€M)p€€€€"Ǯ€4€?]€€9€€€€€€€€€€BJ>c€X€€7€€€>€€:5V€'1€€Ēe€q€Z€[{kx€€€.€;€#€]z€
+weave.rsrc.listc~€FTN€€€€€€€rsrcRSED€N€€€N€Z€€!€`#D"*z€ȉJ€€ȱ€/Sx€€dÉ„-€€€YW֗€€s€€€x€€(€R?€€€#'È€€rx@€€€x€Bw€€F€€€J€€€C€€€€€rT~€#€€€S€k€ͺ€_€€5at€€6r€€€+W€r€€€~K€+€BmP€YuU€dj!);;€€T€2*€€€3k€€4r€vG€€€ˬ€h€lV€g
k€€€€€q€x1€W€XU5€€€€€€€€̎€€€V€Q;€€€€ʃ€€w€€€€€/€€€)3>€g€€€}L€€€€c€€€€/€?€ɳ€€c€€€€€€ۿ)€c|€€€X&€€€ocS€€€€XJ€?€€c€s€e]€€€€€a€€'7€:€%€KQoC]€z;€r€;P€€`€€&€>€x€€€ €€€P€€bY€€4€€€q€€€€f€y{€€€€€€€)]`a€€€S€€€1€t€€͂€€t€€m€€vZX34€€.€€M€€;€zh€€
weave.webc.listc0L€€€€€TEXTMPS €m5(€m5*€€%€€}D€€€€vbUD€p$€*I€J%&€qV#€€€H€0€€;€€A€7€€€€BI=C€@;€€7€€€€2€Ut€&N€€8€p:€T€€J€€€q&צ€TΔGͤb€2€b€€AE$€€g€e€€€:€€€sQ€€€5P€8͙ +KleN€€€ +€q€€€€5€OuQ€€猤€€cO€Fz€€€lG?€€A€€€e€€€€€t&€X€ $w€€€B
€€ 9b€€f€€S€€€{€YN)y<A€€€€€€^ߧ€€€€f€€€€'€k€€SN€gk€€€3€€€€€A?Z€€€k€w€€€:€€d9€€%€<€A€€€J€A€碴€€^€€€€€€[€ +€€Kp€.'€€cgf)€€€_n€p€€~€
€}× Â€-o€p€€€z€€u; €€QBU'N€€$€€€€A€€_>€Ru/€€$€€z€s}€R/z€9>,€ҹ€€`€€€< B€й€€€€ժ€uO€€Le€€€2K€\€*€€K€€!?H2€€u€E€€-€k€€a€€€/€€€€?€€R1€*€3€f:(€€ҡ^€€o8PI_€aOg€껧€%f€i€€fɲ€|€nl€€€€0z&€@€€9m€=€dM=]S€€e1XS€€K€YRh€q€[€€6€€^C€€€€0/€€[€€/€€€€€#€€€{€€€€W€Ï€o)}€bG€{*€Q€{T€-€€}€€€'€€d_€€(€€V€Z€(Ô©.r€ǾΨ€€>€.ya€€€:€ݡ8€7Ds€€€iL€wN€G€9€€~€4€€€€SF€ۺ€
€€€€m€=ڼ€€€€€€€4€€€€~€s€€€€€N€l€€€KNjt€
€<ZZPC€ˡ +€4€€6€€z€€€€?€€J~€€7€\€€|€€a€€€€]{Q/)r|xy€€€T€€€h
€€1€€%)€ᕷv€?k€l€€ԇX€m€€Bg€€<I€y€€p~€{;€€€€€€#%t ?:€€S€€€€k€Mc€6€€€Z€€€ot:m€€€€Ȳ€|V€R€;u/Q€€€€€€{Q€;€€A؈Ò€€E€-€&&€€€aI€€€€Վe=€H_՗€€??5k€€€be€€€€€vuvÕ¦.€I€€T€€z€€€4€€zyqE€{\€€€R€€?€5€o€€€€€€EXq€O€>€-~OSU€€GU€€€z€€^m€€VF€?2}€..€€€€€`'€3€€~€qf€€€€€€€€€€~hS€€€€9M€]€za€€JÜ»k€€Y\dX€MB!k€Ǜ€€€~€|€€€,€T€€€€€€€€祤,h€€€€€€€a;f€ €€€€\B€>€€?€€}^€€€€€u1€€iP{3K€|5€}€|€n€€€Ew~€€€"K€)€v€€€K\`€N3B€5€€5a€€˄v€€U\€G€€2€M@%€€€d€€€m€<,€€Mi[pQ€D€i€R€O€€€€€€€€€€€€€5On)€€€€41€Y€€3€S€u€<#€t79W€(ß°|Þ½WrB€€€>€@€FP€<;v€€€}€€€<3Lj€€€€€ƛ7€€7€XL€€€€€€€O€€}€td€€X€j€€€€€c€€€€€.F€€ԅs€g€!€€€Q.9tܗ€€€€€€n€Fv€~€M>t€Ւ€€€€€€V +€€a€€D€€j€€€€€݇~TR€€€€ŮL€€V_,€ܥ€o€€€€W€j€€€€€€0q€!€€{€€IÖ³=€4€Hb€€€€nt)€€€€€€€€€€~<O€Ұ€98O~n€]€€€€€qpfî€Â€Â€Â€Â€Â€Æ§Â€Â€}_*€€fا€€€€€€€c€€*€€€€€B@€`x=€€€q/€€>€€€€Li?€m €€DQrN€€Yܢ€€€€€€q0€@}€€€€$4P€€zc€*H€€€€€€€€€ؔ31€o€m€€<€^€XW_€€€k€ €AI?€`€v€€bn+€€7O€B€€Í€p€€
€€€€4€€€zK€D€|€m€€<(1I7€€@€€zgs}ܡ+€Nj€€€p9TN€c€€>€ֳ€€€€€{€€?i€€€€uP'€€6€n€}[€€t€€€€ $€€€€€Sm€;€€Ҩ$€*€€O€S€€€€€€€gR€3€i€€Y€L,Nm€€x,ߕ€€€€€€mQ熙غz€€€G€€=lƇ€€8x<'j€€E@ +€€
€€Rw€€€€€€€€€zN7`.€€׷€6&€$g€€ٿv€€€€€€@€ 1€€€==)€U€€€€€AF`€€[€_€€0€=€€L=b€[€؟€}€l€€ÕsҶ€€~€€:€+䅾€€k,€€€B€€RÞ‘-NJ€q€n
€€€€€€ЦL€€€€7*+ S€)b&€8€€€g€€€x€€€€€€€€€ f€٧€#€9€€€^€2€@€€6€H€ᆺ€€{'€€€?€€D€m€t8$>€޵m€€€g!€7€€€€ +€M€€€Rˉ€6€€N!€€j€€):·€uI€,\€q€€€H€b€€€up€€ in)€D]€€:2~€ě€€#€€€€€-&€€C€€ +C€€€\€€€”)Y€y€€€w=$.€$€€€€€PA€€a€€>€€x&€€z€{ 0€Q€€4
݈&wvm€€qd€Q`€#>6€5C€€€€D€€€€€?€€D€€js€m€€ݸ<€€3
€밫A€€€DY€€€€€n€P6u€j€€t€|€€€€3Y&€I€€0pFU€€Ҍ€/J€@€€@€ir?>pE€ 9€#D€Kh€Gϸ€€€€€x Ij€€QÄ +e€€y€to€!€€[Z€(:9R€
x€h€1P5}Qj€€€fД +G€^€p޳R7€€"J€€Z€€䴅v€JMG}€€€€Wn€€Qblβ€€>€€€]€€Z€:€€VD(€)€€|€€
+€€`€ +^€dԈGh€€l€€ja€}f€1n€€€h"€~€Rxs€;}C€ +e=€|%V3|Eׇ€€F€€q€€€xG€€'€€N€€ؘW€€m€V
€€€K€k#€>xx€€a€€sÏžH€€€€€€€€€€€€€€]€"Æ€€€Gޣ€}!)€€€:€$€4n€۹€/€@y`€$€[€~€,€]t~\0tB€€€:€̀€€
€s€Tu€€€@ 6€€€€0ÙŽ}€" +€o8€A€€=|€€€@Â€Â€È Â€u€€{€€r'€€[O€€/€K€-ɬ€€€"=dA€€€5܈€€}€€€€€€a€€€€€€U€
i{px€0€€e€€€=€
€/\;/ß¹lA€r€ [•€€€.5€z[€}(V€€$Ì€€~€!ᕀ€!(€t!€€€6j€€€y€€€€c€Wc#€€M`€Þ\€X€b€€I!1€€E€ʊC€`€€]i€€y:v€+€n€>o-.€O€鰼€€€Q€€~€0€G€€r€H€€˽7€JD€}€€€W܇€!€;\€mS€€€€Y€RNO€D€s81w€€y€@€€E€<DųN2#€=€€ԇ€E€€€€t€€N€83€€€v€€€€€€S€8€M€B€€€)l€€€(@€4[€a€€P€)€0€€@€€f€p€€€K×·m6€U€=/^ٻ€x€l€ل€€€dtRR€€€HZ(€`€=,€€H.€hf?€(0€€G7H€j€€:€€€t9€啈d€€9>€€)aDV€/!€Dc€€C#€\€€כ€€s?]€€d€€€oæ»–Q€9ϡ€€G€€€€€z€€€v?€€-€€€o +€iV€a€le +€)€`R#€Xo:€ְ]€€€ˢ€€€€€q
€€4€€€Oė€H€V€N€€f5€fۖ2$ue€€€€e€_r"x^j€€I€€€xuRJ€(€a€€€E!€€-€€sq2€?/€w€y}ߧ€€͌* k€€y€p]€>|€j[€@€€€¸€€!0€AÊšg€€5>€x€Ƥ€$€j€<€&€Ku€~vV€x€€€PR€U€€B×p#Ì€€:€FK€€€€RL e€<_€€€|ĵ,-€t€€Iz€€€˄qg€^͵Ha&€D€-D€€%€€ļ€€s(€H€€€€€€€^€€€,€-€$€5g€€f€5d€@V€€€H#DT€awA€;€€x€{€bƇ€]€3Þ‘#€,€\€€^í³¬H€€€€U€€€€D€€B@€<€€€ʊ€V€&!€Gt;€€€%9ky€€€p@€"€hg€`Z*€€€VÖ–>€m€Ep€q€€h€i€H€l€b8.€€k€€€€u€€€>€|€6€€€I€€€R€b$€€€€€;€€€€€r€{€€€2€\R€€€׋b|€€€€€€€-€€ӈ
e€€€k€%w€€R€€€€N<€€1W<H€u€k€a€DrU€8_@€=€€€&€L€}€+€€€̚:,S€€X€€€€ Z€€|_5€'€F%c€€{
Â€â… v.uv€u€x€y$€L€€€ €€€:_€ÆF€€C€MoZ€o€€€€2 6F)jK€€€#€,.Q\<Xf*gy€€€jg€S€€€5€/€7hÉ£vH€(€1€|€€ÐX€FW<Öo€p€€p€`׆€€€€€Y€€l€B*€s!€€n€€€/€€n,Ö±`€€€€+B$€w€€€p 4€€€€€€y€€N€€nꄶ €t€€>€W€€€€€€€薛€)W€€O€_€€€€>€€Z€€ĸ€TJ/€{€€€€€€w 3€*€w €€€J@˳€€€X€€€'޴€€$u(€ȓ?,€:.€K€€K\x =€[€ukb€€p67€€n€€ +_×K*€ox€=€}R€#e€W€€€€FH€€€K€€U€؅€€\€_y€`€€€;€l€IC€€v€€>liHo€€€+€P3gnDK' +€b€B$€€€€.xD€ +D€€F䥯X€€€j3€(€€€€!%C€€fj€I€€€(?*€o€€€€Ԙ€K€€ǂ€€D€T€am€€eE€O8€€/;€2cv€€FP-Y€€'*IXՑ€hÞ€: +y€€Ê٦|H€R€j€€p€€BÒ€€aN4w>C€Si\}^Z柕€^€sn2€€€b(iT€O8€d€€g€$ޞƼ7E€–tM€EUiJ)€"(€$h€€€€(mz€C€€?€@|€i€€€a€Y€€Tv{$u€^€ EY€[PÖ¡o€€#€1_€M€6€i€€€#O€€X€6f}ϧ€€€€€€€€3€g`€€€m€€€€€€€€ €€e€w€gz€€€nd1€6֩€' €€~Ê¥^%[Q;€€€€l1€j€€€hTW€€€€€€竲ѯ€€€€€0y€€LÇ€pk€D'HYR|€y4Q€€ *€l€€€€ܗc€€b
1Q€m€&€€>+Q€€cP +WR€[€€ɹ€B€9€€€j" +V$€€S€ɱ2€Z€d€€{E%€Qa€H€€=€€[9n(P€€€€€€酃=€F€€\€€€ +€w€-{€Y,@vZ]€Ï€€€€€€k'€€€%€E€S˵€€ +OÊ€t€A€50€c鎔qdC;@€€Y€O*K€j€€.Ùª-€x€€ܹ€c€$€G€ +B€€yڀ€€nS)€€$€€K€€/€=€€?I€€€€€/'Y€Ԃ€wʀw€Å3 €€J€~€e7P€2*mk(€}€k€k?€Q€€G2J€€€~t:€€zwH
€€€e€€€A€€€fA€€€S>€%€T[`€€€g€€O€O€)€tf€€Gn€9€€ZÜ€]tYP€أ.€P€€dX€m€€7_-)*o€€=€€€4@Å‹!€€m=kv€-€€€€€€€|DK€4$€€ €€€,€€€€€€s€€€H{€"€q€A€€€€€DP2$€€O€}€,€€€]jjK|j€€€€N€€q
€€Z€S€Q€+9€€F€t€€1,#6€€€;€)6€#€€€€٪d#€€€#PP@oBh€-€€€z€+€+.€vBA€Ͳ€p€({lh^€l€ +€€V€€€€kw€€€€Ÿ€€f€0 €€{€É€G€S?€€€€ONCXw€|ۺ€颯8F€fbH€q€u`€€€K€oK€€€2€€Ûr{MR€/€Y^^J€j€3€€€€€#H8v€,€€€€s€€€f€tb5€€€€i€€€€×z€(!l!\h€€€€i€€b€€jA€€(+€€€a€
€€€"€ר€ k€€€p€€€€€&€3`€9S€€N€€X'€B€€€>V€a€i1tj€€€€j€O̅€D€>+€€€€€~€. +€xKP€€€־.S€€[W€€M€촦yqRw€"
|€;€€~%€€
€€)[€€V€€€"Þ€€ť計€€€€€Y€Eß«gz +€€ã¢D#.€€€DåºÂ€Â€Â€Â€Â€o€L€a€€bjH€€@€[H€Xu9w€€€Di€\7}€€€\c€Pl%€€/€Z€5€€€€^€ri€€€€{€\?€u€Vu€bE€€€5xx}Z€€*€€€€o€L\€׶xo€€€Y€~`€_€p€€€|€€€€€sŽ€Q€n-€€€Teu€€€]VP€y€€€5€€1
J€2€{V€۳€€k€€geW€€€€Sx€L€u€€€€Um€&€_€€€€€€\€€€$€€€€}€×€€i€{€€c€€€€]€€€€€€Y€@€€€_€u1;€€€6€U€€€t€€€€€jV€G//€€NURE€€.€b?o€€)€€€€=€€b=€gȲ€0d€€y€€€€€€€€€€T7€D€€#2€K}€€€F€€d€€XLZL^XB% +y€€%#^9l€XÒ˜X€x€€y(€€`€€€&€ +€L€€€€ Z€€(€`Y€€€n€€€€€>€€d€€<€Ã€€€j€€ €€€;€€_Y€Ӻh€m€U<€'€<€&€€€€<]€€€ €W€€€_y€O€€€w€?€'_€€€f€€Mj€_€€ã€€_€€€A]€€€T€_€€[xFxVk^€k.€S€e€€€+D€Я~€W8€b/€ٜ€(€/Ùš €€€€ӊo€€<€€€sH+€€€€]n€€R€<€€€€j€€xÚ R)y€F$\€^o€€؈€€x€€€o^€WS
€{k€Û€€€€M€€€€€€+€€€ +€Ç€no€€€!X€*€€9€vD&€/i€N€€€€€ZQ€A€€€€€€€c).:L= €?36€€?€۳J4€LJ2E€€€€€€€pí·¢>ڊ€_۫€H€€€v'€€€€ €4ף€!-€€ٖmHС2j?€€`×€€{;Æ€)E€€X#e €€h@€C€€€{[j €€€€€6 É€€s€€€€B€€"€,€€"r€€€^€֦€€)-€€0L
!€|1€(€g€€€€I€€L`{€€€} €p3€€cØ Â€5€F[€|€0P€€M€ +4€қ€€+:€€3d1€€€€€I&{€€u€Tm[€€€G7€bK€N€€n€}Ŏ€vk€ތe€J€€€€€r€*+ (7€&AG}n€5Ä’Z^€*€€K€€€Ќ€Cg€˳€€<€"€)xx€w7€€€€€€€€€€€€€€@€€'>l€€€1R€€!I€Û`€€OBUz€98€€=€{€'P€€o€ +h€eu€¦K€€€€0aP€€€]v/)Sh€€€K€Yk-r€€u€€&€€ʶu€g€bq€€1X€€?€€€€€€€(s€€/€€eb€R€)€€€шJq7|R€s1€ f€ +Ö*y€€A;5€€Оu€€€€€€QV€/€€o€Hl>E2&€r€0h€B7€O€QE€€ICF€€€€/€^€€€€V%€X8€€€€E€€DGUٜ€€\\j€€3€o €L€€e€v +€D€€€;j€~€€6€€€q€€oaC€$€fF€W*€€,4X]€€€J€>€և€€F €€nVm€NH[Tv€€€Ucv!€ +€€€m€l€ViX€)€'€€€€€i€K€0€€€€€€Y €€8#s\€P€$€€€€€LX +_d€r€€€€€€€€€Gۘ€€l0X€J€>€5€">Sk€€€€CJ€'Ɣ€€P€€€€€€.€€G€€JJ.€€€N€6€€€pٗ€W€˜€€€&€H~€€€ra€€€€€€{€a€-€€G€v€€€€€|€,h€€€€0;€hl€€(€Z?€€€V€€€I€€€3€€FW€€+€
€U€€€€mÈ‹hۋЗ€s€€€€Ѵ€€W€€y€vy<€i€€€ME€€}€€€5€€€f€i€2€Lr;€Khˊ€€€€€o€zc€q!g€€€€€/;^€1u]1€qc€€€W&€%€€€'€ 2[€͟€€€!€;OUvy&€€€U<€:€€€1€%€G€€~h€€€€€&;€€)€€4l/€L€T€€#^€€€?€€y!pt=(0€r'}'€ë“€嬜€Mk
#$€{FY[=S€O€eA@~€€ ed€=v€€€
?\["?+€€mZ_t€ +€€>€ؕ€i"€€P€xG€f€€€€€`€€fw€Q4€€7€(€€€€€@€€€i€€
€€€€€O€;€€i&€9` +<ãœ8_€l;€€1&]}€m€€€€€€M€€dX€€V€✛€Mb€€€%O€2.€
[O€€Ė€fg€ߌ4€€€׵€@€€€€€L'€:'q€€€`€€€ljC€€L€€Ž7^܄€€ݲ€oÖ¦k€)€€€€€BYa(;KK€€€X}€~T€9T9€€d€6€€€€€DH€mzÌ‚x€€/€€€.€€€=b€€€€€B{€€€,&̳€ €€̰€6H€€€m€,@Fa€bH€€4€€€'€x€€Bd€|€€ €€€€€€€+€F8€m*nضl€0€%;€TWA€€n€€R0^€€€G€€P!€€€J_€€€€y€€€€J€€HF€˫€zI€6€34b€€a€€4€Q8qZ€€€I€€KK€W€€€]€.€€K€€q€€€€~€€€€€%ϱ€€€€€E€€€€V€Ë€€€€J|€xX€€:€€C€€gΔC€#€Q€€7€M,=8M§€L€F +€€k€e€€3g€€P€MW€з f€m€'bV€€€C€%€€a΂b@€qL$€M€vN<€"€€<€€R€v€€k€Gu^€€€B€€€W/€€€=€€€€€gÏHd€€€€€b€QK€€€€€€M€3W€€€Sj€€!€;€€4-n€z€6€u<€)€'z€€€€€€V€€€=€o[€=€€i€€€€€|€xÍ”V +€5X€H:G€Yv€€zZP€&c[€€€m
y€U€Ұ'€=Qė=€]{€5d]Wxީ€€€|€isN€
€ +7b€€€B€€€T€&€€(1e€d€v~1€€€€€5€€{€€€E€€€z€€€€€€l€€€G€ ~T€"ka€a€@Xn€@F€B1€:3€€€€€€€l0€q€-"N€€r<€€€=€€€Dde€S&€€€h€b€€>D€ń€€€²:q€€UB&Q€€L:€7`:Z.€€€€€d€€€€€I€DŽ€"€Dow@€€6€ot{€>]jg€&c0€€€e€€=€€€€;m€9€€0vG€ +€6.RԦU€€#€ v€V €€g+s€h€%€€€€/€€j}>€€.o€€[E@€m€€€€(€€€tz€'€`€ +[ 7i€€€€]€€€€€K|€€€€€ɾ€u`€[€3€€ٹIY€€€j€€i€€€€w;€dx€f€€_WWg€9€€T=k€ۄ€€€rj€N€YY
€b[CI€€€!r€3€€]K€q€OПo€9€댹€€€€€€€€€=u(€vÈ€'€€*N€€/€?€T€€€n2€h{€9€€,[€€%p*z9s m_ÔRID0h€€€€€€€ +€ܽ€W*€g3€€htvw€€€\\€M€6~.€>€y€u[€s` €€€D€€3;€c1€€€׶€=o€:۩K +Y/@>€u€€€j%€€t€M€€s€^\€]€>€d 7€}NdkE4pFxV€\EtIwQhT=€€€<€€B€€€j'~C€Cr,@€w€i€€€€€nt€خ€tPŹ€€€?F€€€T€€€€€R€€Y€€B€€ €/}H€ +€׃U€*Cծ€/U€H€€€A€€€€*U€T€€€€KU`€I t€6€€€;+U€€€€€€_\JA€AIVDd€,€M€\€ܷ€٨€4€€€€%Fd€V€l€J€FT€Yۚͩ€֕X.€€€€J€E*€&r€U€€€€\€I€qr&);€€)\€€ܘ#€€€M€=€€€i€€€g€€€€y€€%m€N€1J?v€€֑€$€€€€€c€t€€€€€€€€왕6€€)H€€€€€~B)€€ЦμC€B€Ví£«Â€Â€Â€Â€Â€j€€XeeC0l€:€w€€€€`€€€F
€d€€j€H€c€en70€Ϩ€€€€€N8€OË– €€€mf€€€€ɡ€m€€ € +€#6€H€<€€WA8€8€€€`€€V€iH€€8V€€€A€€cM-€€€$€€VÄ€€ €h€Z€€ӴsR<;€O€€€1€€€Y€`Ø›1}€€[$€€ڔ鸸€쬪vÙª]€€€€€€5€M€
€?+€€R'€O.€€€€€€A€€€€HT€2l8t(€€€€{€w?&€€€€垨P€@€€[]€q€;#v€c€ų|€3)1Pm€G€€€cmïȉj€&€d0%
€{o׶S€Tvܣ8 +sX€€<€|.€Պ€€€€€€€V€m
€%€€cX€€ҫ<€€Z6|€ҽڒ€9€P€€€€€€€*2 S؄:l€€
€€€€v€p'+ +I€€Z€€p€€[€֞_€€/€€H€6€€}€x6€۵€O%˶T€€€\€ӆ€1€€-Ж€€ZR€€€€}VP€€€€3€ +K€ B2€i€JC€€H€€€€"p€
€€vm€N13h)€ V€€Q/0 yf"€)>€=€€[€4€€Y€NݙI-:€PhK*€p€€L2€€a€g€€€ €€€€H€€;€ޡ€€.€€3€€xu€€€€ײw}b€€j€N;€SpΤ€€EO€uc€x€u6@ +At-EwX€€€t€$ۥ€&>€€,€€€€
m€R1€n€ް84€€'€€€€€€"€db€ +€€ҸĴ€+€€z€L€ €€[€€[€€F€]+€€€[€k€FhE€€W€€.S€€ѨF€€.€P€@5cn€x1W€/7K`€€J€Y€€€€$€€YD"Sx€€€tI€€€€] €€J€€€€c€€h€hR€€<6 N€PA€î¯Â€Â€Â€{€€€->€€€_#€€r€€€Ä€€up€.€€Af€€2{€)€nd€€{€3>€{}€€€€€L€y€٬€€€A€€€€€Þ€€r€^€p p€€,€€_>|r€€ry€€r(€€N€⡕€€:€S* €x*n€€€x8ϯd€€€KD€€€€€3€€yJ€RW€€%€€"Q!€tc€€€€}q'€€yp€B</€€si€z€ €€U€H€5€z€w€€B€G)F€h€€€€€C€a* L€;ÖŽYL€)€€€-)€7€?€€_€d_€n.€€ڀ%€Ok€€l€@\€€jr€€€U€_€€#R€€Q€SԜՀ€€€€€€€|C€"€€/00,s€_€€¥X'€€€]€€7€]?T€€€€€€!t€€€€€U€€ +€)€€€/omZ֣€7€2€ €fJL€sd€€<€^€€€7ExJ€E€%U'G€€€€M€€€ζ€d€m€2€€[`€bז€€oa1`:€d`€46€Kd€O€[€\r€€/A€€€M€€h€€€€€U€€P€~z€B€rl€€u€€>€€€€€B";R€9€Wk€€€€€b[€€€€e€€€€e€€+r€€r<€{€€C鹟n€€cm€€!€SA`€7€€I€C€/€€€kx€Zt€^€€€€_€€€€׃=€s€L`€- u6` €ۣB+€e&€pH€€h6[G€WA^
G€Ê€ބ)j€€vr3U€B!P€D€€€>"J"€f€KEQPLb€€Y€0€ˢ€€Xь€ +Q€€[u€€€€t€€€nX\€W;€ONOqa€€V€€€€€€€h€3XI€€U€D€€€€€€€2€€€€€€€€_€€Iҳ€€€+€)€€€]€s€
߀€(€€€€€€€€X3€€_Q€>€{ệ]€€€€€€֪D€€€€€€€€€x€R-€x€k?€€Ue€I8~m€€€!€€QL9ǥ€Ö€[p€€€€G~# €€€€€€t
€o€€S€&7=€ƅ!wD€€)(€hsr€€€r€€uk€[€€€€E-€6I€€€a€%€€€YI€$€€€N€S€€€Ζ€pGP€唼€€a€€€2€€U€|€ +;%:€€€€€O@Io€€€/dG'€€€et€ߪ€y6€KF€€€€7€''Ý€t€€Ȫ€q€€E€€)R€€i€!€€µxR€D€Ҧ€}9€4g€#Ç©*€€qEy€i`SVe€€€€€€QHL=€€'€aOOR€€€#€P€€]i€€st.€€€€@€€l3x€€C{€h€bV€€€`€Y€]&€€aah5{€AGz€€RAð€€+€K{€€Γ€M€
N€_€)€=€j€h€B€€?€€V?€€€€a€th9€H€€Ci€V€ld€7€@*€€o۽€OpJ*€)€w€€€€;€€€€g€n€€€KJT?uQ%)€ (}€€g€k€€€€Iw&€0%€B€€a€E€€O€s€mw:€:€€"€€+€،€۲edb3İ€€u€€€R€y€€€€z€Q@€`€€€t8€€j€€€y€€
Y€€€n€;€'€€€û€€g€€F€€ePB/f€€i@:€€y$€Ω€€>@Â€Â€É Â€Â€.U€€€€x€b€€U€€€€€|€TDd_€€€OiI€0€€€€€€sM€;…€€(5€C€€V€€#€0€Q€€/i€€/€o€a€€€€*€'€€g;6€€6?uN2€,€€q€€>8 €€" €€_^€ €`Ǔ€€x€c€۾€Z3€-J€ €*€Bm€c€€Rp€€n€7€w€€
HwX"€FFF€e€<€€F€€€h€T€p€8€S€w€€€€ٮg€l7€€€s€3€U€^€€€€€/R€ٹO€€#€€€J!€t€€.>˹р +w,€€h€-€LQ€<Z1€€< Uf€U€ €€G]n€qz€.]5_}DK€€~4€€€x€'€|€u߱6€€]€_jg
[€8G€€€€€6€o()€€€/*,_
€T€€Yu_€€ʃr€c€€€€A3|Rp^H)€&€€n€BFހ€€€M€€j€€*€>€€X€€€€Ϯ€t€€"K€DqYG€eǩ_€€€€D€€(€€€V'ߘ͙€l€€O€e€9"3€€€~€€€€€
€裰€0€€€*€€h€€L€€€V€Fq€vÏ‘f€"€€MטZ€~€€€E€€v€%€€=(3B?2€€€€€€€#"|€€€+€€х€=€'Ac€€rf€v€âœ[2N€.|R;€€۞4?Ôy S€榎€€-}€!&€€x€€ے㇪€€€€S€€€€ʙ€€&0L€h€)€G€VO"a|=?€€€7€€ϵP€:~y|€49€X€ +\€0€@hm^€€€$€A€3m€€€€w€3€€€€€€
_(€€"€€€,bV€€OΧ€O=[y€€€€€Q€€€€€€€€€W/€~K€€/vP€D:#€'-€€€€€NDQ€€€)€gt€€Ĵ-%tn_€€p€rvCu€·"?61€y8)z€T€K€Ë€€ڶ)€$,€€\-€ €€M€kbc€€^@€\3Û€€=€€/m€ߟ8€€> ËG€€€€"o€m'?€u€,QRl#€bD€d€€^€€€}€9+U€Z€lVD*S)€jN€€|€c€q€$E€-[€€욞€'€€€P=€€^z€@"q s€€æ_‰Ö€3~k€5€(€€€€€€Y€€I-z€m-€ə€{€q0€€c~8BXl€€€€9€€o,€€€a€€_5€ +5^€€T%€€'Ô—j€rk€L€€f{x€X€€-€€€€]n'€€w€ 27bK€€€%€€1ë$€€€€s€€€€€N6€ٔR€€€€€)€€A€ €R€€4€€3€€Ѷ +€€€m€J€€€ơ€~€Z︴p€€-z ) K€€€€n#ٛ€1E€€N€€€€t€6€nD€p€uÄ…"~L€ €s4€€€y€" +€[€€G€'€€o€€[z€€€€€€€€€l7€;€€\@€h}<€'n€€€$/€
€]€€+€€m€\€€€Uf€€L€|€€€€#€e€€S€K€a€-€S€\€T>l0€€€€W€€€€;D€d €a€€E€€F€L€b€'€€€UZ&uXfV€€4la%€%%:€€€€€€€€:#'€P€€]€ €€€€+Vr +ͳ€€ + T€@+€(($€$Ոr|T@'€U€I€_€€,M€2€27€€€b€€€Rk€€€B€A€€n€€€€€?€X3€v€€4n€1€FD€A€L€€r€€€q€€€€V|€8€€~
V€3€@€€|€€€TB€`>€€ +8€€2Jޓ܀€€r€4€C€€€2Cv€€+R€G€=€-€/ZPhX€`4h$M€€€i!€€€Q4€€R;€€€#Ì€€€|f%€V{€#<á‘©/*€G€€v€€€U€J€€Ħ€0€Y€€€€"€>€€Äf<g€€€€€Al€\€1?€i€€€DT€€€ѡ€she€1(€2€/€€€€i!€€€€a€€6€=̖€€ +€€€8€
€€€€,Q(}bh€m€€€€€Duc€JV€€c<€^d€€6€€€q€€€€ €թKRN_€€h -[0p€J€€€€0€E`^)€€€€ӆ)X!
€€Er^€e B€€€€€€r€€V€€@ +t|€;[€€S €/A€€ €A€i€C€€a2€€8X€@€€€EV€€[€U€€ʤD€€€€D€&€71€€M-€€€IJՎ€g€آI€q€=€H€€Ҏ€zN€€p€€c€€€€€ܩo€€d5:\€ €€3ǀqA€Ebu€€€>k"6"Z€€>wq&H€ Q€€€€f~€GA€d€€€€€u€ʟR€w d€€%€€N€€€€€#/€g"€3€!€iՅ€ke€O"€He'€€1€€€€'@€€€€f$€RɜmU€[€€S€K€M€{q€€€d€=€{€5"€OG]€€߃Cc€€)B€m]€€€D€d€€€C¿€_Q3phs5€j€0a€XC€R€€Q€€€n€s+€9€2€€CdklJ€€?€G€<€€€
€oÍ“Qێ€@€€Ü€€€€,j€R€€2€€
.C€€€€€?€€€€q8
0€tS€ €€€^€e€€O€R'€Ǝ€€€]`€€.€€í‰G߃€3€€A€€+WB}e8d.&s€€L6€%€€2€€@€€€ZF€€€€g€ )0€€L
|€€6€/€/€€€*€€tpC"€€€՟€Y€E€ €m€ €€€€€€Α€L$€€(€n€>ML€>h€d€€#€*$fI[<#€`a€2r€?€P}E/a€€3€\2€-ـ }€€bI€̀h€€ŋ6€€€€€!€I6€€ !€€SIFde€m7N€s/€pפ€4€€ +d€7€€+€00a1€€K€€?f.EY}€€€€*€"~€,S€޹,c`/K%}€€€k<L€€€€X^€€€€Ӭy€5Y€€7€€€€DP€)6€Y€ίTi€€€€€€Ե€€E€€€€€€iR€ RBE€2€€p€-€€€€]€1FhT€€|8j]€?€WUK€€1GG€€Gk€H€€€V€}€€€e€8€€U€€a€7€Qg€$€sJ€€1 +€,߀(€3€€€hB€€€+€€*€€5Gh€ €c€;€€}"*f€9€€ €€€€€
"О<€W€€€c€6€p€^NgT,"lY€€U€€€€€€€€€L€€N€€*.€yN*€€€€€Ğ&0ۀrֱMiN€€ :b;€$€d€€€1€kv
€€€1Ua9€€€n€€R€^€Us€[K)ឳ€Y€€€ T€L;€Lg€p€€N€ƌ +€BAH +€q€€€€€€Í€&T€€€ºz€%:€€€TFlj€€€ ̬g€€7€€€z€0C€C€`€~r€N€:€թK€v€F€~€€€€€\€€'r€€Z€€€Ggx-'€DPvsG€F€€€hf€cl€1£€a;€€rcl%€hM€€€3kTr€U€I€S€€€_€5k,€ +8WD€Ь€€€€
64€g&h€€1€2€€€€
$€t€c3€€%€(€€EI,€A€€€€€s€€ +€Bb€€VC\€€€€dq1€€ȉ4J€9ׅ0€€€
,€€€MÈ©P"€٪%0€€€86€}€€gu:€O€€P€c|1&zq€|€D€€@€€€@.=B€€€ëºÂ€Â€M怀€€( €€ý€€+V8;~}D?>nRxɘ€€€€€€@3€Y€€€€€]€r,€€€k
€{€€L%€€f~R€ +€h*3€€€€Ä€WXus€c€€g €€V€tHއ€h€€€€ޑ€ŻH€!U€€€(7€€Ú€t€L)#€m€ۛC€€)2€~€Fs€J[n€ÇOݩ€?€€€€€p€}€Өz€6W€BE€Uf,€V€€€€; €uf€>b€ݾ€[F€€€€€€8€€€*€qo&G€€€R|rkF€€A€HX€€#€€€mu€ʀZ€U€d@€ũ€8€€€7€cJ€€i>F€€sd€€€;€€ydo€€q€€€G)€ر{ €€:0€ؼbmU{€d/u€ +€~€=c€;€J€€XRR€Kh€ %€€€7v;0,€€}€)€€†JRS€€Y€C€И|tDDT+€Ty€$€
€(€€3€[€>8r€MY€ҕG$€f€€9€'gI2€€!€m MyX&€?€98€Y€K#€€€€}|lh€x€y€€€€€€€€#€ I€€€=€€`O=b€i€5a€SeEA€€@g€€+N,€€bg€€~€Ma€v@K€€ {V4€=}€eÂ€Â€í·¸ÖŒÂ€Â€Â€Â€E€€€5i?nf€4€/IUN ]€€€€^&€€€,€P€֞ +€Yf€R 3i5(€h€4€€€€€€g€€2-€]m€€B€`€€€€9€G1€ʲïµÂ€Â€}C€€€9€€€j€(€\€€"2[€;€€O.€€e€€ᛡ€€€€€aE€LL€.9€ +€,€*V€Z€€!€€̔ʄEr+€€€QO€€€w)e,€/€̆,€€p€:€'2€r~€€Z€IG<€€€€€€& +u*€4K€jdw€€R€i€0#€gȄ€'€€S€€چɴ€@-:€6z€a€ƺ€€ €rÞM6€€€€€/R€€€€€k€€Ý€ +€p€€WBo€}€€~€*€€A€B€€9{uS}ăq€€€€€, €a€Y%€h€w€̽€ 2Y<€]x€€€€€€^€€x€<{€€K€€€€V€€
€€€€€€6{€€V€€Æ€Q4€€,€€€ +};€-:€€jÄ‘\5€€€Ú€Ý€PCc€CVW1€y€€:l€€€€€€V➚€@@€€€€€~I€{€Ջ€€€€€€€€€€€M€x€SJ€2‡€€€€ +#:€€€F€€€zQl€P€c€€F5,U€€ €F€Z€"|€€€G#w-€€k3{cy€9|€€€€*\h؇€*h[@€€€-€€€€!€€jl^€€€5€,]€€€w_l€€€€€VI€€0€XR꧀D€€€0,l{€]€Ư€UNd3€5€€€€ѻ€fL"€€W€€|w}mI€'mhE€7z€€€t=€€€D6!€tq.€
€U4€_€€MN€eDc€ +a¡[]G€€y +€f€0m€r}€ƛ€A€€€4ii_€€€€_n€€T€nvM€i€€7€€ €Y€€#C'€€R,5€€i .€€ €!€€r€€!€ెĂ2€€€€€m:€6€€€B€€e26€€9€€€€R€€x€x€}_€#ϰ€€ d€J€X€€Z€hY €€€#&L/€S€j7€€€€€j=6€€}$€"€€m6€€€{€€&,.€€€€h/.^*€€€j€€€€€Պ€€cKr=5€Ƃ€€€x€€€€jq€€€€
/Fm€€€E}U€*€x€T€€€€€cTms€3I€€C€'~C€€
"€.€*€€x€€D&€€J€€€€€bV7G€€{€~*€c5€€CІ€€€2:<€0Nሶ"€€؉€€Z€y)€3v`€€€B€T€W €{€8€ޗ€[€S€8Q€N€-*€€€|Ȁ€€IC€cdC^€€€a€Y€>€,€>?€€€€€€<$N"iх€P€€F{=nÜ€8A€€_€A€€j9/ +€€)V€-€V€€%İ€t^€m䧺€ְ€ن€€6Q€€€a€n€㖺€€3€Bw€Ng€€z+€€|^€D€(€w€ڃV€€.€J€€*.€€€€q€€€
€`l
?€~€T€€€€€̜€€€€r"}?(l€€€^€€}€ZhXF1M€€€€€[€€€8t€RX)€G@€€@€€€m +€€]€€V€€'€r€}€8jQ"€€ކ}€€€€€€€€€€F7€g<%_€kn€€€ W?€^dN€X|€€B]€€?~Ptê¢Â€%ȳƞf€€€=;}€€<è¢Â€Â€@I'€"€Eqw€e8€Sv€L€€T0zz€€€€€+€Y5H€€ժbK€€x,€€ׯD€QÞ 2ÞŒ9Z€€gØ€€€€wS€[s^0qq€€C€€€€€€i€€G7€S€Ã€V€€€€-u€€գ€€~€JlV€2€€€f€€€Evő€€sG%€€e€€c€€{€€€€€jÄ€T-x65€€€C€€0€€r)€€€€€3g€+€€-€s€€b(€#€Q€|€€ZEqÜ€(€z€f75O€GOx̀€€€:5€€<€1kj€€€€LA.(€>€€€x-€€y€7€€€B€Y5€<[J€F€e€6'TÔ’mI[€€€€0)€^€r€l€*€a€൪O€6€€ME€€€€?€Z<€I.€€€€=Ô€€|€€4€q€€^€[€€€]€n2€Z€y€€€€]€}|ï®9€€€€€€U€PHØ€zÝœ7:€.€€vp@Ì™YKX$ї€$€€v€€ZIN€€Y€!s€€c€€M€€ٿ€€=€#€€€€q?P€JpABL€K€.س€€itx€€€€I€r`r(z6€€o€@€€b€€€@€l +>>&:8€€Ԧ€€€9Fe€!€€€U€x€€ƻh€€€€&€€mE€G€I€€€.K6D3€€€€€}+€€)b c€|€€€Lӈ€ȇ€.€X€y`B˶€),,l9€Z'@€€€€€w€€|е€T€BaGra?Jsr€3€€€€€=#
€€±<€€€y"€€€M€€E€€€&J€€ U€S€ngH€*€hd€Y€€f€€DŽ€€i€€€€€&o3€€+€Am€h€€€Ԃ€|G27€€€K€/€€x€3€Eb€-€€c€€€,€€€_l{䨄:o]A&g€I€nVw€€Zk1€2€€;H€€!€p€€!y€€ €€€€€.€€
€K€TŞ€2€€€€€€€€H:€€€b€€€L€1€€€€€>_€6€€€€€€€€[雅€}Gæ €€€€m€:€€%€€5€ €[T}€>€$€€vR€n€]<Tb}€€€3"€8y|€€€€c€7N€€€€K€€6⸣€bCY€€€Zn&€€»€MC  €q€€€y
€g)w€Y€.€$7~€€w2€C€<Hۦ€€€mYo€€X€LB€€)€€€a +€ €y6€€€€€:FB€€}€€€>€€63c}€a€t€1€€&jD€8ɻ€€h!9%€€€€€^-)b€%€ +9_bh€€u€-€€ +D€€€QFj>kI€@A€€E€€€[€=€]€C€\€€€R€€S1€€€€+E€€€€€€€),Ф€€TGadÑ€€rv€Xw€]O€9q€ +€+{€€`"€G€Þ€€%€€€€€€€€J€3k€6€€4<€€p€€x€sh €lz€fJvNS€€€€€€€€€{Ò…a€_€J/xG€`y€lw€€su׮€€€€$€e€€€d +€j€Ο~€z€€Ԫ€vV€€€€€E<E€€EH€E€€RHC€€!1l€H€w€X€փ€,€€€uKK€0€i€/:€_4€P€€$€+€€C€N€E€€€€j€€E^€€ "€€€€Ƒ€€€€3€dÂ€Â€Â€Ø d€N€wT€W_ÕO€€;€€€Bd0{€h€è¦Â€Â€6€&€+G+t€@€€60Ȏ€L9€€z]€€?2"€Q€€ק€^[q€蟎€x€€€vϘS€€{T$€€:€€€€r(€x9€ԡ€`€€€€uá‹¿U4F€j€iYIgi_€\ï¢*€(€hAB(X€T*V€€€€€€#y €€€€€ic€€F?w€ڟ€€m€€Z€[€€€€€€2€€€r€€€€g€q€€€€'€PT€€I€R€€*dw(^€ZAIx€€f€v6Y(AQ€BJ¶%€v€[w€>€oc€1DZ€€EB€€~€۷€Us€€€€_€€]H€E€€€€€€€€€.€ѱmHk€€7€t.€€EG€€P€8^€# AyG€0Y€€€€g#€m€€€\€V€€Z€C€dk€tg€€€€+€a€
€€€€*3)€$€€Rh€€w€€u_€;€€€€v€,€I€€w€€€]€h€€)€€W\€!D€2{?€x€€€€€€€€|"€f&€ÎX€t€€€€,€ؼ€€€€ƈB€€:i,€€_^€yߩ€{€€€€€€|€€F€Uγ5€€ݺ€€€>€€=€€A 2€€€€€H>WC€jX€Pc€€p€E;€lY€J€s€D2€,€^€€dOk[€V€MoÂ€í¦¿Â€Â€Â€Ã“Â€jU€€oS^€€C€€R€+€)n€€€€R€Z€xq\€:€V€N€z8€€€_€€€€€_W€ou€€€€€>€ZÏ‹MÊ©VN€€€ʩ*1fh[<]BB/€€1b
€€E€€$€G€€€€5€€d€-U€€(q€b€[Ql€"-1 +Aj€e? ;€'h€€€'€€€€8€€\C€{p€€KdaW€8$Z€Қ1Â€Â€Â€Ä Â€Â€H€€€€#F€€€r€€{X€Mο€€€€€€€ È€'€5 €€,€&€€€€€:€w<|+t€€€@xf5€iȦ€EG€`'/0€€u€€€€€!€€€€€€€€D€€ӂ€€€€€ͥ +-j€3€`B€C€€€€63Nݗ€€€€€Bc€A€€`€€-8\|€:k€€Z€€s€€i€ܼ&€€k-€z>#/€€(dil X€BZ€p€€r`€E*€€!gb€€€S€ +€˓€2H€^,€€€H€€Y€}:€e€€"€€!
€%€@?€€ 6€€X€N8LF\€€}€€€t:)€€€s€DT]T€€€€)Ô“y€€V€#Y€€€€G€€€醻`€€€€Gq4€€€€l:(€0*€€z"€ÍD€^€k-6€)€]_€xr€*}k'€€€t€jw€€4€=€€+€€|€p15O€§€ݼ€EX€=€b€`€l€€€€ouÂŽFx€€€)€€@€€t€€€ۼV6€€O€a€̲M1*6^H€ MÈœK€€բ?€q5€€€€zU€€€€€4€igx[€€Is€€G389€€8€+(€AM€5!2Eǰ€Sñ€QR€€!|€$ѕ€m€N€€:€€€€€€€H€U€}\€}~V€:€
n€€6%€€@€€Ui4žHQ€ €MJg€€€€6€@€€€€^€€€t+€BF€€€€€F^€6@€€€€s€K€"7€XP[ۀ€vG€€€b€€4€€@€Z€€€€€!Ë o€€€X(Ø;€x€€`Q€Af4€B€€é±Â€ß‘4MD€ Ö¬,r€ €V€${€=€€€l5
€#P'€}€ [€€_€E}>€€&H€€E€€f€3€z€€\€€Eܣ€~1ӄ€X-B€€:2€Z0=€€=_€bO€€)€€€X(€€€>ۀ„€€€€€~€€Wͯ €A€€€€}€0€"€N€tt\€9€€"€ +* +€pO€]h-6H€€/€€€€rs€1|~€*€RY€b]€;U€€€€e€\e€€߸)€ €k€ ޮ€€&€V€u/€qN€€-R<*€VX€U>[C€`0kv€O€€Ù[€TD€€<€€€€E€cب"&l df5€€€€€?)€€€p qZ€}Q€€€b€#€€M€;€€h$€€€€€€RXs,U€€>$>€€yd€/m~5€€kk
€€€€wc€y/€€J87(!€$tx€€€8€€w€AtԲ€€c€€€<€€b#€€l€R€Zb€€Ck€}=€€€€`€€€€€€b€€%9€c<€)€p€€€€!€€?KCk€Ό€D€€ t€@ +€ €E1AY€8D1XI€€ݢ€€?0€5€D_]€€€€ġG€u€€€^!€€It€€€€#€€€)) €€1€€`€€€iۑIl€€?€$&JE€€€Y€>P€yX€€€€$€-*Rw/€MsrNH€+|€€€€tCcw€w€K+Yz%€€ˑ?q(€AK €D€ٵ€€€D€€#€E€am:Ԧ# +N B€i€jm[€€€`o€€€9&€€[€-€€u€\t€€€€=€n€€,€f€p€8€O€€€*;€j€€€€€€€€R\€€€;l€€€€€0W€.€C€50€€€€€€€€€"€B\€5€5€€€r€:lxx4€h€^ү€f{€3€€q€+€2k€bN€€o_€`€€NK@€€(C}€€€|-€73I€u:]>€n€3€€Lu)uGikx`r€€7N€€ԫ€pߪs€€.€€4M#€€R€€<I€€F€€ s€8€€k 3€#Q}ٮ€$€€b ̋E@D€€€€€֌Ա€€€€€)A€G€L€`€€€€uK;€€!4€€B[q€€€*€€G€€`%_MVrSWe€€€%€ +U€€€T€€€l€*€L⎴€€$p€€8€42€€€x€1€€€k$2}€.!€"€xO>?€€€€€R ʣ€€€q:€€€q€€€-€y="€drat+oC€€x€^€/€z€€€€€'€€€€2{.!W€€€u€م€ut€€6W€{A€€
ĕ€€8€;€€Flp€€Ԝ€€m˄€€€b€€v€?€€€€€€HG€€€B€€€(€€'€Pt5€€€+2t+€€€i€€€€ޯ;`€€€€€€3€€€€1€€€€a€h8€Wrk€[ 嵹€€€&Q€€€j€+Bo€`d€€€B€€<(€{€:HYy}€V€€N€€ќ_€€€€€€€ף€€WIɌ€€_€]F>l€KS
s€€€PJ?:/€€€€€€€A€€€€€€€€/€€zT(€€ىv€Xπ +?E€€=1€€ٯfW€€€€ҧ2€7€wM_€€€]4€€€€€€s€1M€€€€€€€€|J€€€€ܱ2€"€X!hE€€98€i%ƥ3€193€€60^€€+W€G[€€€YM-€€€IΚ€ +€€€€Lg|H€€€€$€€޺h€€/BBG€€€€25€_s?€;€€Ч1c< +€٣€.€nd޿qw€+€€€€€€€οT?€!oa€€€€:MƎwl€k€€€be\€€€€R*3q€€€€Xn€€c€€€ +]€€€I €%)€€€8€X€€€)€€€€€A€z~@#(Q€Y€€€/€€€€;|€€'€/#)Z|,€$F€>;€*(€r
€$€€€9pRb€€6€P€)m€€)"€8R€€Ut0}HW€€ $€y€#]ۡ€€2€€G€T€
#f)e(lV2Dĉ4€€€<€€C&€5€9€€€€z€Vo€b€Z€€~€b3€Å€&)m€€C$Ö¢"#i€#€€€Š€۵€ђ€@0€b&€ f€)€|€z€|€€1€Q€€€€€EV(€[€€y€€€€8€€€€€€€€€#€O€ʇEj€€p€€€€€€I-C_€}€OX€ Hۃ€€}€€k€4€9'a€|C€m€€€€أ€D€€7maJ;€U€zbD€€!}€€Lљ€qG€€€€qF9€s€€i€ߵ€Y€€.€€€MhTT}€€h+€f +{€_€€#€
€h€€i€΢€€H€a-H€.€+OP€€6x€2(9€|€GR€€€€€{€€€€p€€t€Z€u1€€€p$€8€€€s@€€€€€u5j[r€€€8a]׈G€€€$€€0€"€€F$&s€讑jU€€oT€X€€€D€€€mR,€_€
[€€'Rj8€Z€€q€€€Gf€€€x€aÃŒ%€L5€NJ۸€6€€&€J: +l€€€€H€€/"Q€€qYW5&€€€€˹€€€€€€€€vß®`€€m€Ƥ€€-€€€WV€]uoBdJ€€%€ݳ€}(€€€€€9e€y7€€€€€€€€i€€€€v€S_[<=ß»^j:€d€-5€€@wI€ߤAq€€€ݢ€Ĩ#€5/rY)€hDÈ¡_2€>€$b*?€S€€]5€{|€€€*€B€€ZÛO(€€i4W€J€J€轇v€&€9R€€4€€€€k!€p€s€€€#€K€€Ҙöf€E€€"€Fk#b€F€€\€€\€€Z€T€€þEJ€€€€h€€€\(€ŊiI€`€L€j€D*MÖ…Å€€@€d€€€€ը€Mjpř€€L3€؄P€+€!Z€€€€4€€v€€L€€€ €'- B€€€€€!€€€5j€€+gÖ•s€€€#€€&€€€D€%L€ €1Ŋ€€€p€€G>€i€€E€€€€€)G,BUf€z€€su`€€XOR€M€€I€€€€&€wʺ"M€fQ&€€€_€D@€v€c€€ef€.Y€€€€ۺ';8€z€m*g€€+=Lw5VsT€€2ߪ€e€€h\@€,€€€€€_€€ÊW9n€
JJ€€€#ѹ€€o€'€€€QI€€a=€€€h€€+p€€+€;W€€Wj€f€€W€3€€>€€€@Īd€€@€L+€€N€[p(€€€€pT4h€€€€€€€€€t:€Wd€€€€{;€G3ÿWÂ€Ó ,Ó‹,€€€€q€€;8F€bZʡ€Ԥ€s +̀€€€€€€€€^€€€€I0_€€mt€€ðg€:nN€€€€.|€€?€<€€%€€*€-VHt81€U€€]xNH€*€9r=€#>Y,bGe€€€€€€?€=€x€=€x7Rf€€^Z€€€€€R€€^Y€Xt&€F€k5€€B€€€€r€V.y€.YM€u€€@)€Z€€|€€q€p€<X€€€€=$"€€u€€A
€€@ը€M€@€€:€€€'€`€/.BW€€/€nK~i2$€qÂ€Â€Â€Â€Ô Â€g€G0X@W€[\~h€€€I€W-€€1€€€€&€€€€L€r€A€€€$8€€,€€M F;{b)€€q€€€€.~Ouqj€6-Ia|€o€€9;€€€N€€€€€€€€€l€`€€€€5V€iuL€D !€€R€€1€S€*€v€b€€€€€W€€=:WE€€:€€ Tfye6ȶ€z€%AR€€€€U ?€€C6Mh"2cÔN!{€&€3€w€€HnP€€€6;€Σ€U€€S€zr€y2Wm€€#v€-Sb€€ٵ€€€
,sD-€€€YʑO€€€!€€€€€Ĩ€€ϡ€€3W%8#€A€th€pT€€€N€€7€€€€G€€$€I€€€T€pjΒ€+€֫€$N€€€L €}
-€€:b€a(?E€€€
$We€)e€b€2;$/QҞ€€€€J4Ì«Md6€€j€€€.€W-,€€€€_€€€€L|€€€)€\i +te€€@€g€WQ#€~€€O€'€6€=9€P€€i€€2€€€€f^€€€-€€ld'ML€€€€€€DOM€€iG2hU%€€?NƜ€)D€€€0pÜ…G€€€,Ên€€€€€;a€)€€€W5×£h€€€€€€€j;oR€&€ĸGS€6€L€1eTG€€| +`€€€€€"€€D3€k€C€.€n€ €ѓ€5W€`€€4€<"cz€h€B€j€€€€4u€€8€I$$ +€I€€l€€€>jƜ€€€€8€E€M€/€€$'€€€€]€*<{5+!€€€6€€4€€€€€€€ €5€yÕ¦4€aV€€€€<i€€̣€查€c€€€ ë“€€€58y&€€m€€€€*7Mf€€pI€€ÌQ3׮€€€€h€")flӞ€€€'€€€€€q1€€{€€kA€<Q€€€qR€€ݩ€&$/F€€€Z€€€4€=n€€€€7ߘ€:%h €윩C\€̼€€bo€֯€R€7€€Dmp} Z€€€€^€Sz€€?>F,L€€€N€€2l€C€€FÛº'€#NW0Å€H+€€%r4S€z€m€€<€€€€sOR€Z€dX€G€Q €€&~€X€ߡ€H€,%j a;5Gp +3€I€ܳ€€SD€€8Tr€€€j&€U9€&€#TS€K'A€l€€7€€@€€\€_Lv€a€€€€
T&@?T€f€V€€€€€2€(€€0I€€O6€€€:E>ހ€€€>€€€€(ȷ€0€€F€€€m~?€r2€\m€€€€€€xkO€€€uZIf€€r€~ +AA?€€C€E€M€ €€p€{€€l<ЙI€€1€€Qh€@L€-€€)ß½#L€g€€€2€&€€€€o€8€t€.€ ?>€|€c€JÞ¦^€,€?||€7€€A€€ß€f(a#€,-}€€Ya€pê¨Â€CY۫€H€Z€€-€=0€i`€bqb€€_€€€€€)22R€W€\€{€ʺ}€D€€4€fi&€€.€€!€€2c€€€9{V1€s€€€€]€L€€€g€@€€€(3)€K6€€€!R-2'1€€Ĭ€.€`]€€€Jh€o€€q€R€€s€w€€]€€y€€€€`€€€€€)€)€€r€€J€Y(€€B€€xK<4€E€ +)€jZ€:€԰€fb€I€€!Tu€€Y€dp€€€W€)al_`q€€€€€€€€&€€lZz€ €€)€_€ֽ]€r€€€€€€=€€€" €€9€S^ä°ŠTݪ€€$€€€€Z€St€€ɑ€€==€ӿ€€.;SÕ¼X€q€€€%€€€%€Kp€€€Ã€€ϓ€€€"€€c-€€Ű€EW_@€€Ч€€€,€'€L€q€€p€;€H€€€€€€3€€€ +€#V€1€€€€=€€€_€€€€€€r€€€€Qt*Xo_€:t>€€`9€€€[€€€z޴€N€€€Q€c€€[€€€€o€€€>€r;€€€€
€/€€=D€D€€#€€€)d€X€z€€yy2q`]€€€€D€€€€GB€€€€€€€€€€Vvǿ6€€ɉ>€€€€€€R€p€dTm€Zu€€1€€€/~€d€€€2ڟ€€€\€€䄈Vܒv€€/€€€€€€pH€€y83€€€K{<€€FW€:€lG€/€p€€1€€dw€S€$€~k|_p€€€€€€€@€oǴc| +€i€€s$€
€,{d€€€W€/O€CI}€€/€€}€€9€>€€€€€kL€€z€X2€Uڌ€J€dZ€%,z€:€/€€ ÈŒ r?Ù‹ >V€d€€ǃ€€€`€ißžy€b€€€Xc`€€€_€€€€/€€#-€+¨)€1€€€€€€e€€€:Z€€y^€€€€^G€pxO€4€uK_R0€qvd€&D€€€ȥ1€3€H €P0€Y€€€€€; €x€€r[€€-B€f€€g€€X7€€Ҭ€'€U!#U-€€Ն޻€TJ€€@€C€|ߦ€m€1€Wuce€€\S€€F€€$3€{,€L€€€€b€D€3€€€m€€Sm€€€€^€S=rW€j8| €?€€?€€€4T€€€€m€€V€E€€€^€W€€€:>:€R€D/b€Z€|9€Ô×¥0€][€€ +€~Ȯ€VR€%€€€€<€<€}+€€€€{€L€O€€€€€@v|€€>b€€e€}€r0+€~€@A€€LhOd€€€€€€€씮 +C€P€€T€€€(€
6€€|@=€'€€G€€€`€€€€€€i€oN€~T€€_€€€T€€U}€€/€€€€`€k€;i€€'s€€€S +€L€€€€z€€Ӛ€~K1(€€dUi€€xp-{€N2€R€m9]€hZz!€0È3€€€`€i@Ô¯\€€ޗ#€\ћLJ€!€€€€€ʳT€Q€€ڪY€€€6€€%€€€€€€€iL[€€€€k;D€a*€€€€€t€ w€u€€"e€€jP/%t€F€€€€䵯>€
9€€€ €€€€€!€6NC/€€M€C€€2€D€:€€€pV€€%ih€€e,2€mh€€€€Cw€€Z9$o€@€€3_3q)S€;€(€€€€ S€€€€B€€x-€€€,€C}€Z)€€*;€€€€z€€€€€€8* €3€ e€+€G€W:€G€€Еm€€€€€€€*֒€€Е*c$d€€€€.€€#€xD€cٖ€€€€€€j€€1
2HL€€H€u€޾О(D)o€x€W€;9€L?€€{€€_€~€x€I}€6A€@f2€€ԟ€cy€Pl€RE(V€€€€Eg€#€€6€9€'€>€+{€1;€Zψ€Eβ€
X€F€€€S€4€€Z€€.€€€=€€€A€a€A=€€'4ld%ie€€€€@€€D€€€€€;€€€C€i€K{€€€€€69€Ó€<€\€p€€€€€~0)3x€€€i€|a€€€ע€ƫ€€€}€€€€€€A€H2]€€€€€L€G<€5€€€{$*P€€<€鰛j4€%€€€€€6€€K€€+€€E€_
€&D P€€汤@`€€Gdn€?€4€c€€€- €s`5€€}(e€~€€u_(€€€ȿdA€"€€.€t#€€/)€€8€€€ֲt)K€!€€hI<0€v€E€€s€uK +€Dݺ€€€€!€€€BW+C€l€€€<€%€CH€€ +.La€MMa€ Q1€€€€€F!€Lj)€&€€€B€`V€ €€€€€t€3€€0Í€€€ҲB€ GE$CRx_'z€+ e|€!"-€€8€€€j€?€€=%€€€€f€TN€€€#€0€5€)€L}€€€€[€e€€H€€€€€}€€€€V€€B€€€€-\i€€€{€€€9€€€-€€8€@$\€€€#€Kd^o:A€~ciÑ
€n€Ρ€€€ï‘>#€HH€n€@€$€)€ 2€€<€*€€!/*€€D€E€€̚€j€Q€€€€\9ȱ€€8€€{€0Ë€,€€dszh€l€€€XI€k€€€€Ӊv€€€i€x€€€€€€€^Jhu€€&Z€O€€€€)€€3€'€>f€€€p€€€€€€€Y\p€r5\u:)€S[_SO€'€€€€5wy€y€yi€o€'c€A€oE>n€@V20€+m€€€G€A3+€€€֣€y€{1_€)€€€7򀀀b€kѬr€m€5̃=u€F€v4Ý‚8€B€8€€€1€8€\€€€€€€3€€X€x<€€s},€€€€R$€$Q€€€L€ }R€Ȫ€€€1\h"€0€8€ur€e.€i0€€N€|€€D€Vd€€g€#€H€cCTg7€€au€€<|Pf€ U€%€Bt€(€€É€[N€€€k<o,68%ؑ€$nXf€€€€€Ԍr€Д€€ܔ€G€T€8C€€€€"€€D#Û€€€€€~]](T€€]€: €€€*€€€N€/Q€I€€|?\€€)bʡ€€v€€, Lkì”±|€€*€€g€€€€€=€J=[€i€F€€€|€€j^€€€}€O€€WH^€€3€<€€M€UZ€€€sϷ€€[5z€€€€€쥯€GÜb€tґ؀€R]€>€€
€%€€€€n]€ 4~€l€\€€€€€€€Ta_€€€xد2 €€SdPQ€ʫ€we6€€€1€€€€€$*G€+]€?€Y(€ז#€€k€?oG€€€€|=€y\eÃ¥y€€€€€€|>W\€€ W€€P<€€€€€ÖGxvV€#9o€€I€G€€a€Nx€€€'#Jh€m€€# €€ €U2`n€
{€€Ma€舋€€]7€8K€(f€B€€€9€ȟ€€b€€h€
€c€€W.€€€8u€€KKJ€€W€KD{€€Kß1€€€z€€€X71€.k€€T_€€W €€€€U€€=&€€€€€4€x(NH€€€€M<#Z€K€€h€|.vS{-R€€G€!€€€L€k€U€€€€€B€)€u&K€€(&€O€€:j9@y€-€€vKl€€Qe€€ €€€~1G€€€Z€F€YY]€ +€l€€B€€t]€P€€E€€͋;€D€€%€H€€i€2 €3€<€ +€€€^€€€€4&€€€7€=€С€€
€y€€m€€€€G€€e€€4€€€n#€€v€SV€)€r€X€€'€0€[€2 +*O€€€k€€€€€/€Iͺ€€€$B€€€Px]€€€€€Jm€€€€€ +€f€`@€€#V€€<Bn€€€€€€x!€
믤⃙a€€9€ H€7€F€ϣI€€ZΪ€ŵ 깜€€€€9€6€i€€€)o7'€€;€҃7€d€cy;€€о^`i€€&€€D€F-H€€€€z€€€€€*€€y€:c~€a€6€€€Y€BA€€j €!"5€€€€d,€^E€€€Z€€€~^€€€+x€ؕl€S;€€^ѳ=o€€€€^€*b(€:*€dt€m€€؉zP€V€€€;Ts€€:^c€$\€=$€ǃ€€=€$2.
n€€€€(€Pp€p=,€€y€h€€x? +r'€€€nH€ tÑ1+€€T€€ACeSfb9€€€&€Z +3/&C€€gP+€.8€̄[' -poQK€€€€fD\€€€€t˩€€I€€=€~€€
€o€€€K€€ +z€+€acg|u€€€D€/[€€D€€^€€ڮ€)€ +€€ €c8Z€=w[€€€ϔ€c2€€2N€€=€OM€T€€r€h€ +€~€N€€nk€R€€€Q€4€R€€
€f€qM€€€i€€K.€ۗ€LW€€€r€yd€€7€€€H€€€€€/~€H€€T?L€뮫"€1€ +€Xg€j€X€RW燹€sÍ<h1€€ٌ>UBC€€P6Wo€ €€ᥰj/F€€€€€u€M€€?4€#€W€:-€€Yn€€]€՞`U^L€€O€@,€€€€6€> +}Z€€NwU€€-yEz€€1[€bÍ–m~€€O€eTer€~€+€€€y(€M€q€h€]€Q€RX€N€WDj€k€€K6R€⌽€8€t€^~B€€€€Ao!BD€€_€€G€€
.€*€5€jBN€€k*B€€€€€?€€€€j€!€€€€€€€b€z€Pt€€€,€€S€€@€€B墪&H€€€€PU1N_€wG?€€€€€€€suu
Â€íªƒÂ€AcY€, €/€€q€`€€"€€9*€€7€€A€H€€C€Û€ArY€
i€€€€€€€€€^€c€gUK€€)€]~6€I€U€€DKһ€&€y€7€X!€ aw€€€5%€€"€€€(€€€€YP€€x€€€x9€1€?bb<4b€`€P€_€€€(9 s€€q€€€鬚€'Ce€_€€Ub€€
€€8،€€€2€€€׾€€€€/€€€N"€<(}€
W€y€8sɧ€r€€€Mˎ€%€€€p:C€E€G€P€b&€€^€]€HR +€"€A€Л$ K€€€W€€€€€)~@W€€GTT€}€€€€- ׇ€n0N€€+€A€€PԹ€€Dih€:€€Y€€€€€)€UHY@~€F€J€€€€€€G€u>€€]€€7m€3!€_8€€D€n€g*ϖ€3€^€€€€a€S:Ù{€€,JK€€€g=€€[€€€€€€H'€b€B€ϛ.OVwD€w€€€€6U€€€^€# +€€€?€0mw€od€S€€€Ѣ€€b€€ݔ€>H;˩€{[€'€€l-€<-€€€€€Vo1W''}€€€ȷ}
€L€€€c€XD€ȶ€
€€U€D€€€€€(00€V€€à®u€€ܻ`€J€͒€€€sk€ř€O#j€ j1€€€k;5€€K€Tc€kV<=€€ؼQ€R€€<x€`~W €€>€̩€€D3€€y€€€€=b€Ң€€€B€€€$€€SaJ€€€€€h۱€€Ge,m5V€€€L€€€€€e€€R€M€IJE€€€€I€€$€€::€E^8€€b[€€[.J€€€€@Ý¿af€h€6o€€ͣ€€#Ö¶4:|X€7ݣ€€=c€h€̲€#€H€C€ǫ€lAT€€€.3y€7€oЇ€7€A\€€`€v?^€h€p€€€€z€؞€€P&€p€D(+zƽ€€h€€M€nI5K^€"€Ee€b1€V[€€A׵€€€1€€)%S__€#€€€F€€o8€€CPV€#a€€qh
€8€€€€mt9 €€^€WP€qpZ€€c€Y€CÒ¨Q€€͘€d€€'€€rhQ€€fR€݉DǦ€ꈙ€I€€€fE€qL€€€€=€:€€€"€á¢Â€/u€1€€a€^U#9€PIP€€k&PZd€e€du€€Ple€€c€€€㨇€˟€€€i
L€6€€@,€<v0€!€g%6€€€€f€D€€€v.€5€€L€(€€€l*~_€€€W€€€€7(x<ɕ€b€&Q}i€€Vm€€t,€j€[€C€€€#"€\€€.€Yw7€Dxμ€T€€6c€€)7€€€€a}5€€6V€(f€€€€+€€<52€€ªԀ€€€€QN€€€€(€9#u€€MaE6€€€yN€!Ù› €g'€€mz€ƣ4q€ڇ€€1x€oA€ۅ€€€€€€€€-€%7€€u€€+€€8€7€íšÆ–[}4€^€6€€E€€`€v€€Ь€AIY€€€€€ДA€€€M€€Qd1€F€€€t€€€z€t€€}N€€€
€^F€€)€:t€€g€*2_€FÔ€b€€y€€€!€|€
]€€€RV€\19€€€€€€b€€€€3 +€^€€QJ€€€mj߶s€4€€ -t €'Â€íª¯-€T€=€^~U€Y* ruK€€€{€O +€>€€U€>€€€+€€P|"1O€P2$€€€€ +€΃€^€ԆB€€€I:]I€%€€€Ц€6f6€-€q2€€€L€€€€ў<€V€${z€€2€o.lν€=Cj€€€H€9x€€€r€€€^€€€€I€€€€%q%€€
€€€#c2€_A mE€€€€ř€R€yo€ €xŃ5(6~€FS2€€€€€€€€€€]€€€€€V€l€(lQE̺Sx€€8\€€I€€D@Í“k€€T€˼€€/Ù±4€€€9ݖ€€1S€€H€€€Hb€€8@€€{€I€S/€€€€€€'']€\@€P&€€g(€€€]X€€€>€€€اLB +Qpç’¹Â€Ú Â€ 4р€T€€€-€Y€DH€€R€€ۨ€2€€_€€c&S€I€0€€Í?€€€J€+"€-€LJЪ€h€€€€c€€€€`d€€€_ù€€A#€€d 9€oH#€1€K€<€€€I"wYϤF€€€€q€n€+€.)€p€FfY€)€€9€€O+&€r€QmYK€=€r€€aI€(9€CCj€}r€€€Q€,Óž[/bX%!_€ͬ€€€-Úhpe€x€g€€€U€€€3=€vྜ€€"_€€€ί€BØ€€€€@€€€€€€€€€7#€€€€`p€€.`€€c€€z€€€4Lr€€ȧ€€€dmp]€€1€#€@€€€ʤ4€{[G€€H]€z€!€\k€-x!€mZ€͚€w€€.€€€;Tl€€E€2Ց€#€€€q€֮@܃a"s€€€€,H0C€,<€€✲€€
-€€l€€€€C09€€€€يQ€€q€P€€~€€C€ץ€C+Ä€}€€€j€€D€€((/€€€€ €€€€2v€€€€€f€€ €€€l€
)€%s8C€=€€€€[€€€€€€€q>€)AxzÊ€N€€J€#€€€;dM€H€>F)€Zϗ€€O€€mc€Y€€d€J8€&€<€+H9E€€qk€€€€i\€PX€=j€€€y83ᦑ€€I€h'€€ϡ€€€^€€€~€€€IW€h€€€D5a€W@ +G€j€F€pss€€K(>==€U,€H€ϼ€€€€m€€€Vs€S€ +€€€q€q€[€€€2€3€m€8(€€
/"f€€€P€€H!€€G€~€eTv€G€€Ml€2€Q€_€N€€( +zEd€acN€€{ €:2€۲€€8€€!€Ct €€`"r€€€gQ€€`|€7%G€|€B€€€G€?€7€€€€ޓ€#Z€€€€€擫€€€€€€t`€€€€{€€-€$€€IpU€"€Ǟ@)€€€_S€^€€Q€€DF€€qI8€€I€€~€ꋛn€€_Z€€€€-*V€'€€€€€€9<€hiK€n€€B€WyW€'q€€J€€e€[€% +L€Z€€€\€X€kk?€K€€qè£Â€ZY€€€:Mvu€ʪ圪€€€€€€,)Q€\€€€)I€9R€T€r€€s_d€}€€)€€d€€€€€
C€t€]€E€€€€€4 +€Z€€€x€€ik€v€€w<€_Lç°_€€[]€€€il{;'€€'€€€:H8Y€€_€_Y€A€€PZUIz3f€€2€€i*Û•U_€
.JX€€3É Â€Â€m€|€€R€9?€WH<H€€ΉRonN'€€€J€€4[€€€^€d€€E€י-€€€€€5€€vÂ€Â€Â€Ò Â€Â€Õ·]€Q€€€€L€jd€€f€€€€€€€€%€€Qdžd€€0€Е€EA€<#B€e€€tß²H€070't€€Bp€€€`3€€€ a€€€6y€\€7n'€€€€€€€€=€€9€@3€J4€S€U€'/€€z_€€#€=*\€€€^€TbI€€€8€€€p€jy€€€+P,V€€E€l-e€x€€R€v>€8€€f€€"5€*€€€€€€o|€z€€_~b3€a%€!f€"ËȪ€0|jRW€€~kN€3=7 € €€€Z<€F€€€€€€&€]€€9S_7€[ € €€65€v€€€jÒ H€Z'€C'€€+€7'X,€€k6Y|€€€€€S€L€}€%}j€€\ʢ€\E€€€€:€€K€{€QBH€€€€€ˉ€€D€-U[€o€"S *€€€p(€|Þ¢;!O€#{€€€V€€Hh€€5€€€€i4&€€€
%€€[€€€€€j[€€[€€rS€€€h€bAJ(-€€€f€€€€€€u1€6€y€C€€€€€˛€LJ€€K€m€€$€€€€€€2€€€B€.ZK7€#\~í‹Â€Zb
€€۱€=x€݋€"€]€€€€ۂ€€€€{€Z€%€€?€€z€€}JBq€€'€*€€€€€€€qܨ€€€€€€$F€€I~J©€,€R|A€€€3€h€#€Gq€U€€+€Ζ%dz€€€€€f€€€€€e>H-@€€€€€€%sC€€]?€€€v +€N€€€€€€6j\€8€€€%€€ €€9€&€€Ƶ7-€F€_€Œ€€€€€€€€€€€€€€.€s€ؓ]iŇI€€S€€€R€€€,A€€€€c€€J€tr€€u€€d€y€F:€a€€€€ )€H}€€c€€?€?€&7#?D€€!€U€J€€€€8߶€p€B2V€+€€u€̒€€LZ.€€B
(€ vZP€)€€€€€EUq€€z€]€Q4í“·%Q€€€€€Pe€€}ͯaå·—%:€+€€€€%€M€€i€kA€€€€[€€€+Ò»P€€€€€€€€Sql€€€€s€f€ّ<€€€€Ww€€€S€€8€€€5€€Xa€€€€J€€€d€€L€^#:G~j͑€f7€€x{€f€F(&84g€@y€€?<I>B>v€€€ +J9€€0€!1V€€x€E€€]€€€€J€€€"h€€€^€h€€q€€i€8_€€š/50€B€€$€s€€FD€!€q +7 Ý€j +€€€€÷€€€c)(M +~€€€ĸ€q€Z€B€€€Ý€0'€€Ӯ#v€€€€€T[^hz€€E3€b€N€€WV€€€ €7€A#€9€#€]€€G€€+€K€€sY€€€€€€w€€c͞€€r|Ѐ%K€€€t€€r
i€€P€g€"y€€8f€S/0ً€T2€€€€€€}€T€Du€€ݮW€€€_f€€&=€€€€€k;c€E€#r^d €U€d€6€€€r€€NN?!6bdc€€ʈl€p\!€€Ө€w€€€€€€'€€€-*€?5h€€€€p€€€8€€€€&I€€€€€)ޫ€b +€€€€€l€€Mo€s€€ +€[mkOH€q'i€DZ€€z€tu1€fP€€€%€€+F€€lP€€a€J€€€€f
€€€€€k€€€giRg€J€/€3 a€€€?€a€f_8A€€€€€€i€ €€€a€)s€€W€€v+€E€ZMS€€€€ +J_€pٮ€€h€i€€€€€>B€€I€€[0€_€W€w¹€€€O€€`€?€*€Eh€M€€R!€€€"€;€€€(D +1BeB€j€€kX€€9€€€€€Kݔ€kp€€?€€€g€rD€€U€e€&€€€€€€€€$\Z€f€S€€€€c€k€€€€kS/
€D%€€€€ՙ€X5€_€L€€€€€€€X€€€$€[€!€€>€I㩅€ €$€€d'r֛€~N€b€€€€€€f€ݣX$w€€6ţ€&€€+€Â>e€€v€€€U€޲V_€݀€*V€€€(7€€%ۓ€€-€€T€€ta€Թykn€zU€ q€€€&€€D€y€p€%%Ax~€{)ãš¿(€€€Q€€)€€€ƌ€€€y>XA€€´~0€€€"€€Cw€€T€n€€€€€t~€€y€€0€€€€€€rnW€€€|ԙ€€bJ€G€€J€ui<€€€1€A€Yio€€€€r*c,j€€€€€^E186€€C€FD€~XMN€€€&D}€Y^HƩ€W€2C-€@€RA€ +€0e€ֽ€€€y€€€c€~8׎€"€Q=€€Sږ€€N€6a7p€€qxΧ€ ^Xo€€€€€€/€€€j€€:€€€€€TbQ{_=l€€€[€i€€€2€tOlk,€Ҳ€^-l€€€€'€€€4/߀'€v€>s€X€€€€]qe5€€d€H€${Ȁ€€€€f}Yq€€_Pz€k+€
€")€€€Kl€5w€€R€€X81a€9-€F€*w€€€p€€}x$€Nʨ€ZX€̀E€@€€J€l.6€M&€€€€J:€,€€€bM€€€\|`o€]~r€JBI€€!€W/€`\~€r?€€€)Ҽ€Ú}ì?€J +€€x€€€€g€Zv€€€%wa+€hU€€€i€9€~u€€€€Xa.e€€€€k€#€€1€t€€k€€
€6ß‘>€y€9€rǰ€€€I€^M€€€€z€)€Gr€wÂv €€wB€ۯ0€l6€€€€ѫ€€@€?z[€{€t€€Z#€9€+€€ܪ€€€M€p€€T€€-5€U€f€€€
O€u€€€uK5€P&4dFz€x€€€^€€F€€€ €f˶8~$€€€€'€€ska2€€
f€€€€€V)€|€uϑ€€T€€#€€€_E(€d€w€}€€€€U|€K€€."4€S€!X€€€€{q€Z€€€€€€€€€€€&€q€dx€€j€[RjB}PgAKg`r€MÔ b€o;€€t€€2r€G€o##€€—€ע€?€€€€€h€€پn€֧€€.€€)€#€~€€€€€KI€r€€$€zm€€酑€€€€f€6€.F€%€€€h€O7€€€2€€1€€M;€-€€q€0€€€€€€€€8€T
€^€a€`€€€*U€€€:X=€.@€€-^E!€}€€€€8jcG€
!€Æ$€€)o€]Y€e~~{=aw€{€@6+€fF€]€C\x€\€€€']€€€>€ȇM€€V€€ +€€€€^xQ€'€kw &€I€-€€€€€€€*€v€3€€€11$€o4%€€J6%€V€`n{,1ú€6€€Ըr€€e€t€€f +@g€€Ij€}€@€€!?Ù›_X€pag€u€Y€gf€p€ +Τ€Xs_€u€}€ǖ€l€x€€[€|€Ї)€€b€Œ€€FT€Jԗ€lBbܛ€b} €€x€€€d€h€q€\'€%€/€%€$Tc(bo €€ €€€np,€ZD€€1'3€uÕµ>€Ï€_%€€€.to€^€€. €€ˀ€€#€€@€#€Q€€z€[€€€,=€€€:`€€.y' <91(ߔ€1%`€€€Dw€€%€y€v€0#€
;€{€€€n3€€€`€€C€€u€SUK€!€€8€Z€Y,'€€(€e€~€mw€7€€M^€€€€€€€Ҹ€€€ +P€̥€+n€€2€X€€׮€€€€€€+\k€@5€€€ɼH'€€*€P€5:€<€Q +€E\q€€€b€€]€€[€\A(€,€€/€€€€€n€€€,€Rsh€lO€;o€€2€.B€€€^€.] +€tqLÓN€kq(€€}`]€€€'u€€€€€€@L€(€€9 Z_t€`; +
€€€€€€6#S~P#H€*I€€j€€Εf€\€€WR€€€=€€Ó€€€€€€.P€€€V€Y dHS%
eܲ€ڞ€€€ Zp<Xm€€V€€€€>BÆ‹ €€xÂ€í±˜gfJM€6€Ria'(€Pj€A€€f)€!Z€€h€€€k€€H4€€E€€€#l€€X,€F€'€ū€p€€D<€€€V€5€'€ >€€€#€€€€ €p€h€€€F}€)€€€]Ż€€X܎€€€|RJ|€jÈ…u€Q$€hЫ€AaKP€#€
+€SÂ€Ö X€ճ !€Q€€€zn€€X€€!€€yUÜƶ€J€Y[n~€€€€`€€€€€Їd€€€€a€€€€€€-€P-€E€1&€€€= i€C€€+€Ӆã½Â€Â€Â€Â€Â€{€€€W×?JC€€€€E€~`€€€eoig€"?{€t€€+Ï€X€Ԏ<€€€]i=€€€€€€€€;2<€€€€€€€j€€?€5hJӦ€I€€L/ͣ€€ּ€€^€€€6€-€€€€k€{€€€€x€
€€鵷€€}€€€s€κ€A€€^g€€lz€-€s߃f€€uo€€m€€׼€Moc€۸€m€€o€€Yc€€€€€€Jku€€G€;€€€€~€€€€\]€€€€s€n€S€€ |{
€$}€€€€€€€O€€€€€€€€4€€?€€u€e,€€TDee +€€W€€€€€PX*{W€€€f€)€zQ€€.€s€Toq€€€a€U€€€€5g€Q€7€v€G€€€€;€vqkk€^€€€€€€ຈ€5€€^.#V€€€ p +;€€z€€€â²pM€ݽ)4€€K€€:k€€€€Q€D€€€|€z(9€€€#€G€€€€€"€h€€€
€d8'€> J"€€€€€€F€:a€€1nxO€LE€Ceݣ€S_€€€hA* €&€Qw€€Һ€ݡ€Ţ €€װś€€ȸ€€€m!i€T€€€ €€€€u) 8F[u€€u€WÙƒZ€€W€kY€€_I#€i€b#€€×€€]€Ͱi€|€<M€€€Qt€dr€FÔªf€;T€€Sf€€€J€€y€f*€€l`€€€mQx€€|N€U€7€i€$€\€U€€7€$f€@K€€€g€b€€2k€€+€€€<€€€€€iM#a€€€*€P€TY€€y€my€2~€€M€r€f€€d<A]€6€'%€ +1€Tf€A=-Y&€€"€€h€€€€8V/€L^€€Q€€vD€€€€`@˸K€G€€8€j€€€€7
\€€€%€`t!€€F€j€€€€€?€M€€
€"€\€€€pz€Ŭ€-€€€D€xDZ߱NS!i6&€€K€(#g푼p€Z€€€;jx-/"r€z€€€O#€€€€€k;€("€i€ +h€)€r€#€4]=+€€€€ą€4P€6%0€܅€x|€v€€€b€l€jm€Þ€€€Rq€JI€ϡ€€€€€]€€Ob€
g€yHD* +€€2?€퟊€€€z€€E<%DX€€,ţ€€ÔV&€H€#€3K€€€€€3€O€€q0#€*€9j[€*€€>t%€€€€€€€D€€H1€€t€V`€Ç€€lu€l€€€|Ý;€—€l€€€€€€€€€€N€€{q€€[L€'km
?f€p€r@€€€BW€€ cZ=€r€€€>WUEV€€@r€€V€cj€€I€€TϜ€P€€€DW€€Ӳ€l€!€>MMc€€€€€€^_# +R}vƾ€@o€rR€_€e)€~€€€€€€O.€s€҇>om€yJ€€BU€€iQ€<€t€q2B'€€€€[I6E€€]€€€€˰U€€wgP䙈€€B}€p€!c,€€J€€€€€€€€ +€i€O€€€ŴE=€€€€yDQ€€oH€gФ€=~€ +_R€!ᗦ€R_€y€(€$€€€+€R%'g[€€€".XQ€K5&€€A€6€€€€€€V€€€Ev€{;/€€€€€gW€€%Gr€€o\mK€Ќ€€€RԿ€>~€€€€€`€€7€z€€@€€f€€z€€/GR€€€€磨 +m-€€€xbq€ղ€,e€€€z€€€٠jl€P€WK_€€€=_-€€€(€€CZf€€€€€€Ÿ€€u€Tm€u€€€>€d)vp€€-PKۑz€a€w€p€€€"\€€€CP€€Q:d€€€€€\€€€€iH€c<€€€€€ +O>^€ڀ4|0€€Ç€5c€€€€)œ€4€I€€€N€P€VI䤉Ģ€€\€R€n€€€€]€€€€€ܕ:c.€)€=j€2D€oX€€l]J#sj1^b€€€R€€€€Z€ €G€€wM€€€€€@ꔂqY€p€€€€o€Êa€€N"€a.a€€€b)€€ƌ,€€€k€#3Ë›o*€!€8€€€c€€€€€webheadebc.listc€€N€€€€TEXTMPS €m5!€m5!
€€@*Example.
@c
WebMakefilelistc€€€€€€€€€TEXTMPS €G*€€€Ey€2€q€€€€€€€vbl€ϡ05^€€€Ao€)F[o€€€€€€€#€€%€€A€tp€(€€a€€€€€
@€ڎ€€€S€€€7Ck€€€gEqÝ™|q€Ĉ€€€l€€€|m€€1€Ý€c-€€€~<€€s%
II€ +ӸiTP€>'&€f€(€€€fr%_€,€dPg%h^?g$€Cf&O€I3}q€q€€~ge€0€9!jCt€'4€€€€M^p€_€€€A€€)€€€€V6*w€3€:8WrĘ)J€€€€-
€,eNW€x€`~+yJl=€€Ȁ€€€pz>€€G_F€€J8€p +€€z[}W€€€€|€+#h€L€\ €o€
€€€Ox€€p2€€SB€€Z€€€€€€€€O€}B€%] €€€,V|€€z€€€€€€L€€*%€€i€€^€€€F€R€€4€d€2O€\(€H$€€€t,$€0Q€t(€G€8€Iqj€^€€?€|<€€ӜI€h€€€ZHh€€€€€M€kzɥ?]2€€€)€€\2?€€€&x +€C€€:€€€€y€€ywxz€€€{€Y2€€\wO_vO€€€€€€y€€?aɲ€€€€K€€u^€€j€€€€u€]€#e€Vx€L€\€€€€€€€)€€?T€€&:€€͡€;€c€ZbK€P€€hm +€€77Q€j€€€€€€!5|:€QC-c:€%€)€€€€€&Lz풽€€H€#3€5€4€Bј:ݳ€€€€€$€€ND€E€L€*€<€p€€ dA_€T"€J€(€€€€€€Y€€€€\Fa€€€€<€qn
l€€€€U€€I +€IL€X€€€€€TZ€€Ԫ€tӀ€€>€LB€€_€€H€€9€€p?€l€€€€.O€€€€€yU-ȿd€€E*b6€`0D1€2K€1S€ay
€{.}˺€€€u€€€€€b€*s€€€c€p€€S€'[N€~;€€vVW€{€€y.€k€€€msU€€€€2V€€€€€./{W€€€€€Y€€€`b€t €€b2€vacNG9€d˸€€€€v]иFm€u€€0€y@a€$3$€9Æ’1€R€|€.€e€€€2€€M-€€vff€YS*€{€N:€B€€€{Z€€Y€€€€€ja2€U€€h`h;€€m€€€€€€€€S€€Q%€€[€mr$€@]w€€ʹ€μ€€€"€€€€f-?€€LÈ8K€€€%j€ʫ€€€€A€+jLȖ»9v€€
-8ɑv€6€€€A€k€Ӧ€o€*€E$)€€€7i +M€2Q-€€A€€€€U<`€€X€^€_f€€€i€Y€€+FJ={]€€4QBj€€€f€h*Y3i€€Tk1S€M€€€€€^€€€y€€Yg€HL€€€͗€€€€j4€)€LR€€[<.f.€D[!E:{5€s3x€€€X Y€€<€:€L<€P€€€€8y <Lޢ!€€;.€€ y/Ÿ2€"€U€%S{NGiZ9QJE€2€$z€.€€€UQ €€€0€€UwF€inI€€€^Ǚf€€|€GidVs€€U€€&T€*[€€€,mAUo€€€€ +€€ m+iWG€€€Ø€€gJ€€^€&€%€€€[€€€€Q€?h€€€(€€:>G€€€€€–RWi€+€i*€€€€€€€&€.af€€€q€[\€x€€€MA€Ղu7€i€€`€r?€€€€€€yC€€€/1*q#j€.€€_€€€(€€€;$€ +€b€K€(\€€€_€€€_€r€}€€a€€€€ܧ€y€€BP€€>(K€8€̳€.€>0€
€€€
$€2€€€-n/€€Ih~qf€@$€€€€C€f€€€2€€€€.t8€ܳ€)SlQ€ii€€T€€r€l€€U€€€K€0€€€€<€€€€€€A€€€%eS€€€x€o׃€€€f€s€€€-€?ׅ€ia€=WAv€€€U€€ +€p€€€!€l€7 ヿ€E€€M€€8\€戱wNj"?nlQo€$€豃<@PO#€€€u€S€€€€g€$€1N€t€€€€7З€Q€€€€?f€€€€7€
€c~*€_:€€c"€k€€ t€<€€€
€ +€ +€+g:€@]€Z€€€€L€€
WebMakefile.unix€€€^€€TEXTMPS €m5%€m5%U €€€qNW€x€`v+#G[#Ô‹p€€`€€€€€€=€I[€'?J8€O6X=€S&€€€GMr€l€~€Օ€€€€€6€€7yN8l€ 61€)Yh€€€Tk€€€€€€€€€4_€;cK€€B€N€h€€€B:)l€Ӊs&U€K7J€434€T;€€€X€€€€€qґ€Ś€~€4V€€ *€WF€€€€€4€€€€€€€€€€sI€€R{ʔ€€7€€€€€€a}€m€€€€€\\KÒ† +€€҂8€VyGR€(kt€€7º$€€€€N޽€qr€€^€W€€€'€+)ndr€€€trq,€z€*€I€€€ӟώ€€€€€€€€€€€t€€€74\€€€rv2K`€€€O€_€OH9€€€€\€€€Ox€˲€Þ3Å€€Z3/dIfAe]xU€€>€U€€€€*€€€€€v0":€T€€L=€L€c€w€€ia%€R€€€€G$€€€H€ʴ€€CHo€-€W€€€€€€€€U€ 0xd):B~]!€0`AkS€JE;€tr€€€€k€€€ܔf)€€€09€€ €h€€A€€€\>€€#€€
€€N;€<0I€T5Cʳ!€G€K€x€€€€€€=Ǿ€€ K+JT€€€€€:€€鄀L€Ԫ9€¼imCߴ€A€€c\J€€h€€€!_€)P€ybWa`f€€A.€€€Ռ€#3€L)7"€€N!€€|€€€{S€L€9€v€'€€€sd€€€d€€€&@€€B-€h€€7Sfm€(€M€rI€*€0€r}"|E€9$€€M€QU€T€€A€€€++o€€$o€*X€€€k€)€€€€t€€$.€€€€€€€€€Õ€:€€ -n€ €X.€€€)€q€€€€€€eG>W€€€€€€A€€"€G€ByEۻ€s€4€€€€bz€*€€€€€5€€.€€p€€€€€€€€€€Q€6€Ƨδf€$€קg€€w€qK€€ћ€€€€€€€€x3R€€fI€€€€€€q0€
s€=€€S€-V×€€€€€€€€?r&€U€€€€€P€€€€M%€i€[C€tHË—6|€%€€܃-SY#€€€€OS€O€€~)y€5€€0€;-A\_m`
$€€€€€U€€€i€z@€€Ð}€Z€h€€00€K€C€€€€Mc€€€
{€€au[ќ€6L€€6s4€2A€€ €)-€Y€€ZПi€€+9€€F€_€"€€Ū€€€CД€€#mS~\j€: 1€8€P€€"5€ZIohKV€8€€6€€7€€@€€q€l€R€yk€9€€€€ձ?€5֙ǽaT`#`v€€6H3€€€څ7,(Qŧ€=]€ x€€3V€+€r+€€€-Æ—I€€€4K|q€€€?€€€€ +€ҳ€€[€h€ܬ€qT€€M>}€X$€€€€ưi}>m€q€qvC€t5€€€X€€"€€mY€jW€€€W€l€€-€€c€€€€€Z€€D^€€U€w[€€q€$€?NoGË€€ۛ€W€€
€€€YKCM+€€X€;€B€€€€}€€€q€Ù€I1€׬z€v.€!9`_€€€j€<€%wO€€ +€om€€€€4/MF€Ճ€€`w€f:}€1B~€€€{k`K€ٹNNǰ€jK€5)F/€€{€57$€֚€a€ij%€8€1€I€€€€k€€€€}€EQ(€xÂ€É Â€9}€€€w€€<
; €5€a>€€€C€€]€€€:€€€€€k€v€nz€€
€€t€€a;€€K€m€m€d5vXЅ€€GZ€€bÂ€Ê Â€+4c8Co.€€'€€hP€<€]€ €%€A5o€ _/qִ€v€€€I€.€€€c€c€€€€!_k €€€c€NQ€诋@€?€€xV;€1-ü€+UU4<€€p€-0&j€U€€C€€€€m€€€€€€€€s€€€#:€%3^Z€o r€€€€`€2€h4j€GԞ€#€_һ€€€€€€€€€u€\€۱€€ €(€(jÅ®}€€qH€p"€€€webtailfile.unix_b€€€€€€TEXTMPS €m5"€m5" €P€€@*Index.
!! SpiderWEB €ourcG€ +€^€€€€€Q€€Q€+ճ€
penelope.unixA€€€$€€€€€€€€€€€€€€€0#€
a.spider.unixnix€€€G(€GTEXTMPS €m5€m5,€€(?j
€O€€€€G€[€€€E€€>€€€fI€€?€E€€M€€V€€€€F€z€€>A?b€€€A€+€€€N€€€d€€€€€&cN€Jn€€€;€H€€$3€€€g€€€X|€€€€ĉ€j€-€€€)ĉJ€L€€8LS€2S€€?h€S"O€/€:IA€I€S€ +€c€€€€N€"€€d€h[€J€~*q€€€€?y€€€€€P€X&*ʄ$€€t2vB
r9P€ЗB€€T€B€€€t€€€€ €r€€€s€€U?€)€l€€A€€€€€ш€€€R€|€€€'€€€€€|€€0€€3€^€SC€€€€ZvF\^€Y&€]q}]0€€q€z!o€`F€€€Æ€@€€€Ld€€Ò!€€O€JS1FÂœL€€H>T€@%€C€H€Td#9€)€€€ޚ€dY€sE€37j3X€@€€ +€€'i€iq€€3q@p8€€€€X€q€r_€€j4RK<7v€€Pe€P€€f€#€Ra0 +2€&€€€"€do€€ň€!۪€t€w{P€€c€€=€k€€€€`y€€ t€€ۮ€€€€q€€€€€€€s+€€[€€F€€}1O€̑/6€ddS€{€€oau€'€€€€>F&€€H€b€cv€U€͵:€$€€€qxR|€€LK€s€€s]€=l"^€qc€€<L0 /€Wr>€oi€€€[€€'+€€€7k€€ٔ€€_({*,€8Xx15€€€€#€9€4YG|-€€€և€m!€lР€€€€Q€s€-€€6S€U€€Йo?€€+v€€v€€L€5 +€.i€ï€€€€€|€sÚ€s,ʲ€€L€S€€€€€€S€b€€
€€Tl€€D{K4Ŀ€€+("GP€o€I"€+Z€v€€l€€€€€€"Ob€",=4X€€D$€€}€€80€€Zx€v€L€€€ €V€€5#€t€SÂ€Â€Â€Ø _€€~€€i€€€aBÝ¥_€€€@€€€_€€`€ۼ€€€W€Z€€H%€€p€5h€{€€2€€€~;:€M€€€$ڼ€ +h€B€€€PcO ,=̱8€q€ԋccS€€€€€M€€€:€€W€o€&€:ip€€%€)€€U€€€€€€€.€q"€€싓€€[r~k€€€€ޥ€Dv.€aC€€܀€&&€€€ÅV€€€P€€€€€€€4€€€€€€l€8I€€bR€46Ҽ€€€€€L€q€y€€c€}€€€!Ò¹Xzh€€€€Bz€($€C€€€€kb:21€ؗv€€€u&[h{€n<8€՛€=Q€<UJ€T€ €€j€€TQ
qiM€€G€€€€€=rMWÙµMD€\€€€€'€€2€€€-s€€( +.€u€!€€€C€€c€€€y/€XR€€X?€m€L&€`€€€€€<t€)€;€Y€€kV€`€rÚ€€€€€6€f€ €LV€5€e€€vA€€N€€€KÔšÍ0€twY34€Y€k>€`€rgn€€j€[A[_€=€€~€XN€Ҭ#€€+€q€€€}€€€+€€€€€€€G>O€€€€[\€por€€Q€€€€€\€Q€€.Ý ?€C€€P€d€͈€g€€Ҽ€aL]€€€€€ٵQ€͓K>V#€€{€€€z-L€€ɾ€z
€;€tÚ¸p€€͔Rx|t€?€\€d€€€EÕ’n€@€€€ȸa€€f €+v2€€;€€$€€ €m€€`€C€€€@€2€€,€€€&€=0V€€€÷€z€€€€€c€,7€€FwK€€AHc€EM€|€W€w€€BM€€€ ٜ€€\€€t0/€ז€g€€_€€T€€€]€&€€ç€€\€€€܌€€>€€W€T€€T€y€€~€u€g€€.€R€€€W^€f{ä¿}€s>Po€ީm€N€€€€_€€€9 €€j€€€YM€€ gi€€€{€€e€>€I€€t9r&€€J{€€€€€€n€€U€€?0€€€L€rN€UÒ€V€€u€Ku%_€4€̄€€ǥ€j€€-髳€ST€€[
€€€€JyN9€€a€_€iTig~€€€€€72nI€E€€€€€€>€X€€l,€6f,€갩:€€4s€€ǘ€`3>7P^€€€%€€€}€€C#€
Ҵ€*9€€X€€€A€y€€qy;€€x€F€€€€€€€€€€N€€€€ls0€€€Ao2R^I*U€i6Mc€#€€ €€J|€D€€€€ߖ€/€@€mfͬ€v€€€ €€€€€€"^€{€€mV€€q€R,€w€€€ݗ€!;€t4]€€k€€€€!€€€}€€}€€€aI€ €€ +>)€Uκ€€€€€€ €r€m€€'€€R€uR-(€붳€€3€€P€€€€€W€eӘ6€€€€"C~€.?€*@X€€o€€€i€€€€z€4€€€€#_ /[€€ξ€qݒ€=€J€+:€€$I€€€)a€€€€}#€€€€€;€€€€€€t]E€€:€M€€€<€9l3sɞ€€Ǫ"f€€7X€V€b€€W€̾0kK€bWm`q€m€€€1L€€€€€€1€.€Ó4€ROF€€\Mw€€(€€i€€P€ €€€€\€€M€€€€€€
"€oi`€€ϒ€€€€€ [€}v€f+E€4)JÍ4O1Ó¨|€€€)€€€K€€}€€tTH:€€<L,"€Kr€€|[r€€8€€l€€ €€€€A€€€87€A-€Y€€€b€€€_F€€Fq€€|€€W)€a€kÌ›t€€€€€լz>5*k€€#)€€€b|ff€u€€Oɕ€ޒ-KtUI7'f€+€€€!€̾y€€7ItZ;0 +€+A
€^€€߶K(€€U€35€€[€€€€c,€n€k4€€(€&0€Z#€DY|ĥ€€€€jud€l€<'W_,€>1€\€€€€Q€€ +srj0r€O=€€C€€簾€€&€AF€€L€€€€[€€W€€?€€զq€F€M€M|v-€€€{G€-€c€€€€/9€+€€Z{€€j€d€€U€3€€(ta€€€€€K\€€E0€€€€n€€t=Ap€(jZ€'€€7€Z€€>`p'€€n€€ +€ +U?k€€€€€€Ƕ€€€u€!€q€€€~€^€"D€€9€5€€>€`€€€€€={74€€w>€€€\ں9ogA\€€€\€{€x)*@0€€€Y€€v]€(€€€C<]€.€]|€€N-X€€a€bD€€€€9€€€€€<€S€_0€€€€o€^b'€€€ |T€f€B€cx€€=v€2+€€}:҆€=SIdi€€€x€Ԝ€M€x€Gd€D€€e€€€€=€,€1p߆€€'}ڹ€w?€€&€d€€lD€X:L€ €€:€-€€€€K€ r€€$W€:€€0qͣ![Kٺ€H$*€€€€ +"€'€ €€'u€€
makeider.unixnix€u€€€GTEXTMPS €m5€m5€€€€€€Q€j*€€!€'€y€€pG€a€;€€ +A€€~ +'€€7€;9€€€>€A€/€y€€€1€>€€€ɴ€€€}€€ty\O&'€}H€ɗ€€|C\m€.€€€€€€€ucw(€€0sj€ủL|€€€9€€€€€Ht
nesting.spiderix!€(€€GTEXTMPS €m5€m5€E€j€ +€€ €<€#€^€€€€(9JVrt@€EV€€%€€€€^€€4`k€€Q€~€z€K %€P€&9J€Q2€dDɀ€€G(9JVB{€€\€&€€€x€€8l€€b_h€€.€b
€a€t@€€€Lp,€€€€€e€ S€!F€€€7€€€l€€zNR€`O06€:€5F&'4€€€€ӳn€#LN{€C€i€G€€€p[€+ll€€F€l€E€€z€€ +d€U€€€0€€€€€_€ܶ€f[€€k€J€l1,I0v€Ha[€k€€T€€2u',€iW€i€€€€jN€€/I€€€€€€~<O€O€^5€€Fܢ€€€€€O€7€G€€€€€
processed-a.spider€€€€GTEXTMPS €m5€m5;Q
IC€Qc
€O€€€€€u€?€€€>€€€f€€-€Oh€}d€g€r|€€€€€€€z€€'€G,P€5€=j)[/€€-€I€€€[€€ߒ€€M€<€+€U€I/@G€€€4€€€€€€€{€€ީ€XE#'€€(€€€€€4€€/c€D€C€Ǫ€9€€€€€L€€i,]1P€€2€0€B€X€€?€€€H +/€€I<€€XJ1€|)v?€€€€€€€3€Er(E€D2H€€E€€€€€€€`€:C)v\G€g€bH€€X€€€€0€€€€rS€q€€<)€d€€A€-€€F#R֓CH€t€€€€€€€€m!W€€€i€€~€bMe€€dvF€€€I"€]qq€1€ܲ€€R€ +€V€€͕€m˂'€€DN€€€yw€} +d€S$€Jԑ€€B€7€d$€H€€`€€l€€€€a€Qo€D€€€€ +€€€€O €i€Lc€€€H€8Qё8€ €€tLd€€0€€€b9€j€€€;͢/{ߎ€€<g€#>€€7€e&€€€€Nd€ض3 +GM€V€€€
€N€€k€€T€€€€€€€€*€€+7€m{}€€¤€nfIw)f€Z€€װ€t€€€4yG~€€'#€r;#ݼָu
+€]€€€Ds€€€€]5 +U€€€€€4€€€(R'€€€€<€uf€€€€€€€€n€,j€/€€€€€V!€í†Â€Â€Â€Â€}I€pA€yI€ђl€€l€F€€wz€Ͻؾ€bl€€1%Fz#rL€€€€€€?€i}X]"€z4€€8`t€9€-1€VkS€U€€Йn?€€+f€€v€€€€€ +v€h€€/€㦫€t€€,Ú€c,€NOE€€€#€<€€#Y€c€bÖ‡5€ߗ€&#՟€!€€,€_@9€€€€"€tA€€€€=€€͗€€€F+w€€€`€",}€€*€€€s€€€€d€p€€€€€€'€€
€d+W1ҋ€8€+€€%€d`oP€M€€A&€P€€€g4h€0€€€-€Cw€€4€€€f€€2€€€g8€€h€{€\€I@c€€€[€uM€D€K€€€L€€€'€>L€8€q5Ӌccc€€€€€t€f€:H€Wi€€€:€*€q€€E€)€€E€€€€€l€0r€€€€#€€r€€0€€tS3xg#€3€p€€€€ +€0€€ԟ€h[€ZҒ4҃€9€Y[€€-'€ł€M€/€F€€€€p€0qb€€€<€€1€>l€]€ҹX€PcoDӅt=€$чK€€€tdb|€b€€QW€ת€€€,Z€xp€+7€€€y€€N€€^@gՒ€€/j€ܚf€ώbw€€€€€5^e€6s€{€€Oz€e<3€[€R%Qd\f€zI€
4€m€€€€€€y#+[R€.[o€6[&€€Zg|€6€%€i€€s€€ᒕ(€+€vK.€`.€€-€T€<Պ€$3,€€,_€)€€r€Z€i€€.Kƌ€9€€c€G̕€€u€€OTb€h€€€w€€G.€€€+€€1€ȸ"€ +i€€€F (p0€{oW€$X€€€€y€€€€*€€b€{€€€€€€€ꬎ€€{f{€.€€€€€܌€{€€€€€€€€3€_h=<€c5€€y€€F€€€=ܲQ€A{€€€€5€€R +€v/€€€m€€tq^€€Z€€n€€ €GNX3€€e;€€Ä€V€Ln€€€&hS0€!NRD
€7L€a€p€€uw€U€€h€€€@€93A`€€€€M&€€€.aRcPc%€€€5'€PU€^€]€M€€€eCM€|{m€[€€€€oU€€z€j}€€T<€€€€€€€€§€7J€€R|K€€wk€+€k?s€€Ȗz€k_yy€€€€€€€€€@€&z€€ :€€V€€€€€k€€T€€Ak€qFn"€Y\€€€€ja€O&i=€€€ +€4Wi€`_€hX5€<€W€;€"€€2Ղ?AN€€r€€(€€T`€€€*€€p€€€q)€€€€E€€€1F€&F€€€z€y€Rބ€SNx€0€€€4
*€€?xY€>﵌k€1E€=€€7?€O9f{A=€€€€€:lÊ€?€€€€1€8€L€O4€€l€p€gYz€€€€HC€€m€B€€€-N€€€€€Yղ€€€€t€Z#€ū€})€Ҁj=€x€@€€l€€€`€&€eF€+I€ + "€€€m€zÄ¥)z€ϴ€0Rih=€o3€€u €6€f€p=€€€€€€€€€O"^€{€€MV€€q€R\€€€/€€€!;€€h€€a€r€€€€p7€€€€€Ow€€€€PS€€BqS€,+€€nY€>€€$€€€€€€>/u\€jAF_€€€€1€€€€Ϳ€?€ɛƴ!€€'€€€'t€€€a€ǿaz€CD<Zד€!€€6€y€HGu€€€€€€€F_€€$€€W't€€€*€o€=\o€€€€€`+€e=€)€€€€4AJ~€i€a€€3€8€#€€€€€^aQ€[€€€wSm€€¤-€€]€€M€5€€€O€0E€3<
b€€€1€N<€€€€€€€NpP€€x€9AE€;#€€}€$€€ .>€||€€€:€`€^C€€6[z€€€5€€€€€€€pj€bTKc€4€€€\€€3€ʗ€€€R;€€€€O7€€ +I€Z€€€€€€\€€€5 wl€թ€€ޡt8i€€i€>€djS€ +€€u€)7yã
N€JA€€)"€€Z€€k +#€€rGy"€Z€€W2€8J€€r€€€€€7g€F@€€y€€€K*€€╶€€€€_~€€m@v€€W€€o-0€p€€?:€~`M€€{m€(€U€€~€€km€>€€f€€=€J€M€€Pڛ€+€€€€€k€ji0?(€Ö%€€ڪ€€K€€€€€€-]€€j€€'o€€#Պ€€U€Ek€€v×–^€€=€€6€€Zx€{€€PA€rm€J€€€~€/€m€[€€ +€€.€F;€--€€€v€X[€u€ €.€9w€€%€b€€€€€€€€€€€LG€a€€€Hrr€€E€)W€€€O€}L]€€€€>%@€€€€Y(>h€%€‘/€q€ϓNn€ƕ?>"W€€€-Y3D€€t€q6€̙+€H€€9yY€;ᬦ€DC€a€€€ͻ€€b[)-€€€>€n€€€€k€€€\€Ӆ২€U€€'{E€€€€k€:2{RwxB€VS0Te€€09%€€⑬*W(j€
FÂ€Â€Ö Â€Â€x€
€}Ì€n€|z #€oq€€\ɋ€€€€q€€€€#€€Okp€7€>€wQn€€G€€€v€€<€€[€€L5€€€)
€_y€€€/€`€€€€€€€FO€#€€<€€?€€€Z\€N€€€€€€Bs€€d\PӸ€€-€€|q€r€€Ø€€€€=€2 ,€c€ +B-€€g€ *€Dh>{€€€Go@/€€*W€w׃€€ݡ€€€€޻€gS€€€v€€%Y€K]xd€r2 cL:€:€€l€ΒY€e€€€€û€?€J1€⽳L€€€e€€$hS€€c€€€€P€aL€€R€>q€€3le€y€€€/e€Z!G€€€€€\€€"€P&"€x€€E€€)€#€€€€H€€€€=€€}2€R9€"€6€€€€$*€n€€€€J_[€€€€$€d€€LD€€€t€TrGæ•Â€4C]5p€
~G€(€x€€*'€€k€€€€€PD"€! +\O!/€}b€3s€{8€
scan_annotations.awkne€€GTEXTMPS €m5€m5€€9 +NW€x€ €€ȯ€$€ad€~}r€€€z€€€€€P€€|€$k€#€է€A€P€€ؓ#€LA{2[ €<€€€2x€€J€᷄€d€€!7€Xr€ʹ€€€x€€ы€n€.J€€€̻€€B€€jO€i7€w +q€F)€€z€Tx€+€
8€|M;%5€a>€€(U€1€Ks +€v1€]€€p9€€\XG€L€€€€€f]Gb€`€€;€€m€"€.€€6*€€"€€€=F€S€€3€!€8€5€+-J"€"5€tOv€€€Kt€€<"€€a^€S€)€OuÏšD€€P̧6n€LÞ^€q@€*A7€€€€€i€Pj€
i€<erk€"=ŘN€-3€€\€PJ€€€€€€€2=€B€ €€/q€_kjt/€kc1€<}€€9€apu€[8€€B€ѦD\€€€€€€H€G€€€7€K€€€=€€'1d€g€CAM_€)d€€€ٱ{€€aU€€z€M€€U€J€€€€€€€z€€€ѯxHv€׮'Kم€€€|€€~€€€Psթ€€M€7€s€€€c€j€&€€€€tA˿GM0€€€v€€€מ6€w€
SpiderMakefilens.awkZ€€€GTEXTMPS €m5€m5€uzl€Q€€€€€E€€€}^€;9€€€>$€€ܑ€ɧ€]€@€€€r€B€€€€€€h@€D^@€€.M€€\€€x€,€€€ڰ€€CڤZ€€€€C€€$€€€ €€€€€0€|^€€1X€p?
+stacks.webfilens.awkĪ$j€GTEXTMPS €m5€m51R€Z€
N)y<A'LN€€€'€8€M€ZY€6%l€€,€=€%€WN€X
`}€€€8ގ€VN€€€€@}€€M:?€4€€€€'€€h€€6#€€€€€;6€€€9€€€€2In€(€€€€w€€€p4N€€€nÂ€ç ›Â€lP€qV€fs€€w€z€D€(€y€&€ls3€€Q2)r€€€7€a€>€€€L€€m€Y€€€A€€€[7>:<€V€€(7cuc€zh€€€€€;€€€€€Y€€€€.€€€6€`B_€€h€€l€€YG€€€€€Ml7€€€\gY:€(€€€€€€I€€P=€u€D}€€€Q€~€€<€€V€Uy€€€$6c\€€tҧ€I€(`€€t€)ey€€|€DNj€€€f€€€€p€€LG€€€€q"o€€€Ԩ€~€-€€€€€*€j'&€3€Y}€€€€ n@€€€L€9€€N@€€€I€Qdf€€€*J@&€€€€O%€€,T€€€!o €f€.x€F€rÅ‹90Ý¿jk€I€3€F€€€€€€€€€ɀ~€€:€_+TX€^"€M€€€i€Jy:€
€€€z€J3`€€X€€؟€ue€€€<K€Ehj€+BXa€9€K€€`N€6€@M3€s€ͼw€€€8€€€€+€lW€€€€6șC(Y€€€€K€tZ]S€B=€S€3€еB0€F€Q€4ʽ€,.€€€€€]€v٨])f5€€€ c" €ϰ)4€€15€€€€asf7€n€€€€€€€€€mE€€ئ5€F€€€@€R4Q€,:€{P€l€,k﫽€O€S€HP€M€hڋ€!€€B&4€€0:0€€€¢,e€€ͩ€€€uhC€€
€€-€€pT€7€€€€W€€€XRt9Â€Â€Â€Â€Â€Ô Â€!€€i€LҤ€€#€€€€,€€€€ J0€€€Mfp€6€€€$€pF€€€€0€12€€€€€€w1,€€€{R€€€€X€€W€e/Mc€€i7€€€€€€€p€€€v€€F€*5sv€€€I€€h[%:/2€€€€€€ܩ<€> +V€€K€€€a€€`€€_€j€€€8\ĺ*`€€€6€Kh&€€€Q€€(cÆ“|€XN€€(€ӫ€€€€r€€€€€x€€€€€_7)€(€€€€߷€€€€€€€€€}tÑš]7€€NÞ #€Ou€sv€€f[€€€\Ú Â€Â€tRc€o€€ €B€"€1\ÐŽ_€ʟ#u€R€a€;€M€U€Sd€€ܜ"€DyÇ©#Cğ€|d€N18<8'€|€-z€v>€€€€BA€.€€f€€€@m€-A€ي(H€h+XkNi€Y€j!€<!€#X€+7€€ܽ€€ޞ_I€€€W€€€€G€
€€€|€T€€^f4<EP€a€-€€D&€k€7€7a€€€
€€{€k€Z€€@€€Db5€€€|f5w€ë‘$€ €€U€I€:˸€)r€-€€€€€?€~€€]€€En€
€]P€tί€€€dpyd
T€ +q"€€`€€€x€x€€€€t€€€ v€€€U€CN€€[€€rW€€€€{€Y& €€i€€.€€€R€€ec€€€-b€^- €r€M€€y'€€a€^€r€€!€€0M€€€#€€€a4r€€S€€€[m€.€U€A€€€EezF1€1€€A€D +Wq€€€€€=€€y}€€€W€€qIE%€€Q€X€€lk€€€4€€0€'€€@€€"€t€&k€ܔsc,p&€S"€€D €z)€To€€€
€€€€€€€(€€€€€€€€Xdi1€€,i€y€I#€-€€9}€i€€QK€€€€€€xYe€,^X€H€€€̀ӟ)@€i€ 'VB€€<€€€n +O€y7֗€w6M€o'A€€*耶0€K€€K€B€X€.€€€\€Q€ؽ€ 66€k€Lg]ydl€€ؼo€€€€€t€€€€OQ€Q€Tx€~D€€ €€ +€€Ox€9*
€€H€€€!€€8Ta€€q€/€€€€€€€C€€L€\y€€€8€;wâ/[ë¶Â€p[€5?€\€@€€€~W=l +K€EVÆ€€€?ȉ€7&K€€€9€Ne/_€p€lwD€€€3?'€'€€|pA€V€€€N€@Q%€€€€€€g€Q€€€le€€€GN4,î¯Â€Â€Â€Â€g€€€€7$ %fK€€€l€€{€€€€]9€€€€A€ S€€€€€€€€r€*zTd€ڼ€@€GJ u !b€€(Û]€€I€e€€<:€_c8€iv€XͰ€!€€€,€€€l€€€€N€€,WA€=€:€€m€s€zJ€,€LEN€€eq€J€'€_€&G€€€€}€|€€€&v€엖€€7"€€YO€€\n>St(K€dV€!€r€0!€€€€"€€€€€^€UÈ‘-€~K6pMȳ€f€`€€&€hCC}€€€€€GtIW€|S>?€€€[#;€€#*u€€eH€€€€€G€͵€ή€€3€€€€qR,€€l€€€€/3€€€€€€j€R€€€€3 €€"F€]€€~Rq€pl€€kTdۓA€€&€j|€€€€:€€€€€€JY€sf4ACw€€8€€c€T],€€FÖewA€€R€S€qa€€.€€)-Sz1€€m-l€H€€_€€k€€€꬚W€E"€Z€F€
€€t€c(<Uq"ȽDR€nb-IP€RcW€ѕ€s€3€€€.)€ t€€jUQ
l€ €)€^€€z€V€ٰ%€g€/LI€r€€b€U1€€p€ "€€€\9/€€,_sX D€€?€4A3'€"€€€€€€kq€s€|€€€{_€€€€€+€€€?€€W(~C€6€€€€€€€xnQÎ~{€€'€v€€:"€9€€€€€7)W€€€€€€^€€2€€[\€\KP€y€+O&CÊ€4)e €€€€€!€%€k€U€K€€€€€€z€€W€E€d€,-€€1y€(yBuD]Q€i H€?FI€€€D€€€D€€N€M_€a€8€€)o€€݃^€€€€b€€€€ R€€N!J€ji€€oG€€0d{€!€[>€N€€8€f/€"€Ób€JyC€~€€€׆€l>€7€€€DD€€€€€K 8€€I€€J€€€_€E=€s€€])€€€9€7€1j€€5€5n€[€€€x€€e€€( €€€€€A€€€jd3_€RA[€]€€€j€€€N y€Z€€€-€YP€€OZX€€€€K@y€€€€€€9€8X€%€€€€0#zU€þ€8€€€€€€ϰ€€XO-€1€€Q€hIh€q€[J*HX€_€qo€AE@€€€)€€_{€8€€€ca€€€'!)€€€€€|€I€€y}€€Xƅ€}€€€}€€ €5€€N~€E€€€$€€s€€B€€ކ€Lj€€€vj€€€€€€xGb€O#€2Ge€E€AZ,\€€€€3uO.2e€€€>€fK€€)€>€84€j9Ac €€v€0€-€€€ €€!T€dau€€€,€HN€9€1Q€€/=€60י€p`€€ڑ€€€€t6€€+€€*T€#-€€s(MU€3D€
€€€€`€.,€€€g€€€)€e€~Y€W€T€€€^€Btv)€)P/€W8D€ؚ€€d€3€"€€)€€˟€€K,J€€ra€Y٪€€€t)j€€€€€.€,€ۇ[?€:x€1c€€3=]JP€{€@€G€s^?€P!€€€*€ -%€€9€KS.€€O€€€€€xLg @€֗€€€€€8 z1@>A€}X€*1€€€€€€#TQ%u€N€€€€~€€߮z€/€€=€_XP€€€"Z€|€ <€€€€P€Y€r€€ʜ,!€€yp€€<€p€ (ÅW€€VA€b€y^€€€4=€Ï€€€z0ɸ€€€€€ВG €€I€0€€€€Ҽ&qʬ3n€€^2\€Sg€€€€€€=O!2€€#Ov€~€€€ъS€€`€€J€aYa +Ҍ€€Cu€Wm€€€€yW€L€€€€€€€lu€€8a/€€€€€S€0[€㩨Q€.€-€€Du^€€€N€€€'-€-€€`e€€1€>€€€€€ml€€€€^_€8€€€€€ +€
z€€€€/W!€€ÜPP€€?€)pq€€€R!€€€SnqJ~€<€ν€<,€€1.D€s€)€€0€c€€>[€€z€,€nf€ +€€€€8€€h€!! SpiderWEB €ourcG€ +€€G€€€Q€€Q6-f€b
README.webfilens.awk€€G-€€€€€€TEXTMPS €m5€€B€€€Uӗ€€yG€vbU€($€#€€€dD€€4=€nG€€H€OήI €€€€<€€PRÏ?€€€X:l€€#€€ޗQ/@€C€€G€€€8€DIJD€tH +€an€€UiB€€&+€€| e€eK$Sr1€€€d€ €>Y€€U€}€l€€:E€€V€€LjÖ®W€J€€€
€€€€g€€i€€m4€e€*[me€u:€€€€sFR€>0€€€€,Ì—9€€€`€€€€,>€#€€L蛟€€€€ֵA€€€np€h€\M€ c€̹~€т€€€RNW€€€7€5 [€OOÛ”Fn€€͢€]z€>€mɈ€€€€€ym€€~€€€h€€€€€€€>r[€€€€OÏ·n€hc€€€€DM€Qd}€€9€€lm€@€߬€.64€€v€gjC4X€ €€€OJ€C€i€€L€€$€vPnա€ԯkM€C€dRg*€€€ߜ^_\€^\~X€'€PB>@P€€€kg+ll€€ߋN쌫BkØ»>€€LpFm€1€@€$€c€`}€B2€€w,€#€€€€dmLKX€B%€€W?__€€€v€€€€€l+€€]€€€4€-€€€€€)€€€€€€€€`Æ®//Y€€€}Ö±Æ¦íº—p€€q
T€€€=€€€€
%€bg€+L,€z€€€€~+€`5€N€€/ $€k25;`€?€;΀€€€s€1{[&€€~€~€€€€526€€€ €€y€`€>€€3i€€Ǔ€€˛_€{€€€l€bH€€€t€9s€f€3€€S€]€€;€GB€ء2.€jV$€#v}€€€€(€€qP€€€€B€+€c€;€€{€€€r1€1N€/X€€I~€€€€BU€€€€b€F€.€(€o€@Sj€sl@€€혡€€7€€€Y_€+€€€O€%€€m€N€€L€s€€t€@€€€]€€>r€N€€;#€ABe€€^e€e €€>XL€€€€€€€€€m€€€~€'€>€€€€u€€€€€|:S€€ݕ€€€Z'€5`z€m)€m€€8€Z0€>q€f>€e)^h€d€Sa"€QV1M€€S€€€Vl +€€`€€€/LAՒ€€p;€p9€N€ >%`€€k:X€o€i1'€€/,{x€€€X̡€€B€€€€€1€€S€€€G€€€A€PԮѼ +V€)f,€L,g€r€z€€h€€€€F€€"L{L€'Èœ>€$,s3€€€€E€3€€€€€#€p€€€€€€€€%m€FA€TA8€%€€uy.€/€qq€M€+€L€€}5챃€=€%E(F<qm€€SQ :-€h-€#I€€€o€€€15G-€€€€€€61€6\€ {^€@cJx*€Io€T+g€€OjÅh€€€€U5iM-€€€€S€Z€;IO2n~€ĺ€{*\€.€YoѢ€a€€€€A1€h€€9€€V€€€~€€€%@:€€€€€€yU€€€€€\\€€€€€8JÛ€޸€Yɾ.€@<€€pd_ÑŽj€€?€lKЋ*€€€€€ 6Jx€€€€?€€hct€€b_[€Y8;€€\"€ÂJ€€€[€;z€5 €€€€€€€L€qH€R€ֳ€I€€€€€€€>€>փ€€€€JT5€€C€l]€\5' U={6€€>{€B€Lf€€€yM€tm`€€€_€€€€:m€€€-l€€€b€[€€>€q€nX(Ƿ€€€&€€'€i€k<€€˂€€€g3€;5€€€€€z€<B€\€;€$€ΰ€€€<d€Y€€H€GN0>s€€€€€Q)€€€g€8|€€€+€€€€ؿ€€€P5€€ܞk€VvS€5€€€€€€X6€RV@€ʑ€€€€€›€C&€€r€€€€A€d8€€'Þ¾?€€€€a€€€€m€#j{oG€U€€€€ €€€€W€€g2ܪ€5rKB4€€€€€@€€XYJ€g7€€&_F€€€€€€€p€€f-q€€gER[€{ƹ€€€€€€n€€"€€€€€€€z'%]h€€?€€*rÇ€=€€€€W€€€€€€C W€€€tL&€€X€€G€n€8€€€BDEè·¨g€C€€€€€€d€€€{€€e€ńVۖ]+q€€Z€aG€FsI€€K€K]`€Q€€€*€€€(A€€'?6HRW€q€€~ +Ò¿|€€€(€€€Â€FI.€Es&€€€€€€€}`€z€€m2€:3L#F0€:
-z컩€A€€Ք0€,€€˃zqD€€€=7AÊK€€€€€OXc€€€€˗€€C€7€€|€×€€[€L× Â€Â€w€€~€€ۣWÏ€^€z€€
+README.MPWfilens.awk€$€3r€TEXTMPS €€B€€€P€€€Y€€€€€,€vbl€€€4L€
€€€€s€€- +€헧kRB€?€€€€€q€€€! €)€€€€€€V€€€€i}b!V€€3rC€(t~€uz€€W€{'g€€'sh€€€€€ €€€€g€0fi=Y€3€€€~n€ug€€Crw€(€€8-€€y&u€€€€v\!JÂŽI€€3€€!€$€L€€SÂ€È Â€R&€€€€L€ 1€*€=€f€€€8€€1?€i€€€€€t&€€€€Q€€(€€€€€€ €LQjV?€hAhpF] +N)y€`€r€€$T€g€€€€_€€€€€€€E('€8Ȁ€)€y€€€;~€Tq€0N€p€aN€ro=€€€4:~$ݱ€Yr5€;]€€Y|€€y:€€€Rl€f]g€Υ€6€€Хw[/ۖ€×n€€
€€ +13€ZW€ZsE€6€€wL%€€€s`€ՔX#€'mG€ҞUt^€s€€Z€€€Ф€€€M€|€ce€€€€€€€€5€iEÑ¡ZgddR€€[\€q1~ˡ€4€€΅€Kŀ€zI'$mE'€€Bl€|€€€€€A€ɔ€Q€C€€ki€€$€,€€€b +€€€yL$€€AȪ€€I€€€€[€€W€€€€€€'€€€€a€CXtF€J€€€€€€d€€}p@€p€€J€€€€=€S€C€{3e€+e€€€€€€€€€€&€<Hï¥@K€>+€%_\€€€€€A€€€€€t€N'B€L€€€#db€'b€s%5€%5(EF€€€@K€b€€!€€cmÂ!#P€9€€{€€E€2€`H€€.ȪPΦ\€S€p€€€ʈ€€€€֬€vK€€€y1€!€€]€+€ +€€>€€€€wSh€lߖ€+}€Ŷ€f€€€€€,€€p€ԇ܄€€€€{€€€€ €€{€|c€2(€L€-Ó€€J€K9€jXB€O€€€È€€s€€€^€€€€€€Y€€ҙ€׉€€۬€q8d€€KʵZ€€]7€r€€W€€€€€]€tf0€€J茦L€€€Ä€Y^€7€€P€€2€ +€?€A€€>€€€€€ +€i€L€€B€i€€€l€Vo€ϵ5Ø -Û¬K€#€S㥆Mq€€v€€€€]2€€H€4y8€€g6P€€€€v€€ +7€€€€0€€€q0€€c€K€Zp€w=)€€e€P€8€ҩ€€l€€.€€€€rÄ Â€*€€€O€敔w€e!Æ„G€^€€s€̹€€€€€€l>_n€€€m..€ִZ,€€y€€#€€O€€€€\€e€€T€€۳€?€%€€€€€€€€ܛ€€€€€€&€Ӈ€VE€€T
€€g€€#&€l€z€z€v€o*Ź>€€€€€€f-ĥK€v€€€€€6G!4€E€€€€q€ ϱ€€}€b€BA)€€k€ނ&(€Hdz€2€€€€7€€€_^€F€€€r€iqu6[€€€€€€€k€€o€W?€€-J}€€€€g€C€\pl~G€B€ ssl.unix€z-€>(€3€€€€€€€€€€€j +F€€
makeunixPWfilens.awk@3r4€3rTEXTMPS €m5€m5m]€€j€Q€tH€€€€<$'€€>€€€K€€€€€€€€€€€al€€€r8€€€݅€€€€€€Z[€€€€€$L€uI`€sG| €a6€€€€a€€€!P[*€
s.spiderPWfilens.awk €3€=€3rTEXTMPS €m5€m5€€t€1N7y<A[/€€ݦ֖€€ܖ€f[B€€9v^€^€€&€€JV€€€€cx;€€u€€&€G+P}€><€|€m€fE~€€d€€G€€€€@€€€C€€€`r€€€€€ͷl4c€2€x€Ny€€l€€€3€€T(€S€€}€€€€ €t€[€F€€J€l,S€$I€&R €d€€€;€#€ +€€€x€x€)!€8;<y€€€€^€€e€€%<q€€ ^&ә€x€€€`g€*€€H€€€€XA +S*t€
U0€Y€q<E$`$&P€€<{€0€€€€Yg€8€€<€X€€X€€€:`€€<J€€u2y!b€€€(€€€~0Dɒ€p€y4jx€ )€€€4bQq€;Dd€€€€€">C€>
€€D€ܗC%€€v€€€€݉€€#vA€/€k€€€_T€FA,€U€€5Ч€O-€ٽ€~€€€€AE2I>€€<€€w€a€`|U€}€€0<€€€€{€C€€x€wC€€€7%€A€>@I€€€s€iپjپj€s€0€€€X€€CѺ€€€€h€0€€ €€(W€@€€"€€ú€?€€€€€ؘ€€}€F#€€<€*OE€J€€€P€€b€*€y€B)/€yQ€€€>€€€]€W€€€ €KfaS_%€€N€€€_€€mW€2E€€\€(€ޅ€=€p^€s€€€€€€€M€€%€€€€j€€€F€N
€U€-€€€€-j€!€€€€€€l€€ +€#€|UÂ€Â€Â€Â€Â€Â€Â€í³˜G%€
€€€
€€€€7€€}€€X€€€њv€Ҋ€€h€ִ€Z€C€o€€€&€€4€2€ܮi€€€€
mĹNn€€€€€€€=€€€€e€€^€€&€{{€ח€(C]*+€€€€€6€hv?€ € +?<|€€=€YNĽT*sX8.€T€€€sW€.€€€+€9{9wé¸Â€Â€Â€-PP4€n€€€€€HE8w3Y€հ€€hP€^€€p}€Q€p€'€W€.
€0€O€]€X~€KB€€€w€€€€Xq00G8€E€€€P€€€€€KxU€z,c€€€€ۗ8€€}€€€Ï€畎€€€€€€Z€€Q €jM€FS€^)*`€z 6€€v€€€€I~€€€-$€A܃"€'"S~uE€€dc€KS€€(€€€€Eç¡LD€€ᅾ€aZ€€€2€W@€€€€ +€j`€1€I=T€€L{2€z€h€€JA4V^€FQN€€Mm/q€e€€€8€إ0€€€€€^#€€€TH/€€€€¶€ce4€o€€c"€6€€H€€؃6€9€c€€Fc€€a€€wn€€€€€€m{€<€€H€X}\€M€6#€M€€€̆€@€f€€€€(€@?B€<€€
^ƨ€8x$€.€€PJ>[€uh€ €킛€€y{
€r€UX€7€€€€5xf|€€€%€€€l ى{€5n-€l}M€€
€|c]6K€{
€€Acˋ€vws€€>€2€€€€!€€€€€€f{v€ٙ€€a €€s€F€€I€€€,€€D{€€%>,y€€])€Z€€rٟ€!€w€l€€€t€€€€꩙&€P€h&S0€(€€j€€€€p+}bQy#€-€€€c€€k€€€€€L€>€€<kS€ÉB*€)D€€J€€E€€^€h€`€ǘb€€€{€€€€€€€€€߿`€-Ik€@€+€@Ul€€XX€No]€€€€€€s€€€>€C%Cj춚e€p€D%D€{€ڤ€€XN€€*€x"s€N€w~€?к€'€€BÚµ €€€aMKh€YM€ڻ€€€*O€€€c€€ӗ4€i€€€ €ɔ€t)Ei€r€€1€1KÛ Â€Â€+€€E€€*€Qĥ€€€€lnP€€€k:€€\€€€€m€%Óƒ €€Y€€€€c;€kJ€€qp€ +
€Zr€€|64A€€€Wce€r€€ǥ€€z€€, <€DB€*€6}€€hM€7<€Y€БcSw*:n€€€Jh€€foY€€€€€zU€UvM€€€Z?i€€€,€€-Zm€€r*€€uH€€av€€€#d l€€€Tu[€l€%Nr€\Mz€€*€#€e€€M +€7`€_9€€€€€€onU€Jŷ€Ƕ)€€€€K€€€€'Uc€p€€"€€€€€€6}=€€ŋ€2-€€oj,@-pN€x€€€€€kf_€-€aƄ€€&s>€]`€8€€o`sZ€€^€€€€€€˘aHň€96+n€L€+FU:r€?yDbL€€€KI€€]Ën€€z€Nk{J€f€€D€G
€n€m€
Z.€€B€€€EN€€€€Я<k€k!€€("€{՛€ €*e€Of€|€€rc€S€e$€3€€U^€04€qL€€€0€€J€%,€*€€#€€y€€€€€`€€€€€€!! SpiderWEB €ourcG€ +4€3r€€€Q€€Ql`€H€
webkernel.texens.awkʱ3rT€€€€€€TEXTMPS €m5€m59€Q€p€€
N)yJ€€o€€€€P€l[€J€€€€€€.€:€€Y€3€€€€€
€59A?Z€€뺾I€Wqr€€€B€€€r€r€€€r€€€€€€`€<€F€y€€€€€€€l:€f/ˇaj^€€ž€€g€€€[€0€f€(€(K[,€€€€t€€kzYnr€d4€GYa€€€)€<€€0Ë€S€€e€€k€€€€€ĚϞ€€€_,/€€-€Q€€0€€a€k{€€ќC[a€Nn>€@€€͛7€€€€€€€I€9€€S€a€
€€€Q€ӷ€€M%V€fÂ€Â€Â€Û Â€)3€€€€ã½Â€Â€W€€=€i8€€€€#Krx€€1€€€€€|€€€€€€€~z€€<€Ov€€Ҭ€(€{'N€€€€€€$ €€€r€€€€Ľ€8+€€
€€^€v9€yq€€€€gl4€s€€€)€€q€?€€4ܹ-A€€-€€M
€€€<
€€€iצ€€b€P€€DF€Y€%8€€€yQ€€U€^€WjF>lG€€37RD€QsS€€€l€M€€€R€ebe€€dx€€bW€(€€6P€€
€!€"V€>€€€O(€€€€-q:€€$*€€'Ȏ€€O€M€€€€ €C€€+t-€€5€€€€€€€€)€€@- +€-E7€€%q€€€|€€աN4€`€Y7<€€€QX€`€€A€€€€|€€0?€G€€vr€
zq€€€q€2€€8€n€8€€€q\€€€oG€vlÎÏ¢2s€€€€jì¡Â€[/€
A1 +#€cDk€<€~C7€€Z€€€€
3Â€Ò Â€Â€L€€€€&8€y€€€m€€)8€aG€7€$,-€^lsh€9{w€J€€"€€Ԯ€I€€l€I€€€j&TÄ…9O€€O€€3'"A€€:€€ €€€k€q€w>€R€x€)<€i9E€€€}€F€E€F€€€%7€€€€€Dm€O€€}€\€€<€H€?n€`€}€€€z€e€€€EO€u€€€€€€Hp€}€€€€<€Ñw~h/y€B€€}x€€€v€€K€€€pڎ€%b݄€€€'aP€€
€3]€ЊB€€Tw€\€R]€fI€€^-Zգl€՛^S€€€€€.€c€€2€€3€ݯ
$U€g1t"7€AX€:Fq€€€€F<€0|5€r€)a€h€€lh€ׯ€p.a€f+x€€€€ar€€€ +€€
€P€9+&k€€/€} + €€f€€wp€;€욧/€€€€G€€vM€€€€€€€€s€x€|€kv€€€/€€€?€€€€€ᆋq€g`€\€€€666€€€)€IxR€€€~€ €}€ ˂€~Ƹq€ Ú¨uz€€€#€䔀€€€&€d€€+€€E€€€>6€jo€€€}€€€U1€'_O*y€€j€<|€€€€<€€>€€\€bqÙ–\€€€€€€€€7€€€7€€"€$€€[!€€8x<~~€€Վ€€€€B€€€€B€€€і€[[HN€XG€0€E€ ,pt€€€׫g€€€[W€€€`w€€GP Xm€d€D€€$C€$"€]—€Z€€ €€€+>4€€ €€܆€€"€0€€r€)4\€€€€!€*€+A€Xq€Y€€w€R)$x€€€$€€Iv€€€€:€€€€€qˀ€Lµ4C€€€€>\€޼X€ K€/Þ¢ €FȾ€€€€ܔ€€€€M€rH€q €€P €€*=€€$€-€€ע0;w€€€u €€ +[Z€C€€^b€B€;€|€€€o€f€€€€€€€€€€€{@€€€0€€O€€€€)€€€€)D~W2K€s€APn֥€M€q€P€{€QX_G r€€-u5€k$€€€€p€T!€€Ô€m€€i€€?€i ̼€€€€A€iO9€€a€$€€€€z€h6Z€€_ݨ€€>€xpmY€O(M€€€€€pD€€]€e€€D€€€€١D€ӶߋtI^€€6€€€a€€€qJ€|/€€A3€€€z€€x€€,€7€€d€€€€$Vi'€€€g€€€€X€m€€AL€€€I€€V=€€€R04L€€)€€€F€€€{€ÞZ- Lgx€|i*>€ +g€€€€>'^€@€$Y€_SU:?9€@€€€ €^€€(€d€€€€€`m€€J€€€ή€€6d€Da%€WH€€€€M€/٤€€V}€€€Dv€€}€d€Fa~€€k€\u:€ưDz€i€ Qz€€€`G€G€77e{€€l+ €q%-€D€Z€Q€€؂r͕€€€€o€Ѣ€z€€Q4€€a€U€€e9G€€#€\PJ€yn'€€ْ€kf&€2€X€rj+€€݋O)€i€m€<€€€€€(€€€€)€€$€€€€€€2€Dٗ€€€;5€€?KK €Yr!€О€`i8%€[LM€r€€€€ €M€€€€€€€€€€€€K€ €I€€€p"+=€Ho€€€€€'\€luË›;€€€t€i/E:€ €€€+€€UK€€c|€€J€€€€€€!t_AO€ €6€a€H\$€L€/€|€Y=€€t€׻€€B€€le€€l€L€߅€kn"
{P €€€7ÊŽt€€ €€q€€>T€€€5ے€€y3Z€€€/€€!€vq€€€€€€€€n6F€€€€VzȀ€u€€€€ €€d€F€3€f-€€7)€€€€€€Ѳ€€T%z€€€€momnnr`€€M€€Ѐ€€€€6uʯc€€€€1nsΰ-€€r€€€€xo€€}}€€B+>`€̹€€€€P€8q€€€[€0€.?P€%(r-\#€€zFPB€€€o|€\€€€€€€ +5€:Z€#€€L€€€€ͻ€6€€€€C€€X€€ +€|€O,\fQ€€ +T$99€ €`€€t€z€@€€€]€€€p?€l€€߉€tÄ€€2I^€€@.U-
m€€h +€D€€€{€2€\€u€€€€€€6Ϳ€q0€€€(€<Ge6€7€p€€€[ ƚ€q€€#€U\€€€橞T€€#€w`€€Ul€:*s€€C€€?]v€€€€<€E€Nd€€m€€€€€€A€€€vзTU€%#€4@O€€€ _"€€榹uGNb€C€x܆€}€€€€€€L]€ D€€X'€ R€NI`€]€%/€€€]Z?€€㫎€o€m€f€7:pT€z€€€€{\@g€€=8€>€2€€L
€I|€€€ €€€€i6€€|l€=vR +€ €{2:G€=9€€€jH€€€=:ݺ €€€i€€L€_€€d$€c2a€€€€,!€D€'€{M@$qJ€€€sb€€€€€WGd#:n€8€€€ S!€:xÚ•6€€%r!€x€z€€ €€€€€€€€W$€&€,í»•%€EW€€Ï€€€€€(%;an€€€€€h€€]€€€j€nlOV€€WE€ԓ€q 暶K€$€vG€(€]PQ9€XEv€oX€/€€]€ €Vu€€ެ€.€G€€%`€€zh€€€;6€J€€:<p=6€€€<€€€)€€*€€€€€rwËZ€0A€H€b€4€d5€€ +&€G€`8,€€.ƕ€?04L€y€
€1€3喗€k€€€w€€O䣖€g€€€€v€€srx€_€jY€€€{9jm€NX€€€z[a€€V|%{/€q=€€€o€R€R€L€€x€€€€g/€€<ae(1€8I1C€€:€€€8€ €€K€J€k€€.€€€€~rI€€€€F€€)€€€€`|€Y€H:( +Pa€€€1€<ƔR€W€L€€€\Ԥy0€0?€€€€€€€?"€€€€d€%€! +€J:€%€€[€€ucDC€€ €€€€w6€€€T8€€6€[€b€j€€€o€€6nW€€€€€€€€€€€€!x€
q%€.€%€€€€€€P€€3 €.qӡ@ɧ€€€€c€€j3g€€k€.AQ +€Da)€^p€€lJ€€}€a#Z€9€קRs€€U€֨S€SE€€4€€€u1N€€€`€€#€€i€V€€€AU]€G€€€€€€D#i.€€l€ €"ٸ +€-€/€€'€€Y€€€€€p€€I€$€€J€h€€€€ Q€€€€xd€€€,,՗€€€օ€[`
€€€7€H:€€7Ԏ€"€€΀R€4Т€r€€€€€>€[5€€wr)w€| €2i€\€€P €C€€E9€€XЂ€Y__᜖pn€D€€€Ç>`~€x€€}.€*`€؟€މ€J€ހ€€H€Z€€€w€}W€€€!€€C#€X€8€€h€v€€€ €€€€€€€"fL8p€x€€G€3g€"XX73IN€€€€€€AmA +€i€E9€h€Y4€€€7€€€€jA@€€=€€€€€€'€€\€€€I€,€e€€GY2JMu€€€€)rJF€R€S€€€€;€.€€€u€|D€4€2€€€€€€qAjJ€€%€€€ȼPO€D€€€xG€6€"G€G€F€s€2€*#1€€e€s€app!7>€€€€z€\€D€OV€ҩc€ =€$€€€g&€E€€C€+v€€x€oS€€ٵ.€€€€€y€€;.€v€€€"€€-(€B€
€O7d€:€€€RQ 9€€3I€R;€€cc{€€€!2+€0i€€€$€€€€€-€€fk€'`€€€Or€€k2€5w€y€&€$fO€€h€&€€+€!€€E€€|€€JJT€ €€uA€€€€ڽ€€c€'€a€€€€S:+»k_hU@s€s€€!€,€€d€#f€B€E€€€u€D€]€ʮ€€R€:u€p+ОL€K€I€€€€c2V€€€€€涰}V€€€h4€P€€g8€€€€*ܕ€€€€}wr{€=v€e€€s€€ €+b€€:\€1€€UT=€ + €g€.€P€€r€€_€QՃD8ȅ€€i€#€€€K€h
€uY€€@€€!€€rFG€2€E€8*0€wH€R€~U&՛€€/L€or€S€€€tt€~G€€<€€7€€€€€?€€_(€€€ǫ +€?n޹RU€F`/%R€€Ǵ€8€q€€€€€€€R€€€€€€€€€€3€€W€)K^€€jo€m€€€ €€M€JE€
X€$€p€€>O€f5€€X€T€€p€s€€.€€€€€€ݽ€se8€<L€a€1s@€e€<€ubg€€€€|_€!]€€€€€€€*;\~€€MP€€W€€€Ÿ€€€PBƩS€S€€kq€€v€€i€€wP0tEp€"̆DQX€€€€3a7€[b€€v"€x!b€€€€`€ +W€$ +€n€€ݱ€€€€€&€p€-_@€€€MW,€€:€€6y€€€9€€€Zs€€€€v[€€€€€h€€-€_j€€
C€y€(o€X€€A,#€%€€5K€F€€M_€WRo€q€]€ Ψ€"€€6€x€€€€Ք€J€€€H€7€ޚ€€X€€8€݋€:]€€ d€€€q$€%€6d €[€€g@€€a€xҖ€r€o€€л%€€/€€€Y€€{Yo€€€@€ǘ€?m2is€€¢);€k8i€€€€€€€€€h€܌~d€qbtI€~€CH€€뮩€G€€u€J€€€u€1€€)N3€"`t€;-€€€€WԴ€€簢€€€€ €€€G€=lp€|€€Y)e€€f_€€€N€€€€5 +y€€J&€(O€€5€€V€G€€€,€€€yoW€n€€D€€Ϩ€&€ €€VH5€€&€€-]q€€€€o€tQ€€€y8Uίc€€€54€€ק€L€Rl€q-€€€€€€€ڽ€€€€~{€€åÚdK€€Ϝ€€>€?c€v€€c+̀€R5x-€(€€MR,€€€?I=€€2$p/|P€€@ꢉ@€׃b€€€€m€€A€€5#o€€€v€€[pM€/€€€C1€€l€!€v€c€€€€€٣€Hx1@€€3`R€€UP"€~€€€yvAj€W€€u€b€^€}€€!<Gx=€€nO^5€
€€BY€zo^€€
€€S
<€€€€€€€€d6€€]v€€x€€QY2€€kfd€>kR+fnE€<A€€naG€Y€€€€€j€Ui0€|€ǩf€C€U_€€€€e€)€t€.6€€€g€€€€L€*€€<hY=€€{€j€Y.€€ €AGÞ%Q€€€€3}€€€€S€[k
€€€I€zz&8CKV€`l€5+€F€5@€€ €f€=g#/w9€€€€€" <€|€€€€€€qlj€4YZ^€!! SpiderWEB €ourcG€ +>(€€€€Q€€Q€€4€԰
awktangle€$€€€€€€€MPSTMPS €N€€€€%`€Sd€€€"€€ ?€€+3€QN9€€€le&€€€>7€€M3O€€€€SN€€€€€ͶO€=f€3€€/€€.k€{|€€MpQ€€ _€6A~^?!€m\€€(w€€s€p€€€€Eȶ €€m€la9dy&€€€€.€€.€[€€:A€€€€<H`€€€€9€€€ €ؿR€W€5€M€€€&€€€€€yEa[CGgs€€€€nn^€J€o€€€Ά€€€و€€V€€€€€€€€|€~U|€k€€@MKgc{S€€W$~€€)S +g΂€€hV€€y€€€€€€€€€€€yusk{€€€*€€€€€5:€.O\€€Q€jt€6t€€>€€€€W$C-€N€€€€€3€2ԉa€€€€w€€€€€
€nķ€~|o€€v|€€€N|€€€]€n€w߻€݌€=€n€/€5€€'€&8€€SX1€€J€€ €ɶRs/€€?€€€€€€€y€PM[€+€€€8€€y€ €De€y€€€5€€€q€€€€<.€]|€€<^€€€€€€€' €€z&n;€@€W&€L|€€y€{~€<€€U€€<j€]€€ڜ+€€<n(€€€%€€€+€M€€€€Ǜץ€W €Y€ݵ€[€€€€w €€€3€€€€€ό€€€M_I€ML€w^€€m?B,€€€ͲY€"G€€t€^€~D€€€€€€€€€
€€€€€nߥ€;u€€n€Hۘ€€ٺ=G€ú€€€M6€€€€Ҏ;€ׯI€€I;A€€€€;€u{€no€v€€€;¨€ߤ€€S€€€68u{€€€%€6€K;n€€€z€€D€eIÛ¾J€ F€I€a€vâ·¥=€B€_€€€€NI€m€n€u{€€'M€€€€]€€a€:n€€a€€€F€~Z€_€€€ҎK€€a€€A€{€€>g€€€€MÇ¥m{D€€:€~Q€ ɺ}#z_a|%€[€7Vt̉€5€_8€k€w€€m€Ӈ€\€€€€_)€€€€€€€€€€€€Æ€€Y€€€p€τ€A€4€.<€€/*€€€U€M$€o€|UV +€€Le€0W€Ut€€€€Y€€€€€€€!€€$/[!p€€€嘃€€€Ӕ€€€€€_A€€*€J€€€/ߋ€ €֮€€€€
€+€ Z€€*€€W€€€€€€€€€€f€€€#€€€s€€a€€\€$€z6bbs(€€_€hjm€€€0h€ €€€0i/€€#!<?€€€v?*€j€€ǵ€i~{€€€€
i€€€€[
€UbG3J\€€€€€=ÔD€J€J€€b +X€R€vD€€€€߉78ݣ€E€€R€€[Óƒl€+€I€€€/6q€Ћ€€€€ڷU3€€&€'=\6€#€-ˆ€<T0€€EU€€!€Zh€€€€`C'€€€€€€€UNk9€&€dWZ€€€@€M€€€g€€/€€
€€€€>€€
]€F€€€j€B=,€€€lh €x€
B€€|€€€5-€€€5+€[[€:G%€8V€?€AGB€€€]€~€ߵMw€4€€€a!|€€€
€€m€€G%S)€x@€W€Gz1`T€€
^€€YP$Je€!€ +€Z€€€€t€€€U€€NÓ]€:€b\€
€O€€€#[[l€P€€;'a€߸€i€€€s€€Dǂa€g|€€0;Z*€F€€€€]€€€€ת€5€€#€HN:"9€H€€IܼM€€S€€D€?y€€"5€€€€rH€€"+€z€
€€?€€€b€Ye€€€#=U€H€G€€€Q€yU€€Ỽ&€=|€羘€0Í€€ޗ|€;€0ÃN7€€L'€€“!B5€€€€I€Y€3€€€B€€g€uUr€:|€Jzt€€€€:eBC€€JO€0V€V"€:ʋ€€€ €€€yw€€cK€Y€€@€*€fr7€€€B€€rx€Mso€W€€j€€€n;jX€ă7Ë•+€Q6€{~傅€S€€€€€€€[D€w€o€€-4Q%€cJ€(/€€€0<€ׂ€`6€€€ɵ~cP68€*€"€r€H\o€Y€|€R€€€4€^_€!Va€uH1U€ߊZw€€€€⪂€€€€€7€a[€q€€€€!R€€n€%3R€€€€c>*€>55€€€€€:€, €€€€€D€4€€I€€€H>x€R €€FP-€€ €/EVÖ¼?€€";€€€*€Ƹ€u€€7€P€_Du€'€o-€cW€€*xQG€ѻ€€€€M€€€5x€Ʈ€€j€1€<€)€G€<$z€$€€€q€€H€2 g%€€K€€.,"€P€€€pF̀€ї€€€T€
€€1x€€€€€€T€z€!€2A€L€€W%€€€Ú€HNr€€€€` +g€;w€€€LET[5€€
€T€€€€€9€€
5€€€o€7W€R€ur^x€€€ŊW€uj€59€ €k€€.S€_)€€€x€€/€Q]<%΋€€€€O€e€€,R€[€T€|}€H5>Pde€,€֣⎊!W€3xd€jP€€Ô€€€€d€€X€}[€€" l"u€an€€Wܨ€€n€€€y€X€€€€L€ +€8E€+ €€Y€€b€{€€€€€€V€'€€k€ȩ€€EU€G2Dv€€yNr爴€€€€DQ€o€€€12g€€5€€:€GI€#$€€E€oM%O€Ć€€}!I€r€€€G€€€€€(U€€€RT€C)€€c €PUs€€€z€+€€€Oy€€.Ny€€a?€a€€€€G<<€Oy8€€8€€€D€€_η€@wj€l€€€€"ST€֊€3Ô·`€€&l€€C€€H€€€i/R€K€€€,ZX€€€Ӛ€€ƹ€€}€š= ˦€€€ӶrV€€€Ï€~€€v€€`a€€څ2~€€pN€€!3p€Ne€õ€€?€=€|W€Q€I€€:=€€€€ۨ6e€+€*ev€€€€<€€s,€8р3}Y€]€€?€<eWq&€]~Xj=c€׌f€O`0#€€€€ǾR€€€€IJ€p|€1Æ—~5s€€Eo_€€׮{€€€€d€€€Dž€€!€-E €K$Æ€c€Z=€€€€Ejf\D:n€X
€?jo€€€€€DY€€€M +Ù‡nZ€Û€€€zlw[€€B
md€€€€€€€u€5€A€)D€]€€ŸZ€|€€€€€€€€€€*45( +€€€e)€C>€€€ŔΌ)€€€€Ryj€€€€€€<€€$3€?€Q2/€€€5ǟ€9~05 Yۃ€2MÂ€ï °Â€5€4€]€t9u€€N€3€€ed€€>" +€B€FD€€s€1]5€€IN€€€€€€€~I€€w€ib€€`€€€l€`n€9Æ»o€€<€p€h8€€6e€€{N€Rm=€h4€€M€€:w a€€€€\S"€3€€€e€&€e€€€D€€~€&L€'mÛ¤d"J€€_€.€€€8/€g$OHt|€€yQ€€)q€€Lk€* +€va€€l/3/€OVJP€jvbF݋€q€<€x<ݥ€ϗسkcpf€€€q€td\2€Hh€N'2€~€v€eS€7€kɽ€€83€G€€€€€€€#€>€€€€€€€â¶Â€ÔŸW€€f€€€€}€-Eu€ް/+€€G€}€*vOYI€ €hn€€€€€€€€T€uɂ€€€%€€€€€ڲ€5u€€€€€€i2€y€€€m;€€=€V0€€€€€ަ€€+€ Z€i€€%€€€,€€I€€-€?€L€€€a€kÙµ1o~€g€EΉ!€€|b€8*v*€qb€3€€€V!3€€z::?€D€€€€€C[f€h€x€€T€€€6€€CVJbv€_}€€€€F€d€=€€€€€7€'l€[€€€€é€€;€\€Q_??€€€bT€€*l€ +€€F€€€€/s}€NW€D€u€.5Ѭ€€1Rmde€}€€€C€^€+ÖŽP%nk€€r}}x€€€€x€㇅ÿ€z€€€u€€`xy€€€|€€G€;0SL€€€€€€€€MY€€f€€,Ȥy€'€€ +PÖžO€€€'R€€[€c€7€€5U^T€€€aü€i€$€€€a6€€€$€€€U€€€€€&€€`€M€€U~€Ï€€€6€€€Z€€€m€€€;€VÂ€Â€Â€Â€Â€Â€Â€Â€Â€á «Â€Â€Â€K€a€<€€€<s€€€
€€\Ij€T;q€kM€)x}€\4L+9qUrE€F€€€€€€/"€€€m€€€€€€'^s€€G3€€+7
€NG€€€x€€€Wˉ€€€€o€€€€B€€€R€€īu€u€€-€#€z3€5€€ +f?v€€€+€€€€€|9c€€€1€€€x}€G€^)€€:€eU{€:€-w€€€t:€€€€[)Y)€qY€_€}O€€€M€€z€€p€€€!€€€€€€€€Z Õ‹Z€Ѣ€}f€€€€TÂ€Ü È§Â€D?|^A€€€̩Q€€€€€q€QVmu€x€€€ + €ЎQ€1l€€€5€ƒȎ€€YNE€€f€t€|!€€C€N€€€€7+€7€€€€/7Fm€€Uh;1€s€$€c€o€€€€€€€nb€€B€C]Ue€7Rc€Hn€ʧ€€WJ€=€w€x€€€€€MC€€AC€]€`F$€€}f7f€G6€`€^j€€5€(€C€€€€a€<€€€€€€)€€{€€€*€€€.€յ /;^€€€<€€€>€€€3xJ€€€t€p€zJ€€u€AE€€€€g +€sE€€€x]€i€€6€€€s €1$€I€K€€€_ U€Ý[€€ڞ€x€pv€€L€]€\€:8€`m>#XI€0ۂfR€<€€€?€€€Jz€i`€€€˷1;4€T€€€€€6€€S€?€P€Q€€$aZK€F€€€}€€c€€€€€€m€L(:*v}€^€€>€d€€S€mn7€{6€2€€€2€€€€bɵ€€€+€j€K€jt% +P€€=#€€vۥ€C€U€;O€€VV}€€#( +Z{C€€q€P]€€€€g€$Â€Â€Â€Ì a€ŗ€|€€€U+n?<€€€o3c€€:Y3€€GÓ¸~€W€A[:€@\€€k€€€€€5%\€€tqy€€Y€2€€€z€€€€֡VwÏ‘3€€Ʈ€Ûz€?9€€=I%h%€€€€U€€"0€0p;€ާ€h€€€€€€}m€%€€€Z(€ZA€k"€€€Dc€8€L€ €$€f€€€€)5f€€[3€"€_R]3o€€€€߿€/€#>€€1€€€€l€8€€€€U€[d€̡a€C~;2c€6C;€s€3€F€$€̤w€€U€€n€€€x€€g€5A€<q]€€€|€[]€€€ ۮ€€ʚ€
+€€€€€€€€)€€€€€ǵ€/wI4€€€€}M{4{1Yyn€N€€O€xÓ¦B0€?€€€x€P€B€3j=€cX€G€+€€€;€W€p€€€€U#S^€N€=€€qx€€€€\€o€QW?y€YE€sV€€€€d€=C͂€€€€I€€7€bÊ v€€8q*4€€€N€€`!€)ѻ€€€M€I€\€=€-€€]U€+c€€d€I㚮€L€z€€€f€ͱ€<4Q€97€k€kU€€€t/YW€b?€€a€/Ų€€fA€€ޒ +€WS
€€€€€€€€€€€@=Í"€r€lA€<€yf€€Drȹ€€€€€ԯ€̜€2€\5U€€€M=AegAP€-€€€€€bV€=€{€€€è”€€€€€€€€€
€€€C€p]e€j;€€a€€>ߣ2v€€€-€t€€€€Oȷ€€€€t€Ӌ€€€W€€€A€4€€K€'+€y48S€;€[€€€€V€€Ex7€€U€€21€€gW?CV>޶€GyN@€€*1e;€8j€€€€€€3e'"<€€o_€n€tHIm€ed€ڂ€Ɇ€l:€ʆ`€€Rld€€€e€*€k€ߟ€€m{p-€Z€€€€F"b€[€q€|N€w€3owa€€€0p€€€€€€|€€€€€YÆ´!ҋ€€W€€€€أ€€€ses}#4e€€€]> €d/€.€€€#€€€€^e€€€n€s€€qV$_€€WY0€€€^€€:!€J€€€gJ€€w€€Ҍ€W€€h€w€€€O€b€C€ٹM€€€U~Ñ›W€G:g4jw4j€€~€€l€€8€tn€3€+se€€\Þ¾vhNǹ+€€bDv€€/€€ê¡U€we?€€€€€€€€וBTU€$ɡ€y€€._g€
€€€{€8€~€€U€q~€Kä¸Â€Â€Â€Â€Â€Â€b€€+$p}€~q€8€BU€<ʳ€w €€€*€€&€€H€€€€b€€P€€^J€€ +€€€€€Q€€jE€€€€€K€p€yQ€€Fe€€?€€€2€€>{€G.€€И}€gdEz€€€/y:€·g^€€€€ʿ€€k€>€a€€qd€2€€YʱHgl?.;C€€O€j<\0€€€€€؈€€€€Ur€€€w³*€€:^€#€VD"€€€€!€/€€€€tT+€€€€€€nj€;%€€2€€K€€€€€o€€€Â€€ €U€}€€€=tq€Xs}sO€>€AQ܇^€_€€̒€LϦ€€iğ€€"~€€€N"B€'€€€QO€$1rd+€€H€€€€a€€€€€€0€€€Cup'gS!>€€€7€€€Ƅ€€]€€۷€7€€€ElN€ꮋ€€€€9/W€€ €€$*<?,€/€€€ю€€€€aU€€^€€€€8€f€€€c€;€€)M€€€&u€6€Xm|OBr€€y€€3Y{€E€ꔳ€D€€€€N€ϞrX€€€€p€€€€€€!€Gz€=Da4€*P€€€/€;€e€I€KÛ»"€€b€€€R€€€ +8_k€€€s€p`(0€€vF€€S€€€€#<e +#o€€€€€Y€363€K€j€m€V€8R€8Ss0€€€B€A€€€ ϯtA{fT€€€€€€€zy€UU€g€€€Ը€€Ÿ€=€K€1€€€€l€_B€ƞ€€'D€€€J€[€'?`>€#R|%Ô•#K€€€,€IU*€YF€3€€CL€&€€#K€€s€k€a€€*>€€€€€€Fs(u€1€D2€€€WM€yP€€o€€€€8Â€Â€Ï R€B€lO^€/€,k€€€K€R>€€€€nRl€U€!€O€€€I€€€€€^€€€€zu€€€€€€€€€Ǣ€€0€€€ó€€€€€€€q3€CV€€6w€i€€€€€O€F€}6Ò‡|€€€€++€€+€F€ؤ€€KE€€€€*=]€c€€€€S€o€c€€)P5.€€€Rq€v€&rE!W€p[€€}s +~€€w€N€{€€€€C€A€[Y
D^ €€€kv€€€9€€€]5€€%€]€^€€€^€€€€€R YU€`o€€€€€€€€€J€2w€€€Fߚ€€€;y,¹€y^>1€X3€K€€;%€Ź€~!2)z€;}€)€c€9€p[0˜]€ڬ€"€€€?@ÑŸ#l€€3€ѵt€Q:f€7z€€[]€€€ +T€5€€€U€8€€€?TFB€€* €€€€H#€N€€"E€€€€F€1€€€7Z€wÂ€Â€Â€Â€Ö Â€E€€Y€Jq€G€;4€€V€V€<€ +5€B€ L=9g€-€€€a€€€€€€€€€ +1€€€€]L€|r6€€€A€U€€€:€w46€B~h€%.ZS€€€DR€[V|€€r€€€€N€€€p€|ĽHߪ€+֡€€O€€€€P€€H€€@9:€€Du€S/€8€X€€@+€€U€9€е9€€P`Ä€[h€ €€Ӌx€€€Oq€€rXg€~9€#r€}2vu€€!pj€bB7€=60r€€F€€€1M€€€_€€€€G€C€}€YF€€FÕ§bg€€U€ؒ€T€{€>€|€l€ +€€€€€€€Өo€B€€7€l嶖€€€€€€$+€Jd€€€€€€F€A€4 +L9€p€€€n€€€€$€h€€QM€€;€^S€O€צ:€€€tX6u€€Pgq=[#Z`€]€(e3p€€€€€|k>q%ʀ\€€€J€€€€c€€NsP)'a€j€€€~X€49€€z€ɂY€D€€€€K"€bjZЬN€_M€€b€J€€16€€€^iOOc[,S€€(€DP€\€€>ڷ€~€€ig뜚€€€€;P1€e€R€€aa€€€\€o€€oЛ€x€€_€€€€v€€Do䶚€€€€€.€@Zx€!€€€@€€p€[€P€;€€'q€;,€e€x€€€€€\C€e'x€€ٯE&€€2ah€>\I€Q€ 1€€€p€ײf€€X`€ Ä®9€x€.€{h€€x0XBÓ±]w€€€€r)€€w€A€4€y€€f€X{€ €€€€€o€g€6€€x€€€.€I€€K€9A€)xç¾Â€Â€~€C€s cM9M-v€€$€OL"€?w`
€J€€ +4€€#€€€'. €€€M€
O€[€8]ef€€O€U€€€€€gS€f0€7Ƴz€?U€€_W€€€W;€€)~€€ZU€"U'€€~€€m€|€9€T€Ff€4€€O€ZVD0ȸ€€€€€€y€(91€h6%€€0€€zH€€€€€€€]€u€€€€ץ€*=d€€€$;€:€)€X€€7€P€€_€€€p€tM€€S€E€ћ"€Y€X€s€/€€5€€8€c€€{€=€=€a9ʀ€€€s€*€Y€€6€€€=|Bj€€qڃ€1€€T€~€€€€€a€€€;`€€€€€€€€€|(s€L]4€€dz€}€C{€€3€H€€€:€/Y4Mޗ€€C€€}€4鄅€€K€€€%Ix€,€Dߴ}€€€ٴ€€€€7x€€€=r)€€€B€€j~{€€v€€{€F€X€y/u€€€€€2€ٺgE5€€Bע€\€€€R`€€XF1ְX€V€€€-€€b>[€l-a€€qQ€V'[yl€u#€?ٰFD[E€€*€8q,€p]€*€p€S€X€€,€€dk&[W€U@=€\t€€€€€€ׯo€€?€J€€:#€€7K<€€€€躯c[8k\I€€€€,%YM€d€a=A6x€4€€€€€D+€€2€V€€€<€€f€W€€€]€SgH€€€_Go"+€m€€-€Y€pg€I€\N€9€€$€:դ8€?! .€€€€€€€€V€€€€H€r€ٗ€\[€€|Qj€v€€€€€€€€€€€€€€D€91€€€~&vB€-€Y€€%€^€€€€l€€F€=on€_qK'€€€€€€@€€Q^X€€]€ų +Y€€~€}&t|a€|t€K€M€
$2€P€w(€e€Tzix€;€fm€x€€)C€9€€€€€i€€€€A€`€J+€G'€€€€€€^€)"€€€؄€-€€€€ +€*€x€6€€JU€€pz€TlM€YA€*€€$€s€'€€€€yÀ€€>€€€w,GG€u€iΘ€P€%€€€J€ǵU€€=qX€1€€5M€€k€?3_€1€ۂ€€H`vq€€€€T€€7€ 5_€€T€/,€50?€;€€KǨ€_z€€7€€>€V~€€|/€tAx€zÖˆ^€(€4€€ƺCF'€@€x€€€mY€i#€€pS€|Y€€€z€G€ €€€$€€€€T€̀€AnƢ€r€Z€€€-€>€€ €?`EJ4€R(O€€€sK#€€€3€€'€€€9€€€_€MW€€E€€ €,€G€t>vx€€y€€€€<V E{€€[€k€€E€w(UkD€ӻ9N€€€€-Ǩ€€€€j€D€€I|€€>€^? €€€P?u€€@€€€m€[$€€€M€€€€€€€T,€W€€*€H*i€€z€€Zs€ *Tlv
+̰€€€d€€€€^V €g|e€€€€ǚ+€€+€€€#€|€x€,€€€€€8€O€] +€€€>€P€€&g€2€€?€€H:€€€=Z€€,€€:€€9n€€€_€.€Sߙn€fc€w€vܧx€€hG€€€Я€@€€€t€W€oF€€€e€€€€#€Ua
€朗nU€€e€€€€€€R_€€<€׾z4€€€€€b€+€Y€€€83TR0m€t€€=1{4€€€Ԥ€€߬€̜€€6€€€€€€w0s€fŨ€@{b€h€k>B€#€€D€3€€)z&=€€€€€L€K€€9s€zpI1€€€J߬€€€o#€?€/q~Æc=E€€x€€9€ї€€(€€G€€dz€v€ɕ\˰€€.5€7€w€€€*€€€3€x€€n€€€€€€G{€€€€/€>€W€€GUq€c€8€o€€€}€€<€€€ؔ€€9€T€€y€€:€e€5Q€RnOa€M€C:€Nb€€€ij€:E€€K€€€U€€CK€€n€€€g-€€_']&Ǵ€<'!€0€€€€€€W€Z3€€+€€.€f5v€%G5€€€€€€qMaP€€€€@€T<€S_G€-7rm€€ڞ€€|€€€P4€€€_h/€xYf €6€€M€Hŵ/€€€€Uͯ€€€r€}d}€)M€s€ʉ€xV!i€€n€AMy€€€n€€€I€€WhhLg€J +q_Di€i€€€€q$€€x€+€P€P/€€2€4€€)€€z(€%€Z'€ȼ€€€32€
€o€€€$€€€€Uycld6€.€€k)gkTUI,€y7€€`€€€€(€b€€U€€b€*€U€€€€€ufa€ء€&€0c +€Y€€nÖ€'€€_%^A*;€k€€€€60€M€8g+G}0€a€.€7€r€€€€S€_wS€€€b€×€+€cc€€ۂ8€€€€ܙhK€ N€€_
€€€€8€€Ka€€€€(€€€bO€€,€p€€&[€e€€oy€€U€_€€€G€€,€€€€^?€&€€€r\G€S€q€€/ L€u9ff€€2Z\>€€€€€d€€€€€€€V€,WE€ਧ€€€€€v<]€€y9Ujɧ€€:S€€€€u\Icx€e€1€mr€€€<€3€*Ɔ€l€€€%€#'€€1?€X€֪1?`Z€zP€€Z€h€€€€XY€P€€€€rc€€׺€€F;!N€n=€?€€~YK0€#€€€€€-m€y€€€€€đ€€€5€J€€€c€!€€^€€€€yÂ€Â€Â€Â€Â€Ç Â€Â€Â€ë´¯m>€=`€&;{Ò¶7€k€€W0€srӑ€`€€8€V€€4€€hT€L€}MV€€O€€€Q%€€d€€O€E€€€xO€€€Ө€HT€0€d€€D5E€€€€^d€€O€~)U€€[>€€€*Y(k€€€€O€€E€€6!€ko€€€'QűHTq€€€€€y€G9b€A€x>ރ€̜U€T€6€"ˣ€€€?€€Ý€Shi95€pz€C!€€€€€'€€€€lR€7€€€€€Za[€φ€€Y€+€€`€;€€€€Dr€€€-€e€€ѳQhgP€€€€€€€u5€o€[\ €€\€€:€b€€[€5ap€b€*€ +€€
€z鎛Z€€
+€€/€tme5Y€€"€b$€€€€6€€€h€€$j€#€igz"€€x€€(€/€€€^€~@€;€N-V€<€€€I€€T€5€cIz€|_€E€Pu€€€€€€h)rB€€€€€€V€3€€f€T€€?€/€€̱€\€$€€€€Ö€€y€€ҿ6€€€I€€€€€€UE€€€€€€X€€If€4$€i€ +€Q€€b€€~€€}'€&€€€'YEmt€ +€€H€U€€Ëc€Y€€06D7&€5€ͅY€Q€#)!€^L:}€o€plyTC€€^E€€;€Fߧ€$Nl€€€X~_€GY€(€€뙘€€€€E€Z€€€€€kFwm€€€g€\>€̉€<a(€{€€U€€€u€i€\€€3€%€€ћG€€€T€€€F€€€}€_€€€€€€sA€€€eÓ©^€€€rM€yOXv4€€€,eo~€€>€v€€€€€[u€oj€gC€€€€€€€€p€ˢ€rasgS€€a€€r€€€€nѳ€€€€€€Q€&5sx€l'€€€€€€X}Gdvd€*€€1͈h€€€?€€G€qE€[€<]%v€€€€5€€€€+€€€7€g€€€f€€S€€B€€€\€€Ɉ€€€K€NÉ¥h€A€€(o€Jړ€^ѱm€g€€/€%€€}€ +€€=t€€€€bϳqO €€g€v€q€€U€€+€`€€ +~€€€3€€€&Fމ€)FX€€m€p€€-€€nX€€|[€ Ù¢T1>€€€FU/€€€€"€€€~€€S€ݼ€€F€(€V€8€€&€€€€a€^€s€Äâµ€^Me€l7!本€,ݙ€€)~Vx€€>€ q€x€€€€wL€Ř€€€E€€€w€€€€1€€i€€€€c€/QG€€"€2Z_V€€ȥ€€l€€s€€*€€A€€€€_€IV€pu€€˱!t€€
€€€€€;€€€B€L€H€€s€(€€+€€€€#€€€ht6ϯ€|€€€€OÇ´1€ױ-L€2€ç‘€
€€7€1€2€ +€Mr€€€€€X€+€€rf€€z̶c€€wvq€€2€ +I€€s€€fy"€€ڄ€|€ʀܧ@*€€˚€X€R€:f*а€€€€€€ޱ€€€b€w€€c€€"€Ŕq€2R€=€€€€)€L€€y€7€€S€€`a€o€gcl>2€€c€€€€€€[13€€O€€€?ŊKB€Ǔ(Cxkb€(7>%S€€rc€€€r€€S€x€/€€62zJ€xF€€=J€€€L€€€3€z€}L€ñ€^{€$€€€m€€€!~€'€9€€‚ €q'€1€EQ€€7€€x€9W€€€-tY€@ή€q€-z<s賞K€€}€€€€€€MB€€€h€€GKC€€s€:-ђ€Ec€€€.€y€\4€€L4€€O€€€ +€€]€h€€€€
€€hv=€€€€s€€€3€RÕ¼s€€€€3€2U#M~S€€k.x/k€y€€€jG1€%€9T]@€€€ZÏ·1€=Ɔ€c€€€>€Sh€€€€h~€m€€:€}*€L{€€`ã¹Â€Â€F€€€€L€€€€€Œ€Q_Ö…~€.€ _€€}]€܉}m€€7˫€f}Â€Â€í°¹Dt€sa€M€2€€€I€€€€€&˰€€h.€sݱ€Z€€1€'€.t9W€€.O}€€€€€w€€€ct€€€`€;s<€3€€€<€€VЕ€€<€ :€€C~€
O€n€x€7A€O`€€€Fs€M€€€€$)m€€l=€€n€Pi +B3€€€€潴/€_€,մu€L€€€€€€€€sL%€\€€>€€€o€€7€€€€=€€€=€s47€€€€€G€€€T€n€€ht`€X€€s6q€€@€c€ܞ€€€€}€F'j€f€L€hf€€€
lP[uM{x€!U€ɜ€Oߞ€o€€/€€fpjC€€$y@zSNï››y*~:CV€€€€€[Aq€3ZC€9V€؞w9€€€€J[F€€€se^ϳ€5€ZV€Fsa?'Í€ +€€€€€ 2^~€€€/eM€Z€&Q€€Ʀ€\#Ô¼5€U€j€=€€€€€\U€v€€€nx€€Ù)€oI€€w,€€ €€€2€€q€1#L€Ô€rËߢ€€€€€€`€fܱ€؈^€yRÛ€v€~€€€€Y€x€w€€zMt}€€€€ʮ_Ty7€€€3€€?WY€f€;€Oxz€€€€+€x€€o8€T€H€͘e€'€€1€€s€€t€€z€€<€€8€F{€€~€;B[y€{€€€~€€ﻇ€"€€{€€f€€€t€{€J€g$~€€€j€€g6€€€€=R€Dx7+€€\G.R>€W~6€?g݄€€€y€€€8€€`€r{€€€Gn€€€Ñپ€7€·€€pVr.€€I,€€€€H€€€€QM€€w€€5ѿ€€€€~€t€!€쾟+k#4y€€€€€"€>€€€€>€€V€€€€€e€a)€8€7€€C€€^€€€O€W€€e€F>}/€׷€O€3 >€€ی€pR2€€€€gg_{€c{€€
€g€€€]m+F7€L€€€|v'€/€wO€/4€nl€8€€€€€S€€€3C€,O€@n;؇€t0€€€€wk€yK€؋€z.€ݣ€€€v?€€€btMx!T0ԛ5€€€€ۑ€€/F€€€€vt€xQv€
€`}SscK[€€ɇ]€€w€}}€€Ղ€€<\0€4€cMէ$8€€k$7Ɵ€{C€€€R€J€\€H€€T€€H
4€K&€€u€{€€€e?€ +€:Ѹ/€Z"€}€€€€H$=€D€ۣQ€€€f€?€€€€<€€€8/€7q€€ €€O€€€Np€i?"Ú²6€v€6€Am€r€€€€€~€R{t0€<€€*€`€€€€Z€€€t€€€€€m€g€€€W€€+Y€€|Z1U€h€€H€cӞ€nP€z€f€€€€M€€YA'Ś€=<€€s€€In€9;€€€]€€€€>€€ €€:on€€o€;€FV€€_€w€€€ €d€€q€DÌ•}]€S€KF€€€€_€,e€|€gX€€ €€=€]dU€/C€€҄€wu F€\m€€j€dE1=8€€A€€€!€<€Lh€q€:€b€€€€6€T€€€€*€€€<€4€€€`€;Q€€p€€L€j€€€5€€|€z9]}€/€kf\0]n€€€vy€€ /0€€\€-€w€K€Wu€€€€ßZ&€j팛€[i€€€€€€P#Û¬H€€€€€€€?€Q(k€CWt[€p€W€€€€4€€w€€€u€K€M]€0k€/d€Ź€€o€_^`€€3€,€E€€ۣۛ€€€€WM&s€€d€€€€€g€%€€€6€vL1€€MɎ€$8$€&!€€䈻/€&S€€b6€.€€€8s<€€[Mf[€€w€i€)€l6Y)€€€€fN0€-q€K€]$U€€€j€€E€€€xf€€€€l€Co€Y,iH€$€(&€€€F`D€7€€Y€L€ł€6€€s€M€ɔ R2M€V€q€o€y€Hղ€l€€x€t€€s€€€W€€€ь€Nq&s€€€€7€O€€R€L6d€p€€€ +K}s€€f6€ǣ€€ €€V€€€|L€I€€€$pC€€Ba`f€€6R€F€.a€€g€€Q|€€N=Äc€9€̎€€z#91~R +€{!€(a€€€-€?W€i€^,€€€€,1Y€Mv€EzΨ€€ €d€€q€€ €€XfÄ€6Ñ”b€€€ғ(t<€€5>цTLF4:%€O2€€L=€8€T€E€€<€=!槷€€;€lF€€€g€€V€]B0€"€\€D€€x€€g€€I€g€4!€€@€€€:€€€€5@^€€G€€€2T€€€d,€€€2€€V€€€g€€85ʖ€€_+ZR€€㸔$j€g€€€,Y€h€NDF€Gšf€€dJ€C@€^$K<:€0€Q€%Q€L€€€g#4E€€€€€PO&€€OF[2€5€€^0€€€€€`aw€6€1€sF[R€ٙ€pSÊ®Gpvp€r㹼€€€v€€)-€€4€€€b€€O€€p)€€€,€Q€8€€Q4€€€€b€€g7^H€`€€€K€€€€€€€€%$€€$h€€€X€$€€
1€€€€&€`#€€k@kZlV€/€€€t'€1€€m€)1€€€cP€€@O€hN€€€€n€€€iq€€K€q€€€€IS4z€€v€h€€If{|€€!€t€€€€^U+8(€€€€€€€3€€€€€[€v€€d€3€-`€€?€\ÙŸo€˴€[-i-€f\|A|k|N^€USU€E€€[\€€J€€զfN€€Yg€Y;€€€I€€<k€€8€ +k€5€€€€€€K€€3~G€€€L€u€Ûs€€€€€왩+[€3€€.€kRͱ€V&'M€4+€€€€€6X€X€_€€柒r€€q€Ֆa€]€€€€[x߅€€€€€€€€€€€€€w:€€2/€z€5€~€€R6€€ޗZ/€€Z€€]Ö¤k€%dդ€€m€h€u€5€FÚ…V€€yI^€€€'^€€€k€€;/€:€€€|a€€"x€Z$€€€ۓ€€_€€qi €€u€N€€x €€€€WO€€€€m€€€€€€[|ܰ€`€€Õ€\@Sgf_€€€€
W€qӀ€€iÅ!€2:Ӭ€€C€€€€1€w€€€€g€€€€€JkKW,€Ef8€Ɍ€m€€€€LLR€€Rq€€ފ.€€R€€Kqm€€
3€pKÈ€€ٛcH~€f€€xÍ€€€€€€€€u€ze€D7€€€jź,€€r€€b€ς€W`€€€€e€€7€€_€€L€A8€€€€
€€€^€ɗ€€€€ż€€6D€l€€€€€g€€€€€€\€2WM€{Öª$z€|U[€€€Ìϻ€=€5€|€€o €€€~€n€^€€6Z€t€€sfÆ£piR€ޚ0j€€o€淸€€€€㸫€€&€€M€€€ھlau€{IY€€jnW€+€€€_p€x€e€€€/€~€€€€€€€€€t€^€€€€€:€€€€[A
½g€>€€욒55€€€€s€M€€€_p€€+g€€€€€\]€€€€€€JJ€€,,[€Y콦€ڊʪ€€kj€,€€€€e€]€€€Ն€M€>€ʖU7€€ڃ€€€Z}€€[€€wݟ€Q€Y€/tW€€z€€b€2€!h€T€€E€/VpEr€€€€€%€€€€t€B'S)€€€Jk{€€̚€T€€€€€֮€€€€€€€E€€€Ñs&+ׯl5+- +N€S€€€€€_)Y3€€€€R€M€€€€€€N€€€+€}8€A)€€€}կ€€€€€€€€€€)€m€J€€#N€€(U€C?U€€€ +2Z€+IS€K€+
z€€98T€T3€i2"€㾣€R2?,€€-8€€K€€s€€€€€€€€/€€e€te€B€€€€ƥ€€€€(€€X8€€N€t€Rhkܢ€?:€€"€Z EM{(t€t€€!€€€€y€Ҽ€€€€,T>€€€€-JSK€€$€
M +9€€€€€€€ɓ'&NQ€v$:˦(ٵ€'>€€5VR4€Æ€h€€€€€€u(€EN€@֑€`€Or€2€XF€/€€q€g€rB€€Mp€€Dg€€(€◑ǚ%w%€€Jv(7S3€ڻMy€':o€Y€€€€ޥt4LÑ 77€€Tzɕ€83l€€ȡ€!Ԅ€kk€€€@#\K€&€€€N€<.€€+7€ɔ߂€ڕ
€H +€€!6€ӕ€[_€€€0€E€#€€T€€€€€bjG€ՙ0€c"^:€€8€aO€€8€vj€3€m€€€€W€t€€€#ȃz᳔€€€€€Β€+?€€ P8'€€€€(z777€€€€|€E€€@€€`1A€€€€F€€€€#J€€yuaEWk€€€€€€Am€€[€'€(€FyLp€€ +BH€#N}@€€HÕ™NB€lj#€€d€€mE€€€€€€€€1€€ €y۸€N\8€€q€8i€€€χ +€€;f[w€Z€C€€w:;R€8€€@P€€;h€€\€<€4€€9€~a€€€K€v€%l€+€€€)€€€€€bQ€B%€€ha.€Õ"q€€€2€€<€€yE€€!€\q€€W*€€€κ +0€€Iot€€>€I$€x€€U€JG;$_a€€€t>€4€€€{€€€Ne%Ä›ÍBʼn€eT€€€Zp€G1@J€9<xwG€yj€€€€4€€s:Z€€u'!UHB!€€M€4O€1€<1€€ÙGC€v?€€€€€VG +U_KsS€H€>€ۓQk€wc€Pə€q€€€€i +'€€@8€€<b4N€2€#ejS€ &u(€€$.€€W€%€€OuM."@G€)€€N€€1cj€\Ø“{€vL€6€€o€€f€€uw€€)x€€ +S€L€2€Y€Hb€€S €€€x€Z€pj=€d$fJFG€' %4€€c€^€Ԉ€%D€€1]ho€€t€~€€#B€€€籺ȬǜGs€I€€€€€€u7€€€€€ +в6€€€€^€€Θ€f€€1c€€€=Ó¦a 87;€€€€ع€y€f€€W9V€€kR€€€ږ€€c€;OG]€'€ڻ€€G€NB €€K^€€-k€8€€€€€aWs€€€ٻ€|€l€€R€€€8€€`V€€+PmO€€€$d€O€(i€€€€€֒.€€0f€0€fZ1€€€€€%€€|~€€€€3NV€mh€K€€€€щq;J€€4€€
9]€b€€€u€v€[1€Ŕ'@ €LHƈN5b€€€lrf]€€€€€€@€r€€r{€€~R€€\;>€€€€€|É™}€n4€€€@# +€[€rg€d€€oÙ€j:W€€Ï€:A€€)€F€€€̣Gn€E€3I€€€€€€G€&Y€1€G€k€{€€p€MÆ€; €4€€€€1€8€iǷ€€u€9S€k:€8€€€€€q€T€P,€€€€1€€€€Tb2€x€xMÆ€)€F+€TcoRY€
5€€f€f׀h€5€€B€€5€3€7€>€€&€€€%€p€pZ€1€0ÓÅ€€_€€€߫€€€€1z€€a€€a€i"€pv€€{Ö½x€(€♴€€€€€'€€€€€{[€€€€L€€&€€€ Z"€€^m€€€=G׎€€€€X;&o€5Ø‚)€q€€p€n€3€€a€)€ܸ€:€€dN€€*p ]^€ks€4€€s€w€b€€;O€€]€€N/€r9|€€€€p€€€€€ԅf€=ÞšL€€B€€€`€€԰€€ă€6€€€€€q€8€€€5 +€€€€€€€€G€€€y倀4€€€€€€€€R€҂
€€€€;€L6l€q€€:€Q€€B€:y4€ +\€]등€9V€c;€L8.Dž€€/R€僚Tq<€bx€/€€ +և€€E€€.)cu1€=U€x]̇~U€€u1?€€€l€€>€y€€€+€6€€€€y
€b€€€€€^€\^€Q,f\€€3€gBe€€~€Z€P-xW€€Az˩€dqN=J€€€€I€€2€
€€(€JwL€€PÂ€× 5€€U4€+€(€€€€€€€I€M€p€:ZE.€€€€€€€€#€€€€G}€€ß€k€€z{€E +]€€€€€€€fe€€€€€lx€_L8€€€u€=my€€€]e€€]€€€C€€€€N€Z€€?Vu€€€€pć(€8O€yk€€€€€5€€€5€€€ 6i€uΧBÖ‹6P€'€€€€€e€€€R)s€€\€€ €€€€fmi3€8€k€€€iOw +.Ö·g€€€€~€7€€C€€€€€=€3€3€€nÅ¡L€€\F€.]€m#e€EXi€€€
m€€X<€*T€€€$R{€€€€€ݼi€€€-€€|€€Z€€[€€V€€dDN-€€a-2=€{€€€7€G.K€_Òv6`t€{!|€€N;u€c€?]€l€€.;aɉ€€€€€=€s€€€€oÇ®n€W_€€W€€€7€=t/€€\€€c€€
€f€b€o€·}€€ˊ€l€€Yq[€€€[€`€€€€=€€!~Â€Â€Â€í°ªÂ€Â€Â€Â€Â€`U€˗`€€Û€A€€€€€€€䛂€€€€€€€uUO€€€IWW€LPo챨€೴'S€€q€=F€€€€€€UwO€Z€€Pc6b̄€ד€€€LR€{UWÏ¥jb€€\€N€o2€'€d€v€Z`{Rk€&€€pX]€€€€€€vt'|€g
€rq 6H9€~J\9€(]€4€dH.€e€€€w€€,€€V€5€A€€€GL€a.€|L€eb€€])W,[€]7€Z€€A€_z€€w8€€€rpB€€ʷf€€J9€€€€€€€jt€€€€€:€xC€€€T_€€€L€ZƓ€K3€€€€RH5)€O€€>€€€N€€k=€€a=€A€€€€€!G€1xK€€Vâ”
0€€€€>€ډ€€€@€T€b€y€€o€€@y€{Np€%8Z€kŀ€g€€W€E{€€ƃ€€Pw~]a€€€€;€.€|€ T€(€€€€€6c€s€g€€</ #€F濱kG€€}
€€€F/€€€nv€~p€~€€€N +:€€€€D€€€€€€€77€m€o€€;D[€7)€6؊€BFW€^\J4€Ŗ€€€€€€Q€.€4*€€€a€o€€€ĕ€€€€€€R€€€€&€;€4€€€s€€99€€€Ex€V€s8nU~x€l€€€€8S€Ð+/3€€{H{€꿑c€N€\€€€€'q€€€z€'Rq€쒮€€\€t€-w€€€7€}
€€/?N)€€€/|C€€€PC€E€g`€>+BNb§€€-€€€D€€ֹ5€#€€€€7€k€€1Z€ <€€d +€€řA€`€€€v.y{€€GRo€M€€€vb€pQX€=€€Jz€€€V/n€$€B€^€€€€€€9€€€€€6€ۓ€N€3€€V€ň€€l€ѿ€€€€€ެ€€€8€1€纰€€q<€€g€€€G€€?€€€b€€€€S€€1€Q0€pB€€€€€O~€g€€
€wJm€€€€Kd^€€Y€€€б8€€^€t€€z:&€>]€€€Y€i€]€€7€&€€€#€ř~€c€€?€€Vu€7Η€€€Sq€sn€€^N@/€€"€^€)K6€'
€4€S€AǶ)ř€E€̡€€kF€€€€' €€q{&€7€€6€€€:}\€i\Mw(f9o€z€€€€€€f€€€€[€€€€/0€+D€yi€vK€€€€€€€€€)€sÓø€€€\V€+€k€€h€€%€€wj€y€/€€Kk€€€€c€49e€€ԋM€€\+€9€€€4ܾ€J€€€vÞ‘;€€<!d`€€C€Y€l€.€€€n€<햡¹s€€€€€€1€D€ed€B€F€€[€€€z€gpG€€€€.€€€(€J€€\RcH€€€€Е€€5€-€€€9€g€€W€QgS€€Kx€€€€E€V#€€j|€;è»W$a€e€€-x,*€€€€PB€€Ri€€m€€€Ng€x€).j€€}€'ҩ€€}€.€|€J\€y*€o€|€8€€ՌY~€€*€W!&!p€ZT?€Й€€€L-€€€€BU€€)v€€
€€J\Z"+1^€j€€€5sZ€-`'b€LJ€€֣k€ùC€€€€€VMH€%4€€M€!€:<R`€€ٙ/€€ñ€J5{Jw€^€€6€€{J€{I;Z€ݑ€€&L"€ƕ`€€?3Ñ€€|#€:€€LLh€ˊ€€€€9€E€€€€nMo€€€€5€€€€ͺ€w€€€x€€€Y€€€$€€€B€€,><Bw€€q#€€Y0np_€=
€N€€€y€۴˕€D€€::q€b€€z€&F&':€€€@u€a€mm€€Pq€Z€€€€J€€€#€€€€ř€€w€€s1€€[€€{€€C9)oÈ€u€€€€€€[€XaN€€€€c€AL3€m€€TLxK€€jE*m€YcX€€gm€;y€Kќ€V[€w€
Jn€{r€"€æœ(Z€€k4€)A€€€/?€€€€f€€PѢ€WP€]€€€÷wh€j1€w[€€€w7€w€v€€€€€€yW€pn€€€€b€ٯ0€|€€l
€Ɏ.Å‹vRM#€€€Ӟ€€€~€dU€€\U€€^€l€€€€€€€€K€€'€ܞf€€€Q5p€n€€€€€׋€FV€xF€C\{S€+o€޼z€0*t€€o€h€hr!޿€5€€€€;€€;€~ÒŸ5ySGiOk€@€=@e€€€€€€=r}€€3:p€i€gcM/6L€€€:/jj€I€€€-€MÚ…`€€u€€\ȼ}P€y€€♾€ijJWe€ _€€ޞ!F€ €€€S€@F{€€T€€s2}€>ʻ€Lޔ€€€€€`€PFކ€~o€€5€€va]€€€€€ I€€|S€:€€0€d€Ft€S€V€v'€G€€€€€€ <€((B€ڽ>€€Su6 €€T#€C€€S1€×w€€7A€1oG€€7€ͤ€€n@€€€€€€܃-€€€x€:€3€€{€€€+P5 €`&A€P€€€=€ե€€×3\€w]€i€]F€nv\2€€€S€eW€\€߬j€*a€€€i€€€€!€+~€\F€€€a€€?&6€V*q€€Ó€€(€€€€J€D€m%€€^$s€€€V€-€$_ç‰"€e€€EaA*Z€€9A€>|5€bG€}€€PØ·f€\€QVd€€nv€$€c€E\€€€€t€€8€Ë€€€€L`€w}€€€€€n€g€~€QLf€T€S€€1€/€€j€€€€€€€Yc€€€NB€('\€R€€ʬ€€׃:€€€ѻ€q€U$€Z}€&€€F€RG€FO€€€€w€x€Ua€€ f€€€€€R€€€6€€€&5€ۨڣq€€vn€€рCf€ٽH€€€<€P9€€PN€€7€C€*y€€€€XL€€̂"€+€€€UÈ@ϼX€€i€6*€H€€2`€€X€s€€]3i€€1t€b)€€€€ph€€€€€a}€€€€€H€T€!zq"ހf€€P€€€€ba
H47C*€€€S€€MÚ€q]Â€Â€È Â€â¾j€1e$}€;€€€€[Û¿@Vpx€۶€€€€{€&~€€t€€N€€77*€€++€6{€/€]€`qiy€"€€€€€ +€€ۘ€€€Vzܘz€€6€€€ܰ€7€l{€€Xf€g€Wd€€€t€€€€앧{}€€€€4ᨗz€it€"€€cK€e€€x€€€€€;-€i\9€€€€n€€Ǥ€€d\U€€.€€€€€ujq#€Y$€m€] €"€1s€ݮZ0€d€€€€.€€€€?€€^€zM€u€€€2€Zd€`€€!Â€Â€Ü /€s€€€€€A9€€€1€^€Z`Q€no€5 r€€€?=9<u€€H|€€€€F5A€db+*2l+.€̙q€~o€ K€€€/€€0{€€yA1l€!€€-€€€:/G<€€|K€€€ވ|€.€€€m€FG€€y€>€€ކ€Kd€€€|z€_€c€€€€€€ЈtY€ €/€7S€€€€€€€€}€€u+€|t[8€1m€Ïګ€j€€€fR}-€^n€€r€€€€v€€**^r€Rj€€y€MEe€€€B6€€49€'ToЄj€€€#€t€€x€€5Ŗ€€€ƒ€€€€€€Œ€€d#G€€€€(€€€€|€.€æŠ!€ #o€€€€€€A€€7AF€€€[4€€!€€€D€€#€€€N€€l€€€Y€€€f€b€€€€€€_@Õa€X€kJ=7a€€>€9€€w€€<€€€€h€€€€€€€€HU€l€O€X€Լ`€
€€-h'€-!€€€€ +y>€B€X€€_J€€€€[€€[€€bvE€\€H€€€€€€"€o€J€љ0€n€F,€€KÈI,€€€€-€€€€€Ss9s€l>'0"o^€~0:€MJ&Ê€Br€€€€lW€α€€€€i;€f[oG€€€€€F€6€€q€ €€€|€€€w1€#O€2€!DgF€øzp0hO€€a€€c€€€€Gt€#Ì«1ÑŒuQ€€E€€€<k
€g€€/€Ř€p€€€€€t#€j€€€€€€€€€1€`€€?€7€€D€?v€€N€N#€XG€.(€|€€M€@€€T€€Rs€€3€t€€€€€€€9X€imI€4X€€T€€D\€tNK€&€€0€b#€€€*Fx€p{}€-Q€ȳZttBc€7€€€€€m€€v€€B€€[€€Dz€€+€€€€€,Ks'€€BDOK€€Gs€€L~€"€€"'€€4s€.€€e,€^€€zt€€1$€€€f-€€€€€€ȷqc€x€9€€€bNZ€€€€€`€€\€2/x +Ԛ€Cwy76€€}€€1€€€-€€€k€€?iT€Kb€6<€€2€(=,&€+€€<€5€€ +€€E€ €€€€€€r€€€7€€€Qc3€€€€&€b€€V€D€€€Y€€g€€רd€J}p C!e|ݳt€€[l€€€q€~€€€Q€€€€ݦ€ٺ€lØ Â€r€€€7€€€€G€€]€€a€€|GA€ȅ€_€€ +#€€vECSUgT€kM]€ӑT€4€€€€P|€€vnh4€€)qKက€\€W€;>€€€Xߛ€3€1€€k€€€€€U€BJ~iHų€€P€€€€€€s€fv€>€ۗ
€ +€+€L€€€€Rp€2€l€^€€m€ +n€€5€€o%B€cK0>U~€U€€€N€€R˾7|`0€H_L€D €€#€{€Tf€P€c?JW€€€€€8ı,€€\N€XJ#pۣ€!꼱5€€€c€
€9C€@P€€€€e|€€ +d!^U,€€€֊€€€8€ʢ€$€€%G,]€X€€€͛q€€€o€€o7€X€€€l€,€€€€2€07€€€*qz€)t€€€PW€X€€€1€^€J€€€€e€€€iY +€€€€M€€€~ܖ€ÚΡ€ޗ€€€D\M_JԜ€€€€Ҝ€ [€€€€€+[Fu€€X{[=wӵ€m"oÚ¯Z,€O€€€€-؉A€€t^€€)i€€&L€P€€Ll+€Ě€xÖ—(F€;€.€€€€€€€€%€`pI$€A€€€€!€
B€6€S<€2€€f€^€/€€]N€͛ +€]€M€€|-ZW€w}€c€c€€€ €€€/I€[lV,c€N€€_€Ô€^€€€€€]€€N€Z€n€
J€ш€€9€˺:€€թI€Rw*Õ€ߕU€ѹ€€€€€€€€€€€XYУ€€e܅€€ɸ€€ֽ%~ÜO€€>€€€CEN\D,€€!O€€€1C5€€[€C€€jpӆ€Ċm[1aw€€A]I€€€€.€€>}L€&<€€
€€@€€.€€€€€€)€€€k€€€€cX€7b€S?)j€€€€€PE€Z€j€x>€€€s3€,€€"5€€qD€€i;€
€p€€xY1€€*\{Mn€€€h€€€+€€€y1U€A€<RW =€€g€&€€€€€€7€67€€€€€€ҟW€/l€g€€+€#=€€€€€€^€{€€€€€€€Y€
L$€€ƸÉۘ€1&ЛF€s€T€€ٮ€J1,Ww€€r€}€]RN_€`M€L€ +€€N'€̢€€€€€€K€"€€€56A=€€Z`€€€€€4m€€€OJ€\€€€D남X€€<€lx€6G0€€(:€>gA€*4H€ €Ջ€€(0€#€€€€€$€Oh€DI€€?CuiR€{d#€7D(€ޥ€€€€ʉ€5#€.z€äªÂ€x€€F€{€e7€€r€%q€€€O13€}+€*;qYv€€€=\u€r€w€3€€D,̒€€€€€QAg€€|€P€x€€€€&€€€€€]G1e +€K-€€$@€R/e€j"€€€HR-+r€:!€€o€€n€€U5ع€O€€/Qޜ€j€€€€€$€€€€€€€€€€rn€€€,€mΥ€€ߤ€.Pa€€€€€a€~€]$;€€€jɳ€՘p6€z6Fd€bdI€€1T€[€zw€€]m€€€€3#ƞ€3€t{,€€€€Җ<^ad€D€\'€€€€€€0>Za€j€€z€v€€c'€@€<€€€;.€€ R€I€€9cN/M߰€€€€€jE])€€€€K€SW€€kwAi€0€€+v€€€€€€S죿~M€$€3€€=€€|Rgs€€vb€н€€g€X€J€.ɼ€€r/€y€pui€C€€ €€€€€(6aì«¿9€M€7€€Mt€€~€€€j?p\q€€€VcN_€€€A€€0€cY:g€UG3&2€wH€€€€€&1€€vZ€!€όh€p€$€€"€X€w7€.€}a€€€€f€\|€€s.€rzɲ€€€€€€€M€_qÊŸ^€€€€d€ݟ^€
€x~5E€嘜€€p€€&€€€j€F€€`€€€b] )_å=83€ۧ€€C€ut€€€€ͺ€cf€€G€€*2\€d€V€u€E€Ѱֻ^€8€€€€€€€€€a€*€bb€W/ľ€€~€̄C;'€`€FЈ€p€`€€'4)f€'Y?:€w +€\€€G€€€€x€J€{(F€Q€
>Bre€k€€€6Ż€€»€€€€€€€t€€€=C€Ì€9€t9Û€€l<
€shF8€€r'€€€
;€vTE€5]q €€MZ€<€3€V9Mܺ€€gQ€€~0€€€€€v€T€€.€€€:€JQ,Cj€2 +tB€٩7€€i€€w€?=€Y€b€€њ€w/€1€€€€€@€€€€&€zxe]€}}€€€Q€€Q?€€€7€€C_<€oL€ €€€4q€&B€G<€€€F;юN€€-ljR
€5t€Uo95€€€€€€S€€€€r<u€P€-€€€s/€'P3FV€€3€Uߤ€$H€€€€@€6d€€€€]€L€€€€€.€:=€€€a\}€H2Rai€€€€#€S€ޞ€€€€l€K€€aX)€€€U#]U€'gX'v€Ȋ€ɹu€r€€c€_€€€a€€zՔ`€€z^-€z#;€6t€6M€K!#ed€O1MJT€3&6I\€N€7Z߷(€€€€€€€€€g€9€Ys€€~pj€€€€€€>€f(10€€w€€€4c€Pa?cb2€n€l€€€{06€€F;€€)v€Ä€€€k€;€:|k€€€>S1€ €€€€€€cW€}I€€€[€:€€€Q}/€x€U€€e)^€€O€€/u€€,€€2€A€€€€7€n€€@€+€a€€€€ehSJY$€H€€!?5€€€€€ᇷ€€€H€€€(€€>€0€:€1` ^
5€>€€[€€浚€,€/€€Bn&Ò‘|g€j€+n<S€2>€€€€€€€̱ܟ+€o€=€6u€€nl€X€€.Ge€G2)=€€€€V€€ۉW€_R=qy€€t\gy€L€€€€€qxI/.€L€w\Uj€t]€9€&€ovY€€€€€ez€,€ۈ€|/€3€u]OY€?^pwh\ hG€7bK€€€€H€€€€€€fF€€yQ€v€€^€€€€€`€€€`:Þ\Z€€€U€€€€6a6€€jM)=n3SWV1"€R3€M€€^z€z€<€$€/€6€€€W€L€Y€€6f€€{€€,€€€P5ף€€€€`^€€}+n5€€€€V€+XQ€
*€€O2eN€€ +/7€€ €:€€`;€€B7jp€€€v7€€€7€€€€ €+j6€y€€>4€€)€€€€N€€€€€ܨ€L€%U*€^€Z-JÜ‚0€O€" +`€̓€3€€X€€€€€;€€€€€€€Z€€€뵙€€€€0€ݮ€€€ΉO€€[€E5J€€€U[€,!-€€S€€€€€å¹Â€Â€Â€Â€1KHǨ;a€€€€€J€}€ +€€z'BMr €€€7€€€€nyĮ€J€{€&5o€B€B€€-€€'5;€ +T€€€€€€€C€€€€0€]€€!
W€ɇ>€€€8€e€€€€€K<€ +€kÞ<€€€€i€ƌX€€2V-€Ws€ +€;q€m€€€€€€[7:€k9€{"€€€€€)€€€OPx€€/€€€€€€\€~€€€€€;׷€€€€<!p€€€€1€˿€t9€€NÏ€€€6?;€€€G€€€€€€}=rT€€€€€€€€€-€{y€€€€ë
€
€6mG€€pQ€8C€€*€€fY€I€€V€d€€k€!d$s€€€K€pʨ€9€wC€i€ȋSsV€€€}€i€dG6€€€k-€d\k€'€Mܵ€€€€G̜8€€€/[vn€x€€€-9V€X€€}=€€5ׄC€€€ €;€€ص€€€€€j€5€€€;s€_€;.€[vi€€aM€€€4€N€€€€€ܘG€€xg€SkAm€€€€'€€€*€5€€,[€€j€X€€k(:€nM€i€€
m€,N€c€€AY€n€u€€€€€ƥ€֯`V€€€€cﴋ€€`€V"տ€€€€4i#6€7€€€€€€€€w€€i€P1D€€€w€€€€/€€{€€€pFi€k})O€€€€€€l`=j€€€€`€)&F€€b€€R€:=E€\€}_€€€p]U%z€3h߯€€xi€x€€ؕ€q€IiOÊI4Y€€€€LµH!€€˷ X€€=m€€€€|€€ €€€€€€7€€€ؼç§Â€Â€Â€g€ؼ稇€!€€2\f`€c€€C€}u€F:€€П€€G€p€€€9x€€Ļ€€Ig€T*`.€,Í€ib€€(€€€a€€€€L€Aiq€€"y1ј€€€H€€è¤Â€Â€Â€Â€Â€Â€oÄ¢{€I-€K€€al€€9xK€€€€"€€€€ +€€>k€€€€8€]*D/€-€€u€€ €€€o€€€€€€€
€€€o€€€€]€PBl€_?€€1QB€€o€€€€€€€€Ao€€€v'€€TR€/€m
€€cz€€{€m€€r~€€-€v7€}€€6s]€€€~€€€-€€€,€€)²€€ M€7€€€€€€ߌ€|'>€C€€3A_->/€€"[€€€[n€€€#€fW*€€€€*>€€g8'€€3g€h€€ +€íQ6€€6€€5€€€€SK€`16N[W€.€XWS€`€RkM€€€p€€€€€€
awkweavee.SYM'JUY9€€€€MPSTMPS €N€€€€%€$)}€Y€€€ €€kek€ir€)€€g+€€€€€€\€f€)€|€z[€€€€9€.€€tKm€u€€€wr7€.+€̓€€Q>w€€¶y€[€€€€"€€€€|a]B€.rH7ۂ|€]B€'<υC~.laۅm€€€€€V^€gg€€€bץ€x€#€z€€€€€€€€xV€f>ç€nuI€€t€LI€DHT^qs€€€€sV€(+€€NgiذnCK€€€B\ZY]€€"D?8€€3€€€€€cl€e€o0€€#€€€€qE€€B%€/jJ€D€RQ|@€:*€J€w €€*€x€.i
€€€€MK*€..D€t€€3ejH€€€€€€Bah€€WU€€€€|€€€EdY€=€€1G€€X€89€€K€€€€t€K6€€}€€€[kܫ€€<P€ӕS€3k€€2€€)€€~f€€€€/U"€ڬO!€€€€€y\€<€@€€%€?€€>€€+r€€€€מA €€€hE/ €€@' €€€NJ€K€€t€€#Z€€y\€<.|€K€[€€{€€€G€€€+€€f|€€€Z|€€{€[€݆€€€€C€ܒ€7E€^R(,€€U€Ց€t€|#7€€U€w€€€€€€€y€€€€e€€€ݩ€oR߻€€€=*€€d€€€€€€€€€'€€€€€€€€;€€|€_€€x5^€€g€€€€€{€|'€y'€!€*€€m€-€:€€€)€z€|€€;f€|€€x€€€€˒︵€€W€€€€;€Y€N*W€€€€€€€lW€.€T߷€wJ€€€U€N€€)L*€€]+ߺD€ݬ€€€€€€€€€€0€€€€Q€F}€[€€|€€€€€|€ժ€}€oW€W€F€:€€f€€>}yo€€€s€€ݧ€€#€€p€€|€€€*(€1€€€€ϗ€€€V€'~€€Ak+€ߴzo€€(€+€B€Ѕ€5€<€€€R.:€€|€€€o€€€€€€T6 +c€€]yo0€€€€€m=€€=
€€^?yY€€}€"@€€KS.€w€.p !$€~€€@€xo{owk}SCSkQj}mE€€€C€x€€€€€€€€€7€g€wu€D€~ oUg€€€ -€@W€€€€€€€%€,€K€C_€€3€zU€k€€€€Ž6a]6z€ €W€€€X€€€4€€€€€u€*€€ׯoi€€ +t#€!€€3€!f€?P€!T€€€€{X€€€!:€€€p/€€Ge+€€.n€ +!€€Ӓ€г#^_)€€K€b€,€0€ =P€€`€}€+Wx^E€€€:Q|€€€€€€€zM€€qN9€f€€€ #€€
T€€{;Oe€€8T€€ €€€S_€€€€€€~€€۩€€ߒֆ€NoN€m€|€精€€€€€֖€vF€€^€'€V€MqhCë…£K€€€€€€-q6€€€!€€€Cr€d*N€7€€€€€H€:€€z€€€€a€€€€E*€j€'€ _€#€>G€€€P€%{R(f€€€€y4?qhG€굸€?€€€h€q€:€€\@ÓŠL+€ֶ€€€€€€o€/€n"k€€€€€C€H6_:"Y€H€'€$ܺS€€R€;E€€>€R€€oq€€y@$€V€€a€€€˂€€5€€Í-€\BQc€€J=0€s€€ye€€€€€€
5<€ӿ€€Ѓ€€€W€€{€n€€€€ 3€|€€€UfN€ϲ€0L€-€S"GG€€צT€F€€€€U€7̉L{€5M{€Q€7€€v€€€n~l€c€9€€€W€ ޴Gx€€€€9€€
€+€€t€~Qs€ST€€€€€€€U.€L€Tj€:€*€ €€l€€€F€€€ €6€0€/€U€
€€€€€€!k€€%€€€€ȷ(€€€PH€€€sį€€3A€ь€€f€€€)€€T€€€[€€jde€€€€^z€/>€€€ €c€€eG㮼€"€€p€Dܿ€`Q€G€€€U€€€€€om&v'€€X૾8€W€€3€€8€€€€€d€€D`olǟװ/€$€€:€€k€€%L"€X€€€xƓ?€71€Q[€€k€€€i€€/K€7u5So€€T_€Z€%(€
Ɉd€€€
q
€€€€€~€ϋ6`KETKUK{WSCO€€€€€€h€€1€€€€€€€€W€w€€€՗€V€7€z^€j€,€t€|€/€z€€[€7P€M€€}€€pq9mg€€€ї€€€g€€€c€Q€€J€}€€=€qh3€€€z n-r€€2€G€:€€^]Q€€T=€€€€G€€гJ€€€"Rw€.v€€€+€€€€ˇ.{ܣ€|\€€$Ql"€€)€3/Y%€"€d€€s€€z€D€€€c€€)€€A(€i"€8a€<SJrDÚŽXDK€(u7Gc$r€€€Y€€N€€QR€€S€H€€€ L,€$€d€D€€qr9€€K€FQ*E€€{€=€€€€€c€[€€x€~€}€q€X€€€2€#]€{€€#n€€˸G,<b€=€€€€{$€#A€€g€€€P€€W€€€=€€€|O€€(S€€B/€mQv€F.^.€€€B€€€%Kls-_V€€€Ӛա€Sw!k€€,€;J€B;8€€jVu€S=r€8€€tYٲ€e2~€$s6€€*3(€€3€EccYr0t€€m€6)€€5€€€€€ €€€€2;€k€€'lj€€d8€TQ€7K€€€€€S€€(eR€e€€P€X€€€€€ f$€€`€€€€€~€{€D%OX€€€ˀ's€€€€_€€€€w€L€;|vÏ‘%€B€€ꖢK€€c€€c€€sp}€<€q€€€}U€z€€€€&€o€€{€€€€3€ +€€kl€[€€€Ӿ€€5:€=€€€€ï€\€€€€€cN!z€€Ùm€€€€5V9=&€"€€="€€€€E€5€€FDZH€orcJgÄ”n€€x€o€Rq€€€.€€€€:3S})V€%€>^€|€€X€C€€ID€q~L€€v€€־KB€€:€€€1€+€€_,€€N|y€kBD€1€]€€€€€€3PU)€=Շ€€a€=r€7|6$€€u&€1€€€ͽH˺€"€1€NL€€€Z€>€wm€€"€€€€€w€€€/Y€€ϊ€€€X€€€€z€p€y3pY€€|y€w€͘€€€€Y€D€€ +€€|'€(}€€v€/€>ݾצ€€m€[€€€€?€€(€€-€€€€€€̼€Ϯ8€€€c€a6پ€p€
}€u€,)€k€€`€Þ€€MEPcI1ґ€sA€€m6d|€ӡ€€{k€ZgߌhM€€j€€K€€€~ߧ€}*€R€G_€.€€€€L€\W€€€€=€€€ +wЛ€?o€Y|€€€€€=€Z€3€;€]E\A€€Y€€€€€€
=
J[g[O[C{€Ɔ€€€N€€€€€€<€<vNuw;€ ȣ€Vp€€€8€c€€S€X1'€o€€€߾€€|€€€d€€I€€€o€Î€;€5€욂$€ۄ€€€M"€€[€€co!k€€€C€€€€€€ȼ5€€F€€>€€€€,DF€H€€€€9C#€q€U:C#€X€ko€R€€€€€€Ȼ +8€(€;€*€>c~€€€<~€€`€€€€€\€P_€Ä€€ + €€€1¾€(€O€€Ʒr]€g€ \€€Y€€€6€6L€o€€:€R€€€7€@€€€}u#~€5_:(€€F€€€/€V€€€€€€€ +€€><<7؅€b"^€€܀€rnp€@lÊ¢/€EgmEA&€\A€^B€€v€€€(/O€f#€€€t€€A€€€€>€€€[€bH€€€u{€F€€gH€^Z€€Ro*€0€€€,4€rW€І€€u}m€€cG}€€7G€Yr4€€7+€7€|€<€zÇ€{€7€€€€€>߆y€€@5€€eI0€)€€k€&€j€€~€\ç±£@ɡ€€ +€]€€€U€€€€][Q€€€€1{4€€€€€5€hQa€€ZM#€€5nĄ€€€B+€!€|ϱ€k+j€ܷ{€€€ګy€€€€p€€€€€€€€€€€€t/:+€g€ +€@€€€*€~€>€aVtO€T€^~€8€su€€€%?h€€ +L€WÕ¶G€u€€€€€H€€€}€T€€€€j4€c€@€X€€E€{€€€f€s€"€€I*xÝ‚z€-€ڣ€*s'{€kU€c€]€€ͻ€/€h"t€2܊€`K'€€jw
U€^dǨb€S޻€€€?€J€‸€€€€gTj€€(#€/=€r€(€*t€(<€It?t€€%€€QY~u€€B€;€€ʊ0€€1€do€ȧ€€>€8Q=€+q€€€€€'57S
€€"€€,€G€€o€€€Ð€€€[05f.€€b€€€1,€€ל€€€€€d€€u`.QZÞ»t3€Ex€.
€+ւ€A€€g€€€O€€€%:W€€؛€%Å®b_€5€€:€3€€€€p.€u]€oX €uyx€€€O€€€€s%€€€€k€[€x€`v€€L€]€\€zq€/€€€x€€J€€€>4€"€€i€€€€€€y€€€€D€e"f€€~€€€€֪m€€€€(€?sQ€Q€€&bZK€f€m€m€€f/FÇ”S€/)€ٙ EG€€€Ï€€€€€€€w€€€7A€g€€.€dÄ›2€€€€|ե€€€T€€TWV€]€(:{E€vY€݄1D€€X€€NA+ʇ>W_€€€€RθF €"D.€]b€$€€€L€n€ɛ€|̔€9T$J|€€|€€€X€€p2g€€€1~€€"f%€V€]*€€ܵ€{€€€5%\€€xEYqI€vd*3€6€€_b@€5b€"9Coh€
€€0C€€ٳ€%KVU€€@'{€U€ +€€^€8F€€€:CG=€Q_=€Z€€a€€(€€€^€$€€7€€€€S€€€€€I]€Rj,€[€o€€€dUU€%I€€€€€€:€5€<:€03*€>+s€U_"2€€€€€C€
1U€:€€]€+€"€€>?€€>€€€€l€€B€\€׸`€€€€˺€=€K€€€E€O€yYyoּЈR_€€€€i€€€€€€sK€€á{ր$MO]€vh€
€ +z€€€*4€€F~|€W1m€€€€7++€~T(~€€€3j?ܯ[€€€€€<O€€y€€€б
ó0€€€u~€€€|a€€€€€>€ €>/y€]€€+ѻ€€€€Y€€€ɣ€€%€€€qG€F€By3€€€|ؿ€€w€=€˵7€'a€€]€U€⨬€€€€zz€€0€)€
€€€ɾ}€€=€€{€€ѷ€€/TVx€r€€€€€;€,€E9€€€H2©,€+$[€⒋Ct}r€qCSWGGWg=Í€€r:€,~€%sf€s€=`{‰€€r€%€€€€f=€W€'U€DÕ›z€/€€€€€€€€W)ʜ€շ€o€€€Rè”u€X€{€€€€z€j€€uk+€€?€{2Lؽ€€€€ݴ€ױs)€/;?>Â€Ì¾× Â€ 'tÖ¯;€V€€A€4€€€€_€W6€€€€"€1€€€€€€o'€€€w€€€7€eHnX? +€ym~€W€€۟€<€€€ +L€*Öš €96>gK€}Q€€€i€€€€ݹ€€Z€k€€n€€€7€d€P€€€mlM€€€RC€i€`m€€€€}y€€€€€€€D€g2€!-"&€€ €€Q€€X€€pf€€V€ot €€€€€€€={€ƪ €
Z-€€€"€€€€:Z€{Z[ê› )€€€7€z€$,€€€c€m€€€~A€€AO€€~tp@€{€€€€€/€€€€€A€€#e\€&€€2?€€'€€€C€€9?3GeK€€K€ܑ€T/€GiZ"+€yN€r€€€g\Z€D€n +G
|Tﲞ-j€M€€}W€Y€^€{[4€q€G€]€ʊ€€Y=C€€Ԯ€'Y€P@q€€; +Q€U€€€M€fx€8Û½2[€€ +8€€/€€㼗€f€€€Ï€€"€y×€€€S€€€€€z€€€<€}€x€F€b€֩fr€d€+€z€[YK€€;€€€y€€p€€€€€3€€;/5©΋㌪€(€F€,€0€€€€€T€€yma@̄€€>€€V[€€Q<{.€€€€]€^€u€€_#€iL€€PY7@1 €9<K9€UƟ€€!€€€€€1r€؄€€{'Pr€€€vóR€|€/€4€€€k€€\Uc€€€|0€€€€r€€O€w€g€(€כ€€Oo€€€^€M€CR€€.6|€/€zM€u€€U€€€7€€P1k€€=€€€€yz€€€€€€€E€€I€4€?G€€€!\€€€}€€G€9 +€€€mkD€€€.€B€)1€k"xx€\€€"€g€€€fq6Ll€喝XØžUm؞€€bgt€#€€€€€W€?€#dtAy%Y€€Q€|q€€€y€€€y€ShÄ“=€€€fs)€G^€h€.€u€€`€(6€Ql€l€€@r€€;€€]'€va€ᔳ€d€€€A€€g€: ׂ€p€€€\G€>€€Z€¿€d€'€€=€e€€€€€€Y/3@B€€€€p€C€_T€RL€€ +8o{׆€€€€€Pp:8ԇ€̶€S€k€ɌZ€2€€7€[#€Y€-23€I€պ:€€€#p€€€€€€`&%€€€€€€€€wg@{€W€€€€€Hl€<媬€1€t3€깣€€a€€€€€€€"€K(€ؓB€€u\[€,t&€€€€€€u€*C€€Qx€€*€C€k€9x€sh€€`bՌ€Ã€<gp1€+?l€ +€€€€PlC€vt>€͞t€E€>€:€€€SU€U €"B€€p€€€€€€'€€O€€f€€€€3 €Ӧ€€€€€o€€€M€MQ€6€€€€€ €€h€€€€jo€A€€k€€˿€€€g,€€<iU€€9N
€x'G€€€€T€€€€}2W"€€5~€dlRe€€€"
KS€1q€T€€€€A€€€k€ղz€€Y9,€€€TN;€€D€€#3B€€€5€€=ư€;€€N€=€€͚ +
€€€ig5yŧ +4rkv€€€h€€ӮUÅ’ZRZ€\€€6<V_€€€*0€*€€н €w)€€€€*5€|q€€€o€€h€€<ajz€€Ob$€9€N%Ý€yq.€_€&Ewr€€€`€?g%G€€€€C€€€X€u€$i<€€€ԟx€xe޸€#Qm€€€t€(3€+€Ë€€€Q€€€?'y1€zƸ€wN€Ce$€€€€J<ÔŽT€€)€€€€'F€R€€€u€€€€€€€€V€€E€€V€€€€f€€w€€P€€€}$30€B€ N€#NÅ«S€€Y€b€3€Þ€#€€qx€€AT1€€€zBD€€€€€€{U€€nj€€o€€U€€hNM€I€€nY€€€e€A€€Ò€Î€j>€€H€€IW€C€€ɮͮ€€C€€ €w€hM€Ue€L㋊€{her€€cN;tmV_:1€€M4A€€€€<€€€€X€Y9€€€D?€9l€y€€€<€K1
€€€~€€€
G€€€֧E4-€€€>€?€€ €Wn€Q€F€€S€QU€(€€\€€€€€۾I€€€xI€€D€v€€€€€€%9[€€€€€€€k€€J€€t3€zƟg€W€4 +€r~€€€'€n€€€€$€p€€WM€€+'€€€€€k€ب€<€xY<)€ճ€€lմ +€*L@€R6€7€|\_€7€S€€€թU€€€€+Tx€€l€c€JT€A€€l€*€€€&€€€|€€€7€<€€€y€€FO€j5x€€]€e€€€€€
-€€€€€#€€€ h€€5V€€€€Ѻ€€€j€L€^€€€€€€€€€fcK€Lj€ €€€u€j€€$€
j3€€€1(€peI]€€x€Sn€€€€€€R€€€€€€l€€€qW€iU€€+?€+€€€`€*͆U2€ה€€2€e7€€€€?€M€€B€%}I€Q€ €€€€p€€€e€0Xhq€F9€xs;€=€€B€€w€t€€€N€€€7€)€€7€A€4€yske<€f€€€€€€5^€€€€€|€€€€€€4€<€€3"€BS€€€€i€~€€€s }u€p€€$€O€D€n€€V€€€l€@9j€€€'€€MD€&€i€W€[€€D€;€€€€\€€€|€€d€€KY€€€"}€€H€|€0AK€I
€UFXHC€€€€1€Dh€€€€!€"6pOs_ +c€€8H€€€€C€U€€€<6€h%€€€€€I€€؊€#€]€U€'=€O€€U|€(€€L€€€r€R±n€€hy€"}€h€€
€|€€€€dt€€u€€w'y3€Vz€N€ DX€€:€7€€:G€K€€€€€H€€U€€€=xLj€€p€€-€€R€W€€€€xkɬ€ع€no+€Ur€€€€€€€]€hkI€€a€h֕€ٌf€€k
€€€>>€V€€€€€€dm}€VZ€€}~€€€q€S€q€ €lɂ€>€-hRBb€b€€€€€€€€_€Yx€€€x€€€€j€€€(€€€€b €€€€€_€x5€€€€€€€kT€€€€~1€o€+€€Zd€€€X€€€<€€R€€uXl€€"€#b.^?€€€/€/€€€W€p€€€€ϯ€Upv€€%€€€€€€UB€€P
€^€€€=Ǔ€€€gЩ€€€f1€ᛨ€€€}€€VD€€€J|)U€W€€€c€€€*€|€[(g<FBO€J6€€<v€€*€ʡ<€€€0€)€€t;_€>n€q<€/€€T€>K€><Åϲ€w€€)€€€c26O€€<€€>€Oϔ€ƩY€1y&:€€)€[€€a-€d€€T€€Q€€€€€a€€S€<8€kx'€⑩€€3€ú€€€>€€€aޘ€€?€€€Sq€;€/Iz€€€€€€€€3€c€j0€€?€OZX€€€I?L€xrxp€f Q€€҃3V€€R€oL[8€€c€Av€€€`1I€3߀€€1€€€+€Q€€|€Oe€€
<8€€€€<J1€€€Y\3ͯo€€€w€AW_€";€€€€€€U€R€€€M€€:€€=€[Nz*€B€7€€€€!€€jZ€€ib€€y€€€€^€€Ц€F€€€€€€€€€P€S€€a€€7€€E€€€€^s€€€/€€/€0€€R€1M1߼;&r€€A€€€€ x€4€q€6O€€c€P嬲y€€€_€jГXG~4€ƫ`€|€\)€糅€€€w€€eC}€8€Iu€9€€€€Uv€€€3P €U]€
)Sv€HثU€lu€€€C€€€֬€ܪE#€G€€>€€ʹE#€Y)€€€Lz€f$€€s€€>€0€[l€€*X€m€€C€€€€:6a€,52c€H€€€€J€MO€€€€x€€€)€(€€o€f1€3՚€XfKKt~y#UMK€+,ɒ€'f`€€€R€€€€Hx +€€R€(&€mwҘ€€30[L€€M€B9€Г:y€>u
€€€;h€€€€€Q€gw€i€r€€1m€VZ€P€€Y€€€UP€@€€€_€f€€(r<€€€Ƙî‰Â€xt€€Z€€€NݶnR€)€€€0€€. €'sh€uJg €€€ €E€;€ᱽ{]€€ĎFh7€€]C€xg€g€/€ €5I9€€ D€GfsÔ“3€m#u&€`€€4€€€€€0+dR}b1€[j7lE€€€W€ x€4€a€d€€€€€€ïZ€€V4€9€€€€Vu*€m6€X€|€€€潄€;O€€€€د€€[€€€1€€y6€!€!€€€+€6€€34€(`|Jt@G€xÖ€€€€W€€j)y€€YQ;9€€€#[€N€ €A€€p€€G9y€V€€€W€4€€€!*€€€ÉV€€=€qU€{€Y뀊/€€1€€f$€€€€€€€€¹€ €}€€€€ludq`€E€9\€€€P!€€$<€s€z€$1€"q€|€€€$l€ ;€€€Y86*€€֬ǺUl€€Mz€Wm€m€nh€€"V€\€Q728€€&€€€€€ +€[€€a€€h€€€ޜ€€€€èŒc€€€€o€=€€ak6sc€€€Z€s€€˦h€€€€0G€>q€€€(c€b8ν'8€€ѵ€Q'f€f z€€€G€g€g€Z€u^€€#€+B€Sq€EemÖ€w*€Ņ€€€€#€€B{€F€€gK€€€€|ሯڜ€]bRo+;€€€!f€€€€z€1€#=€€Y*€€€€L€€N€€€€€l€€U`€€P€€€D̳հ€€€€€-€€,+}u€€€[€,_9€0€pļOQ€€€G€€€p$G€€€#€€€|€x€b€s€€5€€€9€yp€(p€€y€|€€€€€€€d€c€Ma€S€n€d
€M€q€€L€a€9€X€Y6b€€_€€€496l?5?€€u€€(g€x€€s8€&€=2€W€v€M<€€€Ij€€€:kT€€€S€€€€>€/R€€lQܕ€.€€€€€€€€Bf€€€ m€€€g€€@Q€Æ?€€€€+€€€;H€€ +€ +eɘ-e€€€€€MG€€€€€2L€€€€€fd€@0<l_€7ȹ€€4€u€€€ӱ1=4€P€ⳜX€€ʗl2€e€4?9€€€€€€:P€€(€€mE€€€€€€€q€€€€€€€€€#€#€;{E€]i€z€€€€€€€bO€€€ҿ€
€€€qh€6j€]€€€=€~€D€b2€€€^€€€7€€<€€P€ix€U€^€€=€VE€€gU€€O{@€25 +€€=€3w€€€ujS€E€€s€c?€€JϚ€=O€€€(€^uRf€€=€€€'€€gTl€-€<Ɍ€YWp~€>!€*F€€€u€€€;d'$~pT€€`{c€U€€€X9€Q€\{€€ €(€ €€5h€wM€€r*ޣ€€?O€<o/€€Oœ€ N€{€2€€€€€x€€yp*€Tl€€€€=6€€w€=€x7M€{`<€5€€<WNE€€n€€<S€Xs4€€z€63€€GC€€€€t€€€€€Ô€€9€o€b€€€7`€€
v€T€€,€&€€y€ս#GX€D€€€MM%€^€€cç «Â€S€P€€€Nu€Y.€O€.w!€.€>€€2.Lb€€€€u€/;€1€€€€€iÌ“`8€€,€€€€tË°[Ù³z€€XU€d€Zd€#v-€€#2€€>€lh€€€€€€p<€€;€-€E€ +€€q;xR1[X€€€mÄ›r"s€€^~€}€€€Z€€(€4€€x€€€ho,€rz€^t€?Ή€x€€€€€'€€n-€#€%€M€Q€€q€d€yS€d/€€€€&1€ͥa€h#.€€"t€k€€€€_H€€Z€N%VH€€€+Å…{)€X€zSx"W€Kd€X]€(ms€@E"2^€€M€L€€,泰€L(€X€€€€€(Pǖ€1"€€€f€€(€€€€s€€€€€€€€V]€€o€€€€MQ€€E€€€€q€M€/€€€m€i€ݪ? +fˈ€->€€y;€€C€T€;K€TF€fO€xd€Ѣ€Z€U€e€€€cDU€mN€{'p€&J€(€€€€{['€}G€€]R€€€ۃ€O€5O€€V€G€€׷bo€Yn€€t€€[€03a€x€€v€€0€OQ€€€€ ꎓqe€€Pi€=€/€€€€{€€Ʒ4i3€do€6#€€,f +€€xy€՗#ñ€€d)€€u€€€W+€pO
€€€€~u7€u€€€€€€€L +u!€]€€bP€€i€VB€€ϘpWs€L€€€€€€w1 €€€€€€€
€€€€€]pN†€DR€€^`E€ro€3`L€M4€€U|€€ɰ6€€€E]€€d
G€r޻A€€V€M€m€€Y€€W€2;€€7€g +€€7PM€9jc€NfB{€2 €€R38€k +v€^€b€€Z€€,€{n€€€€€€V€}€€7x€-1R?7€#€€€€c€B€1€KV;T€(€€a€€€€K€€€
%€€€j€ٚ€G€_CѢ€7€€"a€lP*€x€͆€#:€€ޕw1€ϩ€€€€€€;€Ð€€€-€T€€€€€Lj=ìU3€Z€fn ՜€€_€€€€N€€fEȘfE€*Z€*€€€ €r(e€e<1€€x'€D(€2€Ĉlf€€1€Ұ€€@€€€v€€€0X€€€f9€€aP€€€)€+k€a'€_3€€,釼p%€]C]€€p€€i€€5r̼u€e€€u€€€,€J€{€Y€€€""M€c€/bH€€iؘ€ٌ€€g€€€1:~€€@=€?€^€P>€€$€€xY€€e޽€€€€€€ݮ€€€€€?€€j€tf€b€LG€€,Sj]V€€y€i*h€€{€€€€]5€€TN€>€€HЬ€€\X1@€€'€€€€O€j€€/€6€@B€r€Yl€€€{
€€€€~b€B,€O:€C€€€€M€€'ۀ€€€M]€€€5€€Ƙ€€l€€€OT€O€Ca2V#€?€h€€c6o*€R|&€b€€:€Dƚ€D€€qfy€&€€ĺ_u7n€€ho€€چ€€m€€€€ +€,€€€;S5€€€?€€<n€:1g€€O€Z €ojÀ&ٙ€&/€rKo€€€R€`#€7€€*€€,€€€D3€€Psx€€9(€{Nf€ʷe€€€€€€€€({€€€€H€A€€R€€€o€Lä®Â€sN)€q€Y~€x€]-€?€Ë€֋€ G9€A€åŽ_/GY€€q€€€?E€(oѦ<\['3!u/t€b€€€€€g€8m€9€{€ιW€€€b€€غ~€€é¼Â€Â€Ò¿F€€€yUucu€Z€˞̫,€€$€€,!€iq€€€}€x€€€€€^€#7€o€]/i{î‰Ÿé ‡Z€m€€€Th€ނ€S€/€€I€€ڄ€y€@€€"€€b€€I€€'q€€1€€€2t€]€Ϋ[€۪€€€>€#€€€€€.e€n€€€z€€rW€€€€=€}€챑=xk€€€€€€€Y€(€€V=X€v€ƨob:z{ÔƒU€G€€z€z€€#€!€B€€u€€z €€{p€€zH€ս€€€e€P€€€€=€€B€c€=xo{€€€(€b;]€1r€å°Â€Â€evg{9€€~€€]€ѪwG€V€P7€€€R7-€C€K€m€€vÚ–`9€K€€€€€€€€r
~d.€o֦P[o0G, €€@€Ill\D:€ʅt
+€{€y€/€€€|€O€€(=€Ḽ׋€€€WFY(_€€€4€õ@ob€€<€€[t€€€G€€€€=~؛€€€€N€g€HX4?€o,5U#€€€€GL€€3y€Уt €€
€€€€€<vǙ{*€I€€y"€€€€!ƶK$€€p€{€7€ €€ѽ€€€€ͰQެix€/€€u96LV€€€0€߬膂€€€€€€xTIue{€m€€Æ9€€€pG€€ne]͙+K€^€€ٖnV7€€€€r€4€€€@€€€*oI;剻€€€AϋdS€h>T€q;L€x€€X€€Ns€€r€p€;€6"€€€€9~€J€ԨS€9€€€€€€€€€w€€€€€€Ȉ:%€h€8"U's€€€€€y€yQ€€M€€j%j^<€G€€€€€€:€€€}7€3€WG€€1njS€<€n€=€€_Xv€€U€fv{R€Z€{€"sO€a5€€^€WE€E€H€€€.€€U€ϩ€€Ry€{e€€%*€€€€Ut€J€5m€€€157ijxSp8€€IN€€o€E"?€ €€6€g€>€€€+m€€8€€+K€Wv€€V€€<>€ +%"^€G)€\€9w€€Vq€€€e€€€€\€€€X€\W€€€€€€€6m E€o}V€h}€€T€€€֧€€h€O6€€€P€€%WozѦ9€U€F€M`€€\€8WaVbÖ#€
€<€2€L€r€SY%k€rƫ€€N€€]~€€€€€€€P€@I€%€€€%€/€€I{€YA+€€€€,€Y €,S€ϒv€|€€€€Yb€F`Y€€€€ӎ€€,i'V4'€F*Q*qN€5€€€€bx€€R/i>@ +€€)€€.N€€b,G€Q͈9€'~€G€€H6€`€|€€{*€M€€%↴ €xok€€€qi€€€Ȫ€h€€ڟ0:€Г€@€2€v€E€I€€{€w€$2)^€½€€€մW€Dm€n!€3€€€U€€€µ~€/r<€€€8)'€"€c€€EУ€X€€€N€}€O€?瓸€€ɴ€"Ǥ€€€€o€̱€$€€w€€T€€€eo€=U€~€€€€=€€L€~€{€€€{€z€+€€€€€€€€YZN€X€s€€€€€€€€€€I€€€€€€VI€€€-j€Q̦}€€5ad<_€$Ûœu€[€'Y_€_Y€€1€'4~T€€~^€ӑ€qd€:x€f€€O€€z€€/P€€8€€ړ},+€€€€A€€~€IU:8€€€(s€€€de€€n€€F€€uS€€€yJ0€'€€€>€€€€Z€g€Y€€߫€x€E€~€€|€€%X€€,€€€g€€Ϝ€€€UpF€D€€€:€€€€3€€<>€YD€€sի€€€€S€|€w<€€€€€€€T€Y]€ON"€€€h'€€_€B€€'€€€€Ӽ€€<€S8b€T€RO€€€€]g€€rӢ€.€€W'q<S@€r€€]€y€€5D€N€х€`€€€j5Ƈ€=p5€€j?A€$€€2€y#€;|€€bK€€€U€j€€*€Lb#Up€I~€~€3T€€€~Äš`€€€3€m9€€q+€6Ò2?E{E
€€€LC€.i:C€€€h?z:S€€€(NÌfxyk€8€€€/€}€;`k€]€b5€`€€€ڼuj€1S€LR€€\€€g€_'8€€€€€€ك€€€,?€p€R€€€€,u€€€€'Y€J€-&€€€€€>€7€€€O€€€€I€=€€c€?€€€|€€€€^€h€f/]€€A}ϖ€€€€#€m€€l€t€€€Y/€€€f +€€XKT€t€€€€€;€€€€€€+N+€€)€r€€j€m€€€vc6)€wP€€TU€€Uca{#{€€:€dG칓€€4€C€]€€D4€€hX?€Xn€€€T€\M€*€€€{!N€Rdz€'d€€#F€ژ€m€5€€`€€€€R€r€g€€€j€€ 4tv€€€€€{€€Y€€ܨ€€eX€H;6(€f-€€d€E€T=€€€9f€ÔU€€€€€€X€N€€mo>€<J€€€ql=€€Nx€€uT_€€€k€e*€€€€€>€裗e'€€€€U€a9€€€[Ğ€€˘E/€bx€€7€€ {€€֥€€C€€ >E€€€€,€€€€g€"€€€€€€r€€L€[B€8€*€W€Az%€€+€_t€€€€J(€€F€€€J€€y€z€_€€€€q€€€z€^I€€€€
o€€€գ€€€'/hN€%€€f+€€ĜVL€€€ gÛNfC€^€C6€€€m€€€d6€€€€€m'€ Ξ̌v€€]fȋ€>€€[€€d`€€€7ol€€€"]€€€>€€Wr€ €Z€€€$~T€€yIN€€3g@ €b€%€€€J€€~€W€?浉€€M'Ñ—:€€}€€{€€€ €€€€€€€i€€€€€b#o€uR€%€D€€y€M€€€u€€€"€€€bNgÂ€Â€Â€ï œÂ€[O€€}€g€€D€M€L€€ €€e€7€€ €€€md€€V€ €€r€€-€o9JV€€pd€€F€ €vΆwt€ €€€€3
t-€O€€€2€y€€0€͓€€0€€x€S€€Y'€€6€€€:€t€|€€€{€€€=g€€€€~Ug€C}€€ޣa€€5U€'€€€€q€=ݖ€u/€92€#€%1€J€€}Ъ?ß´7\€ u#vF€€B€,mt€]€"oE€Knd€+%€>3€d€€€€+€\€€€|i€F€€€€0ހ€€Dx€€€€€X-€€€€€8€ml€€€R€^€€€Ѷ1€€I€€€j€€`"ë'kO€€€€lK€d|€z€€€€۶€€[^Þ£n€kT€€€4.c€€€>€€DѼ+r€O€0€#*€€"̷€€€(€7N€Z€€€€€n€€Q}€>€٠V€u€Z€x5€fU€€€€ۄk€~€€€T€i€€€€3d€€Én€€€%[€}€€€€ C€9€€€€C€ƻ€|P€€€€€€€€€ {:€€BbH€>€`€wy€/€dw€WY€€€€€3€V€Tƃ€€€覡_€€€ßE€5gg€o-g€7d€ €e€€u€€rzgZ€€)€€5€€€ѥ€?SX
€kּ€k€€€€€€€w€€l€€{€€€€€N€׿€€€zn€f€mK€€
€€€€K€€€€R€€]€€mW€€€!€€€+€x€s€€€€€€l€€€€eU€€€€€€€*€Õvn\L€€G€€/€?€{€€€cc€€[€€9€w€€e&€nR7€€;Ó€n€€€nb€،}USwU€5€[Hk€€€€*i€€\€€3€#w€姺€0?€s€€m<€@_€€€€h€€l€_€)RÞ„1€v€7չ€o€@\'3€s€€Te8€€€€€€`3]€€7€]I€?€FU€H-€3xY19€€€€E€€vP5€>Y€€ €f=G€q{€€€€0€v?€€€޲€€]€€€?€€€(€r€P$€iA€Ud.<€€€€܊ۅ€€d€€€7€?€€m€€bv€;{€€€î»Â€Â€Â€8€€3€€[€Q€ €"7gX€<(g|}€qgτ€S€€€€ê½Â€Â€7€€D€X€M€€=€xi€€Df€؊;€€€€€€€D€€'@€€,€k€€r€€€NÂ€Ë Â€Â€Â€Â€=€€€€€vD€a€€`€ИR€B€p€€G€€€/bc:€t3€cO3€{O€9€>€TÃ/€€%€€K€€€HÂ€Þ Â€Â€N€€-?€€F*€€7%€ +€S\\€€k€+€€ €)kE€C€z€^1€€€€K*]Y[€€€€/V€€€b€€g€ +€ €3€w€ 8q€€€Hw€x€€€zh€€€G€€€€ +€€€€,6yh€€€s€€€€€€€4€_€dlK€€€€€*€A€[8y€˥q€D€[e,0€€M)t_ ]d€€€€%€7€€€€ჸ€€–€ +6
€€N€_]R[€] €€tw"€€X€w€Hvt=>€n€(€€7€wȫ€"€x\€€€(c€~€€D|H€€€]u€€ +€W€€€W€=€€€€z€€€€€t€/€n€€€t€`:M6h€,o€€€€€y€€€€€%sQ€€Aq€4q€1€€L\
€€€€€13m*e€€€B€8lSI€€=€{W€p€€1€u€ +€€1,€€€SÂ€Â€Ý Â€eWwH€ €ﮧ€U€}8PT€"Q€ +€ +€€€g€€cdqx€€1^c€€cu]G>€€y€%1€^€;Ɨ€€/ـU8€JToT?€€€€d€€vI{€j{b^y€€&€€R€€x€€V;b4€Y€€€X€ƕ€€#\I€{Ì®v€Ie€1€B&}€€€€[U_€[€€€€€X€€x€€M€t
2E€€Ņ€Ut€Yo k€6€€b/4€-4k#€`€>€Ì€€€|(f€€~<W€~U€€€epހ€o3U-€+€Hæ©Â€}TS€€T€€€€€&€J€6Pp/€~€/X€€=l€€€€€H4"€n€€€;Oǔ€N€6ع€€=€M€€€€€€9€Ƌ€€h?€€2€€z€z€e€€@Åg€S€€€€€z8J€q]1/€€NQ}>Ƿ€Z:€}€€34€Z€'€v]€Žk`׼€€=q€€€Z.€€€€'€v€€€S€€€c€€€z4€€o€€€€€
€€ݨ€nVb€!O#?€G凸€Se/€€€Q€0$€€€.z]€€€Y€V€cZ0€q€Y9€€!€€u4€€L€ g€€€€hU€€€g€}FǾ,{€€UZ€P€>)ޕ€€ko U+*R+€w€Z€€[k€-_€w€€Sp€€€*€€&€€€€>€€gu€F-€€€Qd/ͱ€j€€€4€a>€€0€E`i€€ Ne€€€˙€€R"€€€n€)€€}€€yD€ +€^€€Bt€€€€&€€€€€D€€€€~€€Wܧ€r€׌ߓt0€€d€.€€€"€k€€€€€€€€€6~€€€€{#\I€킖7€}€€_€€Y?~€wp€€€€z€€Mn|€w€ᒪ€€p€ϯ;€€_Mq€€€`€€€#€k€&€€€?€€4€€€€€g$€a€/€€€I€€€€Et€€€€3N€€€=cB€€ə€€8€M€€M€5tIy€€€ P€€€€ €}>€€FxùT€yމ€K€€?€€R_€+r€Q€"E€€€€€€=ę €€€€z5:+€€€-€\€€+l=€K€€w€J€1E€T$€€€F€€€q€€P€Xn?€€€zT€€€"€0Q}€;€€Q€€y/€+f€€2€dk€E*€>ދ2€7˻g*݃7N€
|\޲€]€A€W€€€b€J€€?Q€€€€X}€€€€€*O€W€>dU€€€€-€€€|€1€o€y€}t€l€r€€C?€Ț€#€+€€t]ч€€q€€€€€€€€€€o5V€zY{R$€>€€?€€€€,y€9€€1a=]€Y[€}€€mܮ}€z=%l€€€S{>€(€€€€€6rr€jZ +Ƅg€ء1u
€5w*€€€a€€€4€€J€€€€€€€p€y^€Vr€ﵟ€€qB€€€€\º;€€€€€Q€€|€€q€a€€€€^€€€>€ȅztײzӞ€{€€€€r*v€1,€Ye€€m€8u€€€M€,J2€Ì€€ي€€j€)€uRM€佢N€™€$M€€€€€€ޘ€w€€qz€xRC€a€€€
€€4€ʨq€€W€€Q€€f>Â€Â€Ø Â€Â€Â€Â€Â€Â€Â€Â€8{€OD€€ͼE€YΚwZDP€€VwO€€€€€€€ȑw€€€€3€€J€f|%€JV€hÊ©]#€€€€Ef€€€€
8€j€€Ή;]€€޹€€8w€€(R€Y€)€€У€€9€€€€€€n€Y<€upE€#Y€€€h€=€€€l€€|€€P9W€€€T籲€Ɣ}@€ھ€ԾW€+€€€I€€W€!€JwD€9€^'5€R€I€ €~€€J0€c€>V€€q€/€u€€Z€U̕€[€VÖ’V€€˶€€€€n€€0~€/b€Gz;€D€=€VÈœT+€€€Xe€€€j€€€€€KTx+€G1€€p€P€r%Df€€ڰ€e€ѧx€€z:€H~>vs€Hh€€|[€w€S€-€l€ɵ€€€c€€yC$€€€:€€€;<€€€,€€€€€P7€%^€K€J€Gyw€€h@€€*+>€˛€NÅ•V€€Ðc?€€_VG€Q€]ú_€€MR€€€9Ç‹V€€€X0€€#€€P€€G€€pߕ€€€€B:€€*€&b€"ܳ€€€̄f€€JZ€€~€€'€J9€€€5€€u$€€wo넆%€m€C€Z€K€€€€€€s€€6€x€nܥ€0€:€V€m€EU€€€€€^€F;F€€Uc€€€]€€€7€€[€€€€C€&€€bU?x€€€€€€?@%€€A€€a€€€€=€]lWTVD€€€€i€€€€€:'7;€ARU"€€8€€€€€(€%€€€€€Q€ձ€'€€€I€€€E€€`l€€qt€f€ώ)gÑCW€:€7€€€€+€Љ€€€Q€€WÓ¹^HU€€€℞€€Z€Q€5€Ү€€€€4€O€€€9S€#€rZeŻ€€鉾€€€*C€A€o1|?ꃦ9€w€€€H€€€€€€|€€€v€€€~QU€€€€B€B€C€I€zFeE€yf€Na€K€€€8€€`€€3€€€€8R€!\€>fɱ'y€F€€!Q€+€"|(y€€€Jw€€€€ұ>€'€#€+#€€€#-؄€u€€€KHÉ‹'€€€s€Ʈ€€A€€€Z€€#€RqG}<€K€VÓ€!O€k€€€€xY^g €€€U€R€€È€J€8#!u€€€ln3€€€€(!€€]ζ5€€€€Ù6R€ +€€€€l€j€€€.Bk#€@
€v6€6€k€€i€n€S€`€€€€6€€y€n#€€؋€=€,4W +]€M€€€€€U+o€€€€V€|-:€€j€u| +21€V€ +;€€€€)Pd&k€€B€€sw€€€;€V€€YW€R:€€€}և€€bF€]N€€f€€€€€€"€w够d€€€f€€€€sg€€€€HÛ€ -G€€€€_';€€'c€€€w€;Â€î¥ :x€vS J€€|€€}Ìšp;€€6d€wH€€3€o€r€/€'o€€€p€]€€Y€€€S€/€€€€€€€x€D€!î• Y€iD+23^€L€>€€Ӏe€[€€€
Bl{€`0€€€€7b€€x€€lQ€€Yc€€n€'€!Þ€@€5€lXb
€X€]7XΡ€€c,€ƚ
FKL€!6€\€tC€€h0S~€F€ O€1€`4€€EvZ€f#€€€&€€€xF€€€l+€ €5YL€4$6
€#€€d€€€c€11€€)€dBp€A€€,C€€2AJ€!€H€&c€I-€€b€€€€€€1V6€€Y€€SD#2B\8€€v€96€ό!€
2G8€d€Fa€nN8Z€€€X€P€1€<P +p€€€€€i1@7`E/€g€€€&€U€€€:{~\:€€㨆€t€g#'€€q€eBm€bS€€Y€€€€Ȅ€€€€€&€€@€~€€€t€€o6€q€€%€0ÎgL:€€1f€€<#€ +€i€€ Us€o€3#€€€€
iC€L`€e€R`1€€Tq€ +ш€Y€ €鑰>€€&€€j€1€5P€€Ø€Ť€'̨€€T€€€€^1€<'€€T€€`&€€ћQ€RCl€)6€J$M
j0€L6+ո€DQ€f=U€€@€€€J=€DuX€D€bK"f3Ǿ€E}€7€€€€0?[fʀ-F€Ùg€€G€HH>
€€€€b€I0€€V@e&ƌ1€m€$!hJr€€€D.`€€g6&h€("€€+jt,PZ"J€€€€€Vt€mL€$€@€€E€$f€2€x1€€XK<€€€h€€I{€€€€<bC€€€€€€€Vy€'"€€) H€(H€€)€€€0€€€M€€€@€K
€€6M2V2€€€€€€!€4€&l€(
€t€O€3€Sj€€€€X€Q€€Av+€€€/€€€€€€€€O€€€G€Q€B€L€€Lm€€E€&>€€€ 9| N€)f[|€1€€x€€c€3[€€[,€&€ɒ€€0€€€0€€€Ƶ€mQcʌ€#v:€f2€€I€€€,€#9€t2€€5€q)€€Ch€IK€t;C4€€w€€€P€8s€ي~5IUBO€€€r: €b€ÑL&P)8€`€Gj%€e€?€ĉv€€€
€qJ€G€'}€€&€€€€}€OR€€€G&€,€€€€€h€@€€2€€&Ρ0€?€€€€`€\INÙ†8€€dSMhw€$`€€€hx€Td€€€!€€€€֩€€€€Z€'GwÎœ+€b4€9€ߜ€€)€€€€L€€1€g€M€€€0€ €4j€€€€€QÇ‚FF€€h€!€€€€€€{(€€€€€€€8&€X€€yFS€m€€zŘR€N5€"R€J€€€<s<€Dx€5Ɩ€c€€€,€€8€'%[gs;o€€\€€,r€€7€!€€€)r/€€}€"€€€)€€Bd€M1B€P2&€ьf€C€€֣€"h€6@€b€C€€€€h€€<!€J5€ђ€€€€8>€a€€€€9#€`5&€q€Fc€IoA€€@s€Б€€0Y (bI-€)ތ€5l€€€€Z1€EO/*P=€€€C€g€Z€€h87€€gjR€€0V€hC6€3 Ԓ€|€€€,jc€€Ҭ胸€6S[€€€hB€€!€-€4€`€0!€e9Æ£I€€€"#,€?€ϩxQ€€€€€q€`€€a3€X€#>€€H€f€x€€p€€ب€1€:1bd6€E3@€€?Ū€'€`ȷ€d€€ͦ€€€Ξ€€€€€€€<€€ԫ€c?€€€IÍœe^t€€\h€1_bN4€€€€Ei€€€€€€€€;€€€Y}€€€€€\€€€€€~D€V€ݚ€€€€€€[Q€€€€€€€€m€€€€€€\s€)%gn\€€€€€13f$Z.6€ +.€€,0[€€O€€€€€3€튷;lg€€€T|ϳ€df8€€i€I€€€4€Y€çž{m€f_€eZ:€€HL2M˷€N€€€€€\K"€€1{›"€X€̓?E€)C€iä¦@>€€€€:v€d?9€b<bb€[5E
€€0
C
K̉€8€€L€$-€~g€€ٳ€€ͮ€€€զ٥ճ€g€€MӴ€€O€b€€D€€Ϳks€€€ٕ€H€6€*[̌€s€ϵ€k€7垵€X4+))#)K9+€€€€ߘ€€€€b€€Ͱ€kO€€€€€:͞4#€a5[R-€€€€L 6k€€Z:}€弹€€32ϙa€o€m€(€,Kz€y€E)FÜd[€yI|B€i^B€€1€€kɜ6€>€pY\JR€ݞ€€L€2RR,€;€xs€€€€€X0Wˈ^3
d€€"€ڑ€6€|€kZlz"B€B€€A腋'€€€€€B€.ܬ€/€.)€€€€€^€]+€€€?€€z€7€€€€,€€€€!€€€K€€€€€€€€€ݧW€€w7€€}€€€*€€ €€€ʾ€9Z€€€_Z\S€€|E
2sta€j€€€*€€€^K€€€€qYS€.u€€€~€€D€Z€1?Kx€€€€€D€€l€W_€=€y€€{"€€z;q_€?€€€]€€+€1)€G€kK,W.€+Ƨ€e€€5€€-^~|Iy€-€ς€oy€^€€q€%€4€€v€€€'#p€7k€€2€Y€f[€€€g€TO:€Ykɦ}=€,€ B=€€€€€[€T_€=€y9%ZÚ»p€l€€W€P€€LG€/g~,€€q€€A`€€€\€39€€€€€€>+€€€€e€pA€P0nͲ€€€U€€˪€\cnIQ€9Û´^eK0€S€_€€€€€e€€m €T€€€€M€€€5€€O€€[€ͧҞ€€t€€:/{v€€s€€€€€/€`€€~c€']€€€€]€,.Y€tY€r€ +€ʲK€+*/€€€Y€€€€+€|€€€W€{€€[€€ֶ€€€;:€€€ t€€€€€w€€€n€€_€e]€€€€€€%6€€ʒ€N€v€.K€"×’)޶€%€€sf*+:€L€€+=]]J{W€ϖ5S)€R€:€€{€[€€€v€cZ€€€4€6t€Z8€m€L€€֖@€€Ö€€€(
=M€m€>€€w % €€t6#~€ێ€m+9€€€€€B2Ϋ€€W€8€€({WGG^^€€€€Ѣty9贩€€B€݊€y4uۦ €e%c€4€B€€S€€m€ €/€6.€€C€&|€`)€€€€€ӊjT€UpW€€€€ +^€H€€+€€€m}K€8€€Sf€X]€€€€€€ܙJ
€€€€*€€€HDl5`€€€@€€\€€€€€€€s€€€€€€ +'€€'p€€€€€0J€€€Yi €J€€_€̙3€f)€u'€Jg)€ص€€€7€€`€
€€Gw€€z€€€n€€€€€)Jd€y +€€€€Y`€R +=€€€ٟTʈ€€k€€D%%تNEI€E+€€€Je$€€
T€ޮ€€€€€lW€,€Wu€*€- S膆C€B€44Bmv€€ȡ€!Ќ€€h€U€ +€k€\€w€€€€*€€€||ʆ(€€[€S€€Ѓ€@ €€€v€C€€q€€
€€U€H8r€€€P9=A€×€€€q€y€I€€€€ٲ€>€€€x€€€€m€€3€U€€b€%€AT€€€>€|JV€€hj€4<€€ B€€€Ÿ&P€6€4€€e}€fѹ€€k€O€ũq3Ip€€P-mY€€€€€€V€S€l€€D€€€€J€4%€€,€€@CO[#1dK€€v€i U[z³€I€€g*€€m€ޮ€n꨼m}€€^€C_€_w#€€€€€€b€^€x€[ß²\s€J€[€K€€t€€pH€Aa3W€€€€j;dӟ€9a?+€\o€€n€N€€v€a€:€*(€֬€hЋyml\€5!q€m€=)€€€€g€€€~nF€d€€6€€~{€Ǯ€I€€mU5€h€€)€|%:€€€˔_KgKÓfEY +b€€ԗ€̿0O)mi€6€.€€B€€`€€E€|€€€(Y€|E€(€N€€€;Qӫ€€X!€€w&€3€€€€€#€€:{€:{[€€48€€>€h€4€ݽ€€ €vH€oC€go€k€9€€€'*J€E€€D€S€€w€$UTU€€€dt€-}€€€ܻ€|€H€€€B€€€€€€u€€5u/€€
5^L:€{S€€€{(]Qg\p€H؛ا€€"€O7€5€€€€€Q€€E€9€€|€|€4)vb€€F€u€CeE€€€?€€€nCuL$)€lY€8 t€3€+ж€ݜ€€[€B[v€€€€€€5€
h€€J€7+n€€€€}"€Y€€Ϛe+€€€€]0%€ތ;t€'€€€u€hkn€€ۋ€€` 5€ֈ-Vl€€)€€F€€ڹ&€<€€x|€]i€€€€n€€€`k"€]5€e)€s€B€EI€V€€*€€€4PI€€€€€€y€.€xf€ܹ`€7m**€€€€€%`Ë›s€€`9h €€€€€€€)€€€€€€€€€M€J€3€!€[G€C+€"@5€(€€3%Gk€ç³Â€_€6€yz€[€€€€Ү^€€€VC€€6&€T$€݂YEUh€{#€€N€€€€2€|%€€Oq€€+€€[|G€€€€€xM€]8w€dkR€€Fqv€d664€€€ÝhNZz€l€6_'&€€€€0€€@€5<€R|€0€9€€Mk€6vB:€€1€8*€:€D€€e;d€S€€==3Ú»?€€€l€$€E€n€h€€€JYU€€€€€r€p^€€s€uj€€x€ɵ€8a€2€€D€gÕ…M€k€mkoƈ\€Ѿ€€ڜW€:€€€&€€€Wo€l€ w€gz€€cjd€€€€€Q€#iO€[qV]3f$
€
mH€[Z!r€rŅ€€€Zº€€V€S€v€€f€€€€€€€e€k€€#€€€€ny€€u€Ϧ€D€€€n€rQ€ɺ€€€U|V€€€{€gQ€*'a€B7€U€€@€€F€̆€v€€@€u5€€€€€€€*€€D€€"€€u€€]}€M€€r€D]€n€€€ʥm€€@€€Ð6€€7€€€€€Dv8Q€€€€€I€[€Y€F€ ֖€;=W€€2k€€€I€F€€€@€Ӌ€LNd€'D{j+€€€€€€Eg(_2€€:€pJ€, €€€€,€€TwA€|€k€€€€€€€̄€m€€€l1:€$ީ€tz]yu9y€€S€d€g€0K€Ы€€u€€€€W€R€5f€b€*€]€€4€t/€]€SG€€€\_uWL€[J€€€€€€1€m@,€* €€=€€€€€Xe€€ق€ы€G€€€€93€eL€ +SK€€€q2€€u€€`Ks [+€€G75oZS€€€€= +.{€1@b€€IK[€€€€€i&L€€0€'CO€€¶@€K'€gh€€%\€€€P€€€,€\€€€€^€€^€€4v€€T€€€ud€€dR€€M€U€€€%J*YK؎€€€€€€€^€€:w€>x€€€€Ԫ€ €€€€i,u€€6€€€]T€W€€€€}€€IvÖS€€€€D€€€€€Ŷ€w?€$b€|€A€~o€€€6i€p€.€€€a;Ö“B€[€Y€€€€€€`g€]€;.,€€€€€˅x€€€€€€€€€״€€W_M€€T€€
H€€€€+P€€€TÙ…)]K€[€]$€AW€RbC€€|m֛€,€oN,€€€€?€n€€VÝ€{€t,€(€.{tO€€€€O€}Aj€€{]wX7€S€n€€E€€€ +€€€€€€€p€€BG€.I'g€€€2$€€Mly€€}€€"(€€€y€€€€€€yÿ€€€€€͆€€€€mzS€€€€(€€&€€€€€E~€€;€€7€€Q5€ +€hq€€Q€`€€s€€€N(€€l€€[€IXR€'€€€€%€"€€€€€|€€€Y€6€Nl€cÞ”'h?€€TR€€6€€€a€t>|€€€€FE€€€€€ѽ€€]€€Λ€)€€a€€€aC€Ӆ=W€{€Qr€€€cit€€€€<QR€ކ€V€€.€i.€€€ +GJ€€€€€€€€€€'l'€€y€€6€YÛ£Y㲢€5^+€c9€€€K€€€Na€0.V€€$&€Ϥ€V€€W€u݂€4 +€€€$€€€€8€€~€€€b;€€€+?€€€
苸^€€R€€5€S€€€4l€}Kt€wUtL@G€G€€€xu€€P€€€X$|1€É{1€€€€dqN€J€Z€D€j€€o€p€h€eI€j5€€€€€€2€Q€6i()W€Ww2{€/€€z,s€€€€V€{€€€ں€z€:€€驨€€c$€kD5€)€7€€W€&€>J\€q[m6*I`2x€c€€z1€€€€€;€€:€€€€T%€€€€€€€+Y€€€€€€n€€€'G€€€€€c€<w€/u€€M€€5€o€€€'€L€€K€€€€A€>o$\w€* +€?e€€R€z܋€€€€3€€VFƲ6u€GRæºe€€o€€€€t€l\€€{ܸn€€CS€€€€€€p€€On€Ȯ>€ e€,€€:GR€€(€€RGLj€€€t€S€€;€>Vy€€t€h€9€€9€s€€(j€€€C[:as€€€€ +a€#rj€€€2€€r #H€Z€€<€]€€€C€?€€GA€Ӏ€€€6C€€€€€F€€€X€€€ê¸%€€€€Vm{t[€a€Cǎ€€€€€€€€€US€M㮨X!€Z€~€+€€
€€€Pc€ߓx€€}€ll€€€N~€į€u€€€€€€€*z€Ƕ€€€€J|k€z^Ul€€2|7!€€|€€€€o€M€€$f€€€€€d€€€D€€?€€€?€se€ɳ>€€3=U€6Oy€€€€€€€€=%€1€€~€g1b,D€€x€€€y€€€x€€<€€s=€€€?Ó_;€'€gx€€k€[ߟ€€€€€T3€€w4€+€€€€Cظ€€€€€3.'€5)€Eq
€ܵg€A€€b€€€€€€U€€€€Õ€€€€€m€€€TΗz€€€€€€€€€€Ƕv€)e€i€€X=€€€€\€w€^€>^x€ Z€R€O(f€Tَ€9@)gٷ€€€€O€€€K€€€€€a€€x)t€€€€€އ€2)k€O·.€€€b€d#$æ•…F<€€€€N€Z(€€m€€€TsQ;€€շ€5€/€€€€€U€$<m€
€€€gY€€t€c:x4€:r€
€I€€€€€€3€€€:€€€€€€OF€O€Z>(€€v€k€E€€3M/R€€€€hR€€r€B€€€mt€'€€€nZ€€€€€€R€SȈ€€€_€€€€zoC€X€SV€€T€o€€ +€€€~€€I€۰€€€O€z€€€€€m/oEW€€`K)€ݵ€6
w€€Z€€€u€<Ä€€l<)€zǗ€€,a€€<z%€€€:€€
€€Q€€€€€€€Y€^1ޅ€u<€€€€ymjf6€€0€"€ݕ€€[€€€€.9H€€:€€€€G€X€€€=z€€€J€€n,0€€]€y€n€a€€€G€ޒs€I€M7€€P7€y€ѻ€c€€rt]T€€€_€ux]€€€€"8Re€:+j€c€G€€۵>5€€ƨ€W€(€ힷ€l€TV€
€1€[u3€€€€"S€W€)€€€€€€€=€€ͫQ#€€bo~€H.€yR +€bog€Q€W€€€v€;OL€€€€n,€€€€l6c€€d€€€q_€€f_;€Ũ€€€:Â€Â€îŠ Â€Â€l€#€J€q€€€,€[ʶa_!dz€|*€+€M?€C_€€€z\A _€ٗ€€€€ +€'€>€B#G€&€m.)I.€5[€z€Hf^€€S€€€нs€€g€€€€€€tl€=U€€€€K€€€s€€€€€q€îªÂ€L_€uy€€€̞€€€(€m€€€S€k9€,€€€'y€€€€~]&€€€|€ߺsVQ€{y4€Ed€Z€&pÄ€g€ID>q€d€J€B)€€€€€€€yM€d€~€ €€Z€€€€Zn€€jAû€€€ƕ€€n€€z8-Qm€V€€€qm€N€€$ʯĄk^F€˪Vz€U+mɴ€{€€€74€€€w'€ި^€€?€€ÎmP€€€b{€€"e3€€I€S€Z€€$yÉ‹q€p€WÑ¥>{to€;}€<d`J€€€€l€f€}€€2/t€€.a€uJoj-&€J€ XF€140J€]K€kx€f€€Ó€€€skB}€u~^€€Vg€.u3g€gOvm,€F€€|€g€€?€rԅ€€܆€€hgh#€Z€€€€€€ W€.5€
U€€g€X€|€w€€€€K€@€"€€m€€6[€€&€S\`€€u€'€ WÊž0u]€€Z€€€€€€7€€-€€€3od€L€ +k€^€1€€€€€€€m9€€€€W€0 +U€|€€€€6€w'!q€S"1€jU€:+€€f€2€;€zpR"W€U€€€€]€€€i€€€€in׈€€€€%€T€B€!6€q€x<6€X€€€€]Å»S/€Fh€€*€€€€€0€€T€Ç€€€~€_€€G€€fÅŽe1€#/+€K€€€Z€€'€€ھ]€9Kw`{€5ʷ€€€€€€€knT€w€pV€€€€€Gy3€>+€ +%€gt'€B€€SЗމ€€C€ub€€ۨ€^€\€J€D€€:ڪ€€4|€ը€€L6TX&n€€€اs uL€€LOg€2|(+i€k€T€ƢL€Ͻ\€s1€€€€€R€N€q€€€€{€K€#€€€+€צ-€€€ +x€€Q€t€€%F€f€<€}€€!m€€Ó€€gm€€€}<A€l€VS᳢€€€€€b€€€!Jhμ€!+€q"€€€€€/<\€€3qq€€€€
€>ч€€€€€gw€€€4€€€1€CV€%y€€€?€l€y€€€€#€#€{€€F€€}€#€€€wTvG€€:€I#€€€€)€€€€U172>:B]_€€€)+^̜€€]G?€€€€€D€€QTx€€€€ €€€€€€€€€€€<Gl€ڼh9n€€€(Ϲ€B!€d€€`€m€€€3€2€>€a?€˺ySE€€€~€l%€€+€a%€€€̞Q€)€€Ol€€€€€k€€v.X3t€'o=€&€
€€С€֩~Fq€,€€€€l€P€€€!Lc€)Ý#€€€1€€C€€k*€€0€€@€x€=€2€k€ͻ€Dޔ€€€c11€€€F_€€~w€€1oSͲښQ€€I€€€y€5\A€€ €[Q1€€v€€€€=€e€s€Ⳍ€B`€€Ë€{g€€O€€ [e€€€cP_?QA€€ +€€€,€y€u>#il€€€'€€_p€€€}€€€7Z€3]€Ў\€@
€6\€€#,¢ݞ€€\U€z\€}!€€e€v€€Hî¸Â€>€l;fMeW€€̂oV€c€€€€€i€€€(€s€€€€uabF€€u€€€€€€֚ +%€€`€!lG€髷€€€?€€€€G€€€2€€Jwe€€U7K€%€D€€Ô€€bqA!€€ÍFP€€G€€€!€€i( €vdF8€€€€€€
H€&€€K€8HSx0.€ڱOdR€`c€
6e€Ӿ€€€€帚€-€€€€€b2c$€€3F c€X€3€€€t€€€€€#€€:€PN€s=€"€€?€A@2€€}I€€ֵz€:€€D4u€F€DL€€€{€=€V€Q€€u€€€€€€€€&€Ǿ€€Iܤ€ą€|€€m€€€€CF\€€ܓ=€€%4€€€€€€€€C[}€€%8€|0€€€€€`€ҳ€€€€I"€߉sÏ–{€€€€H\€s€SU€€\l€"U€B +€€:<€€f€€€Qg€B2€VL€y€€€€h6€Y€]€€€O€€€€cI€€€€€€SÂ€Â€Â€Â€Â€Â€Ú Â€Â€Â€4€0e$}€€€€€+€€^€€K07€y?lw€€7€€€€€ƶ€€€€€_€€€U€€€ZQ€€f€€€e€KV€€T€€_€€f€€a}2zУ€€т€B€]W€€ݺ€€_€G€€ +.€\€€€P€€€\€G^ +{€€^W€€€€€VHX륞c.fc|O€a€€lhb\_w€€€E€A€4€&L€5€mRj€€€€4€€+5uK€-€€N
n€1€Raz€q€3€+€S€^)€cN€€€€€]€€€€€U7€€€EJ€Y/(5€€'€_€J
2S€('€€[N87€€€€€€lØbY€pQ€n/€€€9r"+€€€m€rq5€V€qi G€G&€€B€΢B€€€y€€€€86g€€c€wv€q=€zJ1n
€C€€/v€€(0
€€a9€€€€€+1€€€7"€€€€}€€€€€;{€Pg6€ס€€:€€€€|€€/€z€€€€J<€€XW€€€Y€f€Q€€_Uw€{^€€€;€€€
=M€s€ҮJZ€SÜŽM€€x€€€€%m€Κ$€-€U€TT€€Ê€=Ø’H€:hcPyE€€€€€C6€€<3€'T/Ñ„j€€€C%Õ¨ +€q€ €k€L€€n€€€€€€%Ǿs€K€}^€d+G€>€%6(#(€€€u€€€0ÞºU€i2€21€€˰€z€AF_"} €Wh€a€ї€c€y€€o€€N€€l€€
€€N€€€F€b€€€!€€€?€€a€X€%!€:L5€e€Ĝt€
€€€€€9z€€A€€[v€€ق€€X€Լ`€$k€€vQ€-)€€€3€ ~€€:€€€^I€€p€€s€;k€€svÔ 7B-€8€j€緖€€0€n€F,€€K@€I]~€€€€̻)€€1]€€3W€€s:GY€€€€71~L€(/Q€Gm€€€6ps€"€p1VDZ€vv€v€g€߾s€€)€3r€€`9€h€€8€0€€1)Ó±Bxv€Ǽ1胮܃n€€t€€7L^€€€._5M9€}5&€€*€W€o€€x€F€S=QE>€,Ɯ€#ຸ€@S€€O€€GO€€€3 €€O€€z€€€y€.€T€4"J€k€€B€G+I€D +€He-O'57*€!€ZU/-€bq7)E€€€€€€€7€€€]€€€'€€€€̈́€0i€J€K€<y€^€}U€-€€€-€{€€͆€)"V€€a€`!['v€€€I€Ucl"€€€+€€<€€
€4w€=P(hzZ€`€%8€-2g€€€€€9AD€€U1€.ch|€y€U€€p€P€€l€$Em4€€p#€2€€A€€RDa€€€€€և€D'€=€S€€*€€h€€€€H€W€€KV€?€€€;€c€I€ug€€€€|V€€|E€€€R€€€È$€€"€€€ ݎ€ꄊ€;7€'M€€€€ٛ€b +€€€€€€%€|kKd€€€€i=i€€,€y€L€Hc€€€an€I€€)€{€:€"€M8o۷€#cs.€€p!€€-߀€€\K€$M€Tl€€€€Z€€€€€€9€5€€(€u€€}€5@V€½B€%€€€€€-{€€€€€€E€6'€2€€€€€€!Ua€€€\a€€€>€€€z€€€OQw€€€*p€y&C€€€M€v€€׳rUÆ´ &1€e€a€€€%8€€:€€ފ€^uq€€ €I€€]€€€Q€€t€ENz€€H€€€€€O߯[€E€€9Z€€]7Թ€h
P\€b€x^€Y€€vF€€X€ԋ[G€8>€€aAg€€€V€€!€Wa€CrÓ†v€€V€€w€~€d€G€€€€8嫄€A€ѯ€€ojoi€€E€€€&€€€€€7€€|K€€€JѼㄵVs€€€_X€k=€€€€ֻT€€€B€€€€€.ڄ€€€€C\€€ Ú¸p}6Ja€€"(z€t€&€6€€Ŝ€r€B€/€K+€vjn€€lF€€W€€Gi€€I€Dbr€Xմ€c€€HUN€C€€€Hֻ€€€€d€€€qAT€€€€-=€€Ê€sh€gl+€€€4€€€€
€Q€€=€*Bv€oLP8b*H€=€€=€K]€€€k€8€N B!€n€€{:p€DZ€ޛL5}|m D7€i€€p}?={€Ė€€,€€H|P€€€€€h€J€€V€æ¾Q€)넱€€(€
€€€€v€€M€6
A€€,€_€€€€Z€|€€€%2E€Ң€€€€2JJ€ÜD:s€I€$€€€K€R€͊Vv;€€UP€€€€W€€,€€T€h€€ X
€€Dyb@t€€€ڋxY€-E€̈́€€€Z3€?€X€€€ХV<)g'€S€<WX€€gcW€€#3K€€€P€€€€]€€€€€m€€qG2B]€€W!€R€X]}€€€€€€<€€€63)€Fq€$LJ€K€€9€€W{€Z_€€$€€l€€€€€€.€'iLM3€€€4)€€€€€vc,€H~8€%{€7j+€ۺ€€€G€~€6.\%€€€@}€Itq€€|€€€€€5€v"€4€€€B€u€€€ba€]F€€1€x€ʓ]€€U€€€€€€€€j€϶€
l^7€o€r€wS€m€€Va€€€€]€€-z€Z=€i€€R{6١€€o€€ +ڑ"YweF&)€A€a+€€€€_€€€€€gȎ|w%€} €€Jqmy.?€€=W€€#€€€V=1€€s
€o€'k€€€€?C€'€€€ar€V€-ǀ{v€h€€€k€o駄€ʽ€€€€BS€€€I*€`q€(€€€ˆ€r
݋€€€€'€u€O€€+€€Ŭ€€J<€€F€%€i€a€ēχt%s€€€
€€€/Z€€[}&€K0€ +€NB_€€~=p€€€€?€€w~€€G€€€€wB€c#]t3x8€€F€ƴut
E€€+C€^€5€6ìŽ Â€Mv_€T€€€€€_]€€Sj€€3T]€bt€`€9€+g2^g€Oր€EyZ€€€`€\€U`€€U€{€;€€€m€iȀ]Nlw<€€kRp€€€€b€€uq€m€€7€€9€V€€JVLC€Ueh€ €\€€€H€€o@€0€€€&€b€s€Z€49€;~€€€€eOs5€&€zH޵ͽ, +€€€€€€€€€t€K€€€M€E€.C€iâ‚ij€€4>€NQRՀJ4Q/F€<€Մ0€m€€}|Ô‹-€=€S€€#Zr\€ePL€f
9€€€j€hkd>€€ÕZ&€€뉾
€X€]€+€ €€€c€G<€N€€€-€€€€Ւ€j0€eަ€€X5€€<€:ȯ€€€x€€€(€ɨ€€P€€V@q€=€€97m5€€€-€zw€€fOr€€€O€j»`p€6ͽ€€2.€€)€]%E4)€€fȆ8€€I€R.1€y€%€B€€}€€€{€BEЩl€€Lvͷ€€]3zj€P)€€ûh€€€€xěJ€+_h€€F€Ϝh€fm€€€"€€o€€E+€€)q€3€メ]€Z|k€U€:€€/Q|ٗ}€€k€*€€€6€3J€€*D€<K
,5€'`Y
€j€W`€€€ֳ€5€€€܋+€€zskwA9 +€׊{€J€IMZ€€€:€jyh€C€€y2€€€€€€€€€€€€n
€+€€€0€€€€€€h€€€€€ϟ€Ë€C€5Z$€`€€h(€€€€%-߅€'€3€€€Gy>€€€€€€€|ix€€L€€€€I€x6€€: [€eR<€€€F(€_)€€€e€€€%€ǰ€\€]€€€|€t€€€€€€Z€U€qy{*€c€€r€f_[€€€€€€€ +€S€2<@/€눩| +€€|€Sw€€K:€G€€€!€+€€€€€D€~€6€€€€0€5€»€€6^€k='€€€€o€€€€oC€[€K€k/€X€#`%[4€"l€XÛž\<l1RU€€2#€€d €*€€=l>@€€D€Wc€Ѱ€y€€€E€€c€w€€{[€Lx?€€[Pe7f€0€€€n€€7€€€(W€€KCW€eF€€€€U€ZB€€<€Jx`'€€€€€w-€€X€€*€€€€l€ꬺγ€<€€€€€<y€މ€M€€P€€R€€€3^€Ú€|ƒ€€"€€€v€€4€€'f€€€€€€7€L€€@O€V| td€€P€€€€€€/€Z€ €€1U€{€€€€€D€^€@B€€:€W€%€e;It€€€æ€3€3m€€1S@€€€.€€€F!€€€€€ w€ç /@ݔ€€€€€€^€J"€{€~.oÞ²P€Z€€€oW€ +€€€.€p€*€€Mt€6*€€4HW6€"€€t€@€€€€€S/€h€^€<€}€€s€l€-€€Ǧ.€.И€€€€v€€€€€€€€F\€XK|F€€€Å1w@X€ +€€€€~€nÄH€)€€€?2€0€=€€€3Q€5€€€X€e€Z€€€€[€^€€€€€`€€J _g€€€+]€v€€€c~V€€€&€€€€D]€<Uף€e]€€€*i€N*€1€r€E}o€\€s_€i€ڦMN`ZpV8€/€6*€€6€=€x;U2bm€2€!d$€€ڟs€x€z[€w8€€€€I€ȋ€€€€€€€€€€<ڟ€€ۊ*2n4yL€ €F€€€f €€€€0€ c€€NT_€lY€y€+€ +€e€1{€€[пo€€€€`€€€-€€€€8€Bm€4€€€€2Lj€@€€8€x'€€||͹€€+Q€€€m€4€F€P€€€F%€G€Ѽ€€SQ€l€ŋ€€&€'€€€*\5€[€,€€€J<€€bW€€€T€4I€ +í¾®C€€I;€€;(+O €€€€€€v€€Ѐ€YveR€€ި€€]!€T*€s€€i€F€,ln€€€6z€]€~€<€€€N€w€
C€Pu/
€s€`id€€€€Żƛ€€]€?€nF€X€€1€+Fxq€VO€€ך€€}€€€€=q€8j€3€€€Y€€€lD5b€ǵ€*€€!)4Y€€€€€€B!ÉOL€[€/P€-€ho€|€\ €€€B€€ἧ=2€y€A€E~1€Y46€9€€€m#S€€p€>V ^€€}€€W€€7€\ €w+a€€€xq€€€[€€Ig€T*`.€,€D€€€y€€€<€€€€|\€[^* +j!|€€7|€€<d€C€€#€uP4€€ +€€ga€€X~€€EpK€a€€€U€€€"€p€|€.€X€€[EPj€€€€m.€]öA€]˶€€Z?€{-€ul#I2b€€€€O؎€m€l€€€l€l€€€MP&€€€NLW€€€€€K<€€Pj€€€mF€€€€€-F€S€_Òªg€Q*:€儵€Ⓤ.€+€v€€y€m80€€B€€€7^€€€i€.._V€€€|^€o€€6Zӊ€€e€€c€€€.[m€€Y€€1x€€€€
cptangle.SYMMKF€€€,€€€€MPSTMPS €N€€€€)€€%e€*4€€€ ?€€+3€QN9€€€le&€€3€€€et€̓€€l€€€€€€(w€-€€|€Y€€e€€€€€Z€€Qn€€€;N€¶ €fW€€€v€fۣ€€<7€€€€€€l€-€€€€€c€-l€ €,€€u€7€€€l€5€#€ؑ[€€<H`€€€€9€{!B€€-€|
€€,€ €45€€m^Q€€€€€*€`€€€W€m€€Ά€€€Y€ꪚZ|!4€€€€€€o[ŗ€/7€€€€€€y€€€€€€)S +g΂€€hV.€y€劫€€€€€€€yusk{€€€€Jl€€t€€€€&€l€€€5:Z:[€€€€€€€€€€@€€€€€€B€€€€€€€€€ߛ€݀€F|7€ۋo€€€{+€€€{;€€€€|€ķ߻€݌€€€n€/€1€€'€&8€€SX6€€J€€ €ɶRs€€€V€G€8x€<T€€s +€€5N=€@€€€#Q€x€<&nM€€y\t€|u€€€€%€€€€\€€€€s€€€|€€€€€c{€€Ĝ€€€S €w€
€€e€€€€G€€€W^€s€€㺂€€Z€€€€€€€x͹€x€€€s +€1€3€€xkÔ´s€1€/}F8€€€€€|€€€u€€)€€€+€G€s€Y6K[€€v€nߣ€€€^€~U€_€€!C€ݺ€€;t{€n€€aiSt;[€€€vX€_€€ɦ€>€>(€€#z€€€m€€€€€ €€#Y€g€€&i'€€'€-€z€M€m€€€€ۥm,€€€\€qˤm€€€€/€€/K€€U€N0€vH€€€€#€€€€€n€vJ€n{t;€ۛ€=i€n€€v€n€€€€Iچ€€6u€I€~]€€I;.I€K€U€i€€6€€m€€€6€€€€Ai€€t€i'$€€€€|€!X€€o€€X€U0'~€€>€€€1€іWP€€€€R€€m€€r€€^€€€7$€€4n€w€€8dY:PzBT8Õ?€aX€ €;€€R€€\=x<~V€v€€]€UY)[3€€€\1H€W€N€|f€€€€€€ΆPgW€€lК€~€cJ€€OS€€K€|u€€*a€t€'€Z€:V€764€l&h€€€t_[1N€€€€€€j€€€~€`{Gg€1€ݧ€~I€€L€€€P€=T€€!€€€L€€0h€ +€€€0i/ €€#!<?t]€v€€€Ú€4€€`Y€€€+
i€€€€[
€UbG3J\€€€€€=ÔDKK€/b +X€R€vD€€€€?€€€€1€€G
€l€€€€€€%€P€€wr€Ћ€€€€wT3€'&€'}€l€G€Z€U€V0aۢ€€ê€y-4_kk}€€MDu€€X€*€€€Sr€+-€€y€€&€€ ]€3€€j€€`€€€€€@€J€s5l€€~€W6€d€i
B€€|€€€5-€€€5+€[[€:G$€8V€?€AGB€€€]€~€ߴ€€K€€×>€€€;€m;€€€€€P€~€€€€€#€0€€€€€€,(€€€€HR-PS +€E:rX€€r\€i€.E€D1.Ն€€F€€Ñ-6@€€æ“€€o€ڴ€RŹu€R€cA€€€3€{X€-€ #P€/^€!Ì—w€k€€€€€h$€?€z€€€$n€.R€€€€"ÅŸ<€j€€osy^>,RP€€J€€ş€g€€V€€€t€€E€EU-R€Qsjn€k^U€g€€€€D€€€/€_+€@s€j€€%_€€1€€€€€
b1€€7€€T€PM€€(rR€€€t€ €P€€€€У€J€\€€S€B€€€€Q€Lh€€€€€.€€€€Ⱥ€€€€o$€€h€€€€€r€€#€€€E€€€€€€€€Ps€€€€W€€;D€€%€€g€ÛV-€€€r€JmX€M€€_€`€€€h€€€€€Q€€€[&vMTI€€R/€˿o O€€€2І€;€€`€€€€= € Y!G€€%€€€€ȷ)U€*MS€€€ +€+:€*l€)€J€kQ€nÕ²W\U€€€Q5€&3l€<€X€^1D€€€€€dF*€€_€€R€SS€€€€Ȓz€4€€&2)€€i€€ R*!ҙ€€€;ĉ€€ʚ€W]d€€\E|B€€(€€€€€€€*€€€n€Ď€s€€R_/€(?z[€€€Ð€Fc€€€U€Q
2€€G1€€€€€D€€$€€€ N€€}A&ጣD|€SÚ…E€€€UΨ€3€€bu€€€A€4€€€"!^8€jXOc€LP8S€€Uɶ€€6€ €ӟ€€h€7€€€€€]€€€9S€V€a€ƆN +*€ku€lj€€€4€;&€€€€€€€€€€€«€€/T€̯Sc€ə€^€€€€2€€岼€€€€;€€€S€€Л/€€$X€€€"չ€Hu€€mE€€€";(cf €€wT€ê™Â€#€V€j|€P€,u€dx$€G€R€;J€ea€[
sK€€€z€€€Ί€k€U€U€J€€€€ €S€€€1€€€^)r€€E€׀|€€€€=€€]€EN€€.€€=€!2€€d€s€;G€m€G€$€€€ΑI€!cp€€[(€€€€(€z€€3€H€€€䉚€P€€"$€T€€€y€m]€hN€R€(€^€?E5nK€K€v€€€€€m€€W<{Åy€€€.€<€€€€y€€a€€€G€€€€1€Dx$€=€R€u€S;€€NO@{)(2E€€€8SA}vjo¶);€€€€DJ^€€u€D€^Ϣ€€K+ˡ€,€6Í¥,€E.€qX6€w€€€€ڤg€|n=€#Ç·S€€€.€€€€€ €3pr€€;€€?€E€€6€€€M€€€€6€P€€znI€€Pm€W€U€€<?6€€<€€s,€m€€€g€€"9€^€€9ewq&€]~Dh€F3€€\W`€€€€€e€€_.{€€€$%O8€€0€K€€
]lvA€[׸€€€€€{€?Y}w€ €|w}KQ€€€1`G€XD€V€€nf€Hm€€€€㦎հ€€€€FØ›}€.(€€€?kR€>|Ê&؆€€€€`€€€€€€jh#€€dGxGР€w€1€B€]`vɎ€ja€€€KT€s€€kÂ€ÃªÂ€Ô (€cX€€€`s€€€*€*€€€€Ry€R€tI€yGIf€€€d^€€ k€? s€`,j€€€2MÂ€ï °Â€5€4€€t€:fq'}€€€2€
€€>€€j€w#"€9ǘ€€€€€$€€€xw߻w€€€€€€41€h€X€q€x07€€]7LJ€c8i4€€€A€€€€€Z*€m@€€€€ITY€#$€w€2€€kJd}€€Ѻl€u€c€=€€€_w'€€I€€T2€P€/Ae€g{€€3€'$8
€€w€€€ה8h€Lk€* +€vAgd€€€€'+%€€S5;€€_€€v€€€#^Owir€€E€€€€€(€€8F:2.€U$€d€_€O;€€)€€€5€€Dk€ԣ]€€€€€ă€n€€€|[€cqH€U€ϫ€€€\O€о€=€€€Joؗ€?€ă€n€€€€=SV3€:€€<k€€€h€€/Vt]€€€€Ai €t€4€€€€€:€€€€€€4€<tN€€€€d/€ +f€€€€€ە€z€€`Û’;wlYrg€c€€€H)€R€Sh*m'€@€qd€L€€&€€Ow€€€€€€€€ rqT€9>X0€€€g€€€9€BfTgu.:?€D€€€€€ރ[f€hCx€€P€€€6€€CVJbv€€}€€n€€F€d€€€€€€€7€'€€G€€€€#€€€P.n€€€€€€g€€ +€€€€€€n€€%€o€€ꖨ€ޯKM4€hm€TYo/€€)€€€z%€€Q€€-M$(€ח€ €€<rD8€+€€O€YW€Ö€€€*É—xxT7€ M1 €sD7€W€€€MY€€f€€,€$=€€P(kÏ'€€€€€È€a€€€[€€*/(€`e€€Ao}€4ÉŸ4€€Zc€€迺j€վTz€b €^H€€V€AC<7{€z€€€€€€ҟm€<€€*€6|€<€\}€^_€uw"€€Nè™»Qe€lЀJ€Ps€€€€\kzMÂ€ë›¨Â€Ê az€€WP%W$ot€k€€€€€"€€€=€€€*Kz€5€€=€€E\€€€ur(€Ɠ€€€ZNy€€|€€€€ +€€CJŞ€€€UÖ•{€€€€€ͨ€@Ä‹*€€€€€[€h€€€[\€€€鞓€}`V€€€€@€€€R(€€€8€U1<7$€€l€K€€s
€€€€€i€Xxt€€eqU€>€D7- +€€€#€/h€€€{€€k#€€€€^€€=€3€-€Φ€N€|€O€€€€€-€Μ€X]€M€€P€a€Vw€€n€€€€ €8e€ €`s€h€ή1-<€츪€r*€64c(@€€w€,>,nW€€-~€R[€]9€<€R€€f€ +m'€X€I€><€€€Þ€€*€"&€/$€1€UU€y#5€€É\€€€€€J €€€€€e€€€€€R€€€€€.D0#€
|€>€€€€€€€€KmP€Q3€€€1€€€€€6€€€K*€€€R€=7X€€€kA€bX]€€€€€`A€€€3kA€€€€g€€S€-€€€€€€S귯€;*Z`€€€€?SP€+€<€€€€M€D€!d €€!€N€_ڜ€€€€€€€€€€€y€€Y€G€3ge"€z€Z€€€€€`k€€Jڅ€>€In€ZcC€峕€€ԓ€€€ЗoA;4€3€€77U€€+l€€€X€€N€€N€ZKz#EoG€€€€€€rre^€€@&&:*€{€^€€>€d€€+€mn7€l€en€6epW}}Œ€1P€€.€€€Y€(@u€"€€€€mwC€€€fw€€€VV~€€€€€Jj\€T€bDv€€Y€d=€€4€€€Ò€€€€j€€€€g€€€m€b€ +€€5=},€€€Wz€T€€€€€]Ë¿/€€€€)€ҥ€€€K€€€ڕ€\€ד€0€€€iu€€€74v€€~h€€€€€€€%€`€€`€<S€/€D€za€v€ާ€h€€€€€€}m€%€€€Z(€ZA€k"€€/Gc€8€L€ €$€f€€€€Mj€€÷f>E€€€€f€€[€€€€hG}f€€€€ٙ٘€P€€2W9€n€€3€€Th€€v<d€€6C;€s€3€€€€I€€I€~€€€uͬK€€€R€y€€€€5€€N€€nat€€"€'l€€€+k€6€€dz€6G€x%<€
€?€=}€C€ф€E€i€W.€€€€€I;€€P~B€SP€ +€€>WUy€^€€b%f€zl€a€眗€'|!vH€€€€€€€+€€€€vj€v€€Y€|€€€d€€€€€€€€d€€€t5Y€€캧€"-H K€]€€4€)€€w€€д€ޤ€d€€€ €€<z€?Zw'p/€€€€ QVU€€€6YW€€5]O€\€€€€a€ͱ=4Q€9€€€€ZU€€€#€r€{F€€Y€€€ґ,8™,€€[R€€J€!X_€€1nklokkԓ€€€HO€
€8€y€€€€€€€€€€€뎷€€ëšÂ€tS€€
€€€€ (€€€E9€bV€€޻€€€€;)7s€W€€€€
€€€C€p]e€j€z€a€€^€C2v€€€-v.€€g€'€[€€Vt:€€X€WB€?HM€€€d€€1€g€uG_K €€Y€J3r€
€:5{@v€Ć€{€ڶ€€O€€€€€(€ €S]%T€#€€6<A€+^q€€B€g€€€€v€b€€\Fv€-€€l̒€b^€l€€T€€,#€UV€€2€€€€y€€ض€r<€u€€ȵ€€P|€~[)€€€€€7€€€€€€€€€€€€€l€€;€€^€€€€j꫘€€,€hk€€\€\߈€2s€€.€€€d/€€€#{i€ \€=@€;{o€€w€€€€€€€"€JÔ=€€2€ziÖÉ—3>o{[€_€€€o*-€€--€.v€c€€_{I-€€€4-ڹ€/z€2[€sF€vG€€>€w€€6€€€N€€<€€r€€x€€€ێ€€€q€€nò€€zIv€`_€b€+€I€€xP€?,q].D€€)I€€Ku}׀نe€z€€€€8€7j8€/s€€w€€h~0!€€€€ + \€€_€:A€P€€€V€€€혊m€AÇ (€;}€€>€e€oe/€€wr€}€.ʼP€€€€€(€€#€a^€ie€]€€€~€€6K€3€G{d€;!13€@_€Y€€€€6€K€%޹€€k€€<7_€€€€aM€Ã€7l€7n€ €€簖r<€;€€!€€€R5€€5€€€€€2lD€€€€Ur€€€w€€*€€:^€#€VD"€€€€"€/€€€}:€€€p}€€f€c€€€}€€€€€€€z€€d€&€ѫ+I€€€_ß}€€€l€€[€€s}I€€€>f€€€€y€az€
€fz6€O#€LW€st€€€€=ɞ€€zz8€€㠂(;9€€Z€€j€o€ +€€X=Tw€A€"€€7€€fq6€8€€€o€x€€€€€€s€€€€€€1>sj5€€F€€€h€€€D€g€D€€+u€3<€€€€6€f€գ€€€€)€W€€€€€;1€S€t€M€Hm€€€€|€q73€€€€€ڃ- +T€€€3%J€^v +€|€€#€P€t€€€€€u€€€>ҫ€_€A€€#€U€€€€=€€€y^€€}i{W€€P€€t€Agy€m€€€€€€q€l€ +L€€€cڞV"^€€Id€€€)€€Q€€€b€1€€€€€€[1€€€Ӕ€35€€T€€o'<€y€gF€Q€€;€€^V€€*€CI€€€[€{€€€€1€7€€€M€KL€€'M€ +€€€€V,€€€€€H€€PW/%€3€€€€T€=€€0gx0€L€U€€€€AH€€€Zo€^€€€€€0q€h€N0€€H€€€€€2€"}€
2€€€)T€Yh€€€€€:˚€€€\€€€€g€€&6ÔªsT€զ€€€w€€€€€Ww€{€^ݣ€€S€€`€H€€€€:7€ 6€€(€|€€€€=€€XY€€€i€N€G€ãˆÂ€Â€Â€Â€D€€Op\€yWV€€W€€i*X/'Ò°4€€W€€:€€€€€€€€P€ӓ€@€`€€€6K€I€€E€€& +€Bؚۣ€€€E€3€€€ ~O€€Y€V€€€€€€4y%LB€€€^Â€Â€Â€É C
€z€U€O€€€€܋€nw€€€*€€€@€€€3€ބ€]o€€1€€)5€€€b7}€4€€€ɣΪ€y€€c9€€.Q€€B€€€~€€€c€+G€s€€€`8€1€€g€€€'€ElQ€Y€z€€1€€92[p€€C€€޻U€€€€€=€@ե€€>R€€1€{€€ǔ€{䔄O€€^Y€HçŸÂ€Â€Â€È‘€!€€€€€€F€€NX€€l
:Z€€€`€7{€€=Z€Oe€<€ +5€4€€€zjN +€€ĩ[€0K€Z€&€€€?T(€€€€>€€p€ԧ€3€A€U€€:€w46€B~̪K\€€€剉4
JlYI€ٳ€1€w€w€€Dn½€€#€E€€j€b€MN€€x€Ý€]M|7P€€€<Q]€€K+(V€(€€€€€€€V̵9€€€€€߷€€ €€€"€_€€7€/+€€lb€/EtD€€OÆ®Np=€N€T,€覹€€€€x€Qv€k€€€O€€€€ ~2€!€sw5s€€€X€٬€€€€W€bK€R€o9€€€e€"€%}d€e€€D}S€n8(€€[Z€€[€€o€€DN"€€€:#€€€A€€€€+€€)€€€€€I€€€嘩€r€€kJ€€€€T'€€€˦NR€,€gvdVX€B€=D€€€&€€|;ßšO\ 1€.€}R€ֶ€X€€j*€$€P€€W€Û€€&€S€^n€@€€€€<|Iä©Â€Â€4€€€W€€€€rZ€€nnžW€€€€€T€f€S"€p€€g€*€€€c€K€€€sj~€€#݉€Y.€€:€[.€€:|#€€O}€€€€€€ +G€€€\Ad€V@n€€Lܯ3€€$€,<iHj€iе7€€~€€|w€$€|'c€€€,€y}€€€(#€€€`>={sD t€ C€€€J€€L€M€€|-kFP+€6R v{€&€€€€€€B<,!ul€'@=€=t€2K#%)€Ԛ€4S€€C<IC~€€qh<€€€€€€€€ni€=€€€ +€€€]€€€N€€€B€@ÆšrR-v€I̟€Dn€€€€EhhC;F€'#O€GH79€*L€€€y€€€8d€€€2€+€Mz€€€€€€xVO€€J€€€J_€€JcDZ7€/g€€VC€H€ɤ€€d&B(M*b#3x€u€€€€€"d\€€€€€€€1€%'€ͦ€€€€€:€€xz€€!€]€v€€€€€€€*=l€€€Ä€0€+uJ4V9€F€+é‘—0€P€+W€€€€!Q€A€€Ht€C,€5Ñ—Q}€€€A€€€€€d€'0$5€H€,\?'M=€}€&€"€{€€3~€8€€€،€€J€V5€€€@€€€€}€€N€€y€`>&s€L]€r€cmm_€€^€€€=R€w€_g€%€€€}Y€=4€€/€€NX€˾T€k_€€€€Õ蛶€€€9€D6€0€€U€€€g`€^A€€UW€€D5€=€o{€€]~;A€<€€€€€u€UFs€€Y€€w0ע€ilų€€*%€€b.€!€€€&X'E[>X€€|€€Z€V€€€€N€€€*d€zX€ٰ€E[E€€*€8q ,€p]تg/€€b[€€5€€€€*€y&s€€€€€}€€€T€€S€€߸€€€%}c€dt€7€-€g\€z€.€€€,€€9<€€€
€€€
mrg€€€m€I+`x€[€c€P3€+Sxs€>€€Î3€€>€€€tԷ€€€fÂ}€'ir9)9R€€Ftu€Iq€B@€''€7€w€w€[1
ogD€€E€f_ +smmwlfm€Î€ά=€€€s€焊€I€€€ €\€€J€,q€`?€€€lD€€€€€€+n€€5€€€€€€€2€€€K€€k€€€€€8?|€_6€€€;ASd€€%€€]€fM*€84€m`€€€€x€€)€€9€€€€€i€€ÒA€`€J+€G€ +B€}Y€}ϓ€€€€:6€b¿€€_€f€€6€m€€€2€R€Nd8€€*€€€V:€€€€>I€,€ €€€^o8p@€=€g€S€€€€(€6€€€€€€€9E€€ڪ€zO€=A€€€eM€€€€€€€€€b€€€`{0€€.Nx~€€J€€V5€€€€€T€€˰G
€€€6€€€q€€€€aʛ€t€yO~=_M=€g€Y€€€€€5€€< +w
4uc€)€j€z€qin€6€,€€a€S€€\€€€€€€z€G€ TK`€jsXN€̸€2€€XW€€€€8€b€Ó€"€€H€fS€€€€€€€H€€|€p€€€€?€^€€€\UX^ f9€QD-@€c€€O€€€<=€€SBÑž`€€€€€€€€J€€€€n€B€€€€d;a€q€2:!ǿ€11€€Ʀ>€^? Keq€€:Cz€€€€W€€-€€w€€&€€X€€Ȝ€agȳR<€J3€=G€ZsT€€€аN€€d€€€€^V !O€€€ʬ%€€€i€4€€€$€yk-€€_K€€€€€8֧€.€F_€€P€€€€€€ܘ€€>7G€€Yahۣ€€€€<€z:G€O€s\€+€r€1€€€-€€€€€€N€€툢€€€+*€"€€€€*€€€€xa1€€€€UaU€€>€€€€€[€lɄ€€€s}%*€2€}€€€,xB€Y€v€^ €TgK +f€€
€€.9[€#€€e€€€a€€€p€[€€€€€€€€€@z3€oU€Lh€&€d€ +€YT!€qe&€z€|€€€€€€ɤ€€,€€1€9s€pI1€€T€oU€€M€€€€€8?€€ў"ft"€€€€€€€e€€c€O2=p;€J€\˰€€.5€7€w€€€€€€3€€€n€€€€є€€€€sp€?M€€G€€€G€€€>€€w€}4€€*fS€?€x7Pm"rd-9€u4€ꫢ€3€ܞ€6€€m:€N€yW€€€g;E€
€Y,q|v€WѼ:X€€v€€€?€+w€9€€i. +€q€€$4?€€<x9€>UHW€€€{€€€€€€Y€]r€љB€€€€|€0€Evʌ€@€*j€j€€\[}€€L$€k€^)€€€_€^>€Af €6€€M€h€k_€€!€€€_#€€€˕€€€%c3€€<$€€€B€€ֻ55€
&Ϻ €€€€€G€B€€€3C%€€72i€€_€€q€€€t€€%€pO/€xA:'€T2€€p€xe€€z€#€€€?id€€o€ۥ€€|€^€€€`#€€hui€€(o€€QU%€€g€€€-€~€g€€€€=k€T€g€€€|gtz\€€€&خk€€%€c€€€€€S8€2€€€€f
xR]€O€€€€€Gy.€€6€€&P€Ǹ€㕣>€0Y€€!€€o€€€€€n*€ݴB€:H€ӱ€€€[€8€€u€€L€€€€€e€€€[5d€ƌ€€€€€Y€€ü€€dY€€{Ɋ{€€€€#€ߖ€€€e€€€ {€Ʊ€€,€6€nd*(k€&€{€€€J€€-€€€*€€€r€€͕€|I€Aķˡl€}€hyp€HF€G3€=6€jW@ۯ€U€€ap%€i€S€€€k€գ,0€J-€$#p^g +€?=#€€€€€€€FY=E€o€€BF5€€€y\#€€€RG€€x#€N~€€~€A€m€€\€~@€,€e€y€€€1€1€€Ǧ€ƑUY€96€€€ €€l€:€[€Y€3€€p€8€w€'
€}$€€€Vݥ€8€W€x€€€€€&6€U€€V€hmh€A€€€L€€;€€€9€€k€a€{€{€€€A€€€^;^€€€=H€€3Ӝ€€€!€[€IÔ¤hT3€€€€ǚ>€jz-€ijÊ€€€c€€D€?€g€€€€€$jk4*€Ø€a€€€€€€Qs9^€€
€D€€€w9€S€€€qT€€h€€G,^{l€'Q€D€€€€dO€€I€€€Q%Zoe€€O€€D€B€a\€€A{L€€€€€€w<€€€G€€gZ€€#€r€'€€€q]€Ѩ€8€€€o~uY4*€€€W€€€}TM€W€?€€8€P€2€oo€e€€13€¹€%€2sV€€lmzE€G€I7€m€خﴌq˘27Zq€€Sj/€{€€€€€€e€€€€€
:€€€_€€Y>€€€jq€€€-€pz;€ÜT€€€ãY€€ɩ€(€€)€€€q€6I€€nQp9x€3Yn€hd€€J€~O€ք€ €€€€*€VT6€Ϭw€€€oX€܀€]€k+€€S€.€€ļ€c€€L?€z€T€;€€~O$€€€/x€\€€̒€A€€€W€€€5€i€€€€€€€M€M]€{€€'q€€€Į€€x#€€€9€G€T€€€ݞ€ +mfy€€€a€SU€€;€)/s,;€>€Y€€r€€
€3€€€{5€€=€O}0€a€€I€€N€2{€s€8€€s<€+€ +€€y€z€€~€€8€€iÎŽg€€€i€€)€€u€+€€€؟€€m€L€{€5€K€}$€€€SB€€€6€€€±€€9€<€Q€A*€`E|€€€8€€-€v€y€E|€e9€L€_߀{€€€€€€€€8€fd€Y€xf$€€3s"/Oӡ€€€€U€€€7€I€\€€3€9€€ћG€€€T€q€€#€€€>€€€I6€€€B؉Fz€4€€€€^€"€w€€F€}€€€€Í€ߧ׮u|ZË¢N€]€€l(€€€X€€>Ö«"€5€J€D€€€€Ԧt€€".A€xN ]€dhyG€€{€€M€-€€€]ش€€€bq€=€#[o€€ΑhFD€o€€€€?€+€€2€€€€*€€€€€<G€€M€€€€z€=€€z€€€4€QP€€!€€\MFt}€ +w€!€€[Lyr€y€€€(€€9€sz€̗(€€+€z€€€€?(€&=€€€`€€€€€z€^uU€!€€G+€$€€€€€€€|€F€oG€€<=€mf€€q€c<=Uta>€€€€˷€€-€I€€;e€€€#€w€€"n€€€zEK0?{ë™Â€Â€Â€pZ€€€s4_`€€€U€C€€M€€Z@€€2X€넿e€=VFD(€g€€'€ZÛ—x\€Ř€€€g€€€€€€€Ӣ€€:€€_€~€:z€€a€€€€€<€\€O€€V+9€8V€€swo\€2Z€€€rlie€{|€€|€ €€M€€g€`€|€€9€)€€+€=€€1%€€M€1€Y5~€'€€kg€
€|€ul€L€9ddl€@€€Mq€€€L€Ã€A€T€€€X€#€€rf€€ZL€2'€€ +€€€d`2'-_€-€€€€€sh€€E`+€r€MR?[€TdzFe<k€LsD€#<€A7M€;€đWl€€€€€諯€g€€8zM\>€€€€€€X€<1€€€ E8ZD€;G{6€€#:X€€€€€€ɷbf@€€€€dx€w€j€8€D€[€€Ê€d€€_€€€€€V6Ǝ€€r€k#€€'€2€€€€_i_€€9}rӴ€z€=Ô…{T€€€€C€Dr€€€Q€€€€€€*1€€€€~'nP1€*E€;€€€M€\K#;€€€€|€[€€Ǹ€=#h€X*;/Y€g€€<]2€ht€o'"z€€"Ñ…1€.€8_€€€L€€€€€h<Y€A€€m€€h+€BD€€l€֟G€€h€€т?€€€h%g€I^€~€DK>€9€€.G;t6Z€ϣ€!€€g€€€€hF€€l49w€f×£]€.;KN€€+S€;€€€}€|€H€v€Qy)€€
4€€ʴv€4m0€€ €m:c€€6€€€al€8€€€€€m6O|€€;Ў€€€€€Ȇ€'~€€f,€3€s€€€€[j€gA€Z,P€€€€/x<|)Mv€€Cb€0€€€*€Y€€e;b.]€i€n€€€2€€€I€€€le€e€€o€€€€Xg€g`€ʻ،€€o€V}d€€€޼8€K7Ñ€Cß¹LoO€€_€€€€f€€€<€]ϳ€=€t%€€€?F€i€€€_`ӀR€€€E€€€E€€m,Ԟ€hc€7€€€ €(.[_€€@bÞ¤î¶b€€!€€M€€€€RM=ß0€"p5€€€*€1|&€L€€u€€BÖ‘wt€€€€€€€€zn€€?{€€L€€Gh$€€€n€ €€€€c€€(SO}€L€€€!€€=€€Sr€€€LW€?a€V}€€T,Vh€€€€3€€{€€M߈€a~€ƶ€€J€€€7€€€€€€€€J€Cf€o€€C€ €H
9€Xb7H€€3€€d4€*€€|€y=k€kFftxv9€€9I€.€+€r€€€d€8€€€ +_Êšx€pM€:{€M€€F€yk€€€1Y{€€hv<DY€€ʙnзs€€+€€ݙ€€€€آ~C€€Ôb€€8€>#€€?€€€B€€njoю€€Ur#q€`3n$rlB/€j€€€Gj>€€€1€Wy€ʡׄw€€€*€€€_Ty€7€3b
€?UY€€€€€OX€|€F€€€d€€€N!€h€€fh€€€€€€ƹBM{€€z&€0€.€ޑ€€=1€€€V€€€o\€€€€€=|q€G€×€€€€€€€s1€€/ޕ€p€k%€€df€€€ߥ€€€^N€€€#Mt€[~&ϯ€<€€€€€€€€<€€€-7€ꛟ€ƯW€€€ +€€€8€-ᬤ޽€I€e€€€€ԉ€v€5%G€1/€€€€€€*€€G€Q€€3€€.?€
€€€€֣r€€€)j€€€^D`Xo€€€p€€€€€?€€,€€.z€€>m~D€ܗ€€€€€€€€€a€O%€x€t3nJ€€QÉ°z#€Ϯ€vZ€v€p+.€€€V€lۙȗ+€>€N€€F€&V€€/€{7€V€€€/F€a€O€€P,¹€€mz€w?€€€€bޒ€<v€€€€u€H€€€€€€€btMx>T0Ø“5€€z€€€H€1!#€⾂€€;p€€€€nk뛚[€€€G€ €€€[€ €€h€[#T€€XSu€€-9€€u}€€N%€€€€9€5€&MR1€DSNþd€/}>€L€€y€gR€]'€E_KÄO€Xm€DÒ³H€€5e€€€*Ҿ€€]€€€w€^€oyuO6ԧ€€€€Qp€i€"€€V€€7׆)€€€s€€€€=€g.€€y"q€?T)j€X€?€%€$€€€€€R€>€€€.ox€€€€€k>€P9€Ħ€rê±i/_
€€:c€g€IL€€€͜€€x€p/€€z€eAg€0€€x€q€~€€4€W€€€[€Fk€€.€€€€€#€€€]€€Cq€/<€€J€\€€7t€€€3z€/€€~G€€€€BY€€sW}€D~&M8€Xb€Ϥ€€C€€OV€€)€
Ӗ€<cȣ€€€>€VgS,€€?€m€Ǻm€_Vq€(V€€€€-p€W€d€q'€L€"€€W€€€€|€A€€>€7€53.Zȕ€€X€Nä!€q€€€j-€a{€€g€€U]%c=€4-€€v€
€€5€€6€€]€€Mi4€€€ݼ€€?€Q(k€C€u[qo€€€40€Â€€€x€€€€€r€€€Sg{€3TO€€^€R3€,€€?€€€€{€}€d2€€L€8€€[Lqf[€€j€m€€9ޔ€HN€C€i€L€€€o2€€,f€€"€o€3Ç“o€€d€€€M€q€&€€€f€€€K0[-0m€€€g€€ER€€aÚ¬f€[P€€€€g€!€8€€€€@€8€€`€€Œ€€€C€€b€8)iF€xs\€%€d€[,nC}€?G=€€L€ %€єnEI€€€€$P-€€fJ€€K€€8?[Pz€>N€€q€g2'K€ x€€€8*€€dC€€*€Σ€€7€;€̦€x€P€9€<€ +p€€€€€iq6€n€Y(€L€€F€Ո€E€u€L{:€o3۩€€u€"'€€s€bAo$'€OJAqχ%lA7€€€€€3€ԋe5]€€€ &k€€n€@€€v3€€lv€"€9>€\ËŒ8p@€&€RL€tSze€€'4€€'Ú€Ɉ€B€€$€I€€}€ɡ€g€€€€€€€'Â€Â€Â€Ö Â€t'€͈€㓓€€"€€€K€@€€€€h2/€9€€#€9 €LX€€#€^(8Q€p€€€h€€€€^€#@€P€€ €p€€d,€€€2€€V€€€g€€85ʖ€€_+ZR€€㸔$j€g€€€€€€€€€=€f€€EX€"U€€€Ȝ€Í€Y€,€€LIq€mÖ‹i€GG! 0€Aj€$ €€IH\2^€l€€Ȗs€€€€€€€€€іLå³Â€Â€Â€v€>€€€Z€'€€bL€€ѾԌv€1ܼ€€i€\iB€x€€€ʔ `B€v€€f€(€F€1I€€€€B€€X€€t€€(€€H `1ZȎ€€€AF€€.€€€€€8€€€€€€(F&$€;%€€€€!€{€8I6€=b$€€€€ .#B€e0:J€E€6€
€€€l€€l€€<€6€€€[m€Q€€€€€'J&@€€€Č€€iq€΋€q€€€L€;z€€v€c€€If{|€€!€t€€s[€€V€WvO€€€Ug€s€€€€€N€€g4[€€€€€€p€/€€iM€Z€Zf͸€€€€€€€€+€€€€€7€&€_€€€M͜b€€€b-€vZ€Y€€€y€Dkq€e€kƥi€+`'€d€g8€€€€€€€€з[€Z€3SW,€€gX€]€€€€c-€€LN€~qV€€mm€α€w€€u€€€˜€€€€€€€€€7l€}€€€€€€€[?=€€ €€9€€y€֋€€€€€€€€€z€u€5?€eMJ€€\DVM:Y€€&Y'[€[a€€o€€g€€t€€J€y€€€€€X/€f_|€€R€€€€€€€M,r€+€٪E€€^€€€b€€€€q
€v€L€€]€€;€ǧ€Y€€€€_|°€ W€T\Ô Â€3€€€€+€€€7€qk€€€i€€+€~;JX.€#€€€Dx€n€€€€€€€€֖.€X\€€p€€71€<?N€
P[R€€Rq€W€.€€R€€Kq€Q€
3€p€Ê€€}.Ç€Z€߉€€}€€€q"]€€U€8T€n_€€€=ÔŠbt€€*7€€€+ί€2€€
?€
o>;€€˙€€p€[х€3€^€ɗ€€€4€VO€D€n6€€€I;ER€€U€t1]?€€€=kU€E€€-K€€€€g€€N€€€€€€7€SRH€€8R€N\€€d€€€93€€€€*€€€0j€€€n€[\€€€€€€7€&?G$€>o€€€Օ€%ee€€]€//€€9€
~€€A€€r€}€€<€€߆€Ow€€€€€O€€€€€ì¼Â€ €s&€ӿɮ)YS€/ɹt€€€y€€ͼ|Ö§f_1€€€O€-€WRêž¿`a€"€b€U€WWTV]S]S€d€€u€-€€€€^_€6€hlj€€W€€€€€-€€€PGg€€€ܴ€€€€u€3€څ€€€Z€€QLV€7€€ +€€Ƚ€ +€€nV2~€|Q€de1€€€)_Jg{€€€€;€&+€€€€€€€€€C€%2€767€A€€€qt€€€ʵ+€C€JK€€S€>5€%€WJ€̣€c€€€@€7€0}o€€C€€>€y€€܄€ʾ€W€€D€{€€€€€€€€€f€€€€€€M€€ݡ€3€€€€N-t€€€€WO€€=q€P6€L|ݜ€€y€w€XJ€€€€€€ |€€€€p€€€€k€€€ex€"]€€P-€-€q€€Hq|-€l$N€€SU.€€€€7)€€N.€€€€HQ€ +ݔ€46[:oR€€467€€€€€€€Iiji€p€€€€I€€€\%€€€o€<y€€€)€ԎDg€e!€€7€€€€€Jʃ4nÜ Â€Â€Â€h%b€BA€\€4dy€€€8s€€(€ȗL€€€€J9€€€&e€€FJtV€€€€€ȣ€€€s€€e!;€€}€]€€€K€€€,@€oj€R:€€€€€B\)€€J€ +\€6€R€P€jB×µ5€*+P€€€€vG€€€€p€|€Ê! 2€€ €veC'€>€p€€C€€v€€€T€Hu€€€ +€€!=QL€€€E€vL€Kg€g6€€€€€€€€€o€€,€€*€h!€€€^€%€Y€3€€€G€€€€c€b€€ €Y*€€€€€
€€}k>€"pC€€F€€ $€€€@I€€€€Zм€€€€€€Y€1p€A+€€€€€M€€H€\€<€€c€€W€S€oǹRu怒P=€€AHb8>Y)m[€€€j€€ B€€€€=>€€<`€x;oz€8p€€~a€€€P€€=€۶€8€F€ K€tv€€€€?€g€ €€€s€€€€€€€€€ç‡Â€n€€€€€€W6€ڕ`F€̟>]€-€XT€P€€7€C€%pPuMC€j€€*3€$€€yE€€!€\vå•—+€€*€€€€Y€~~€€€7€M}96€ €E€€C€€€€.€ €3€ €s4€€-€€SY€€€€@€€€,€4€ml€å€€ €€@€Ãuwt€€€N€O€€8sÑ‚Ä«; €:€ +q{p€dyb€€剩M€n=€€€ѴM̶:€€m€€47€€€kC€€€&z7J@€€€€€€€€*M€$=€€\€9€€€€S;R€6 +"bQ۩M€€€)|{a"€€T€€€"€s€h€<wjÇŒS;€ž."€'€(€€QT4€c€t€p-€7€€{jG€ܹs€A€€\X€€<WO~.ؕ€{€€ϟ€€€,G$€1€`€€B +$@€€€€&R(|€€€h€YeQ€€)€"€+D€€!F€€r7;k?€o€A!~€€€h]d֣€#€Ϥ€€€q€G€Dnishh\€^Ø‘l€?€€Q€€€sÑ‘ 3fÌ;€€€h€tH€s€€€€€€€€€€€€€h€€u_€"'€€(W€tt€6€u=€@,h€"M €|W€<. @€l€ZÖ¢q€!€I9€€€€@c€€g€€*P€H€T€€8d€`V€€)PmO€€s$d€€QҔ€€€€€ݒ.hR€h€€€€1€3€87@€€a›ÏP€i`€€€€C€€€€uutB€G€€€&pj"€!€k,$€€€€Ζ`+T`HDJ€%#€€€D€€l€̺€€-4N2€€€8)€€€S€€€€€v|R€ӕaqÊ™}€n€d€N €€€V€€Y8Y€€/€€CM€*8h;€l€€=eB[P€Y€€€^€aF"€€7€4r€€€€$2€{i€€€sG€h7€Ҧ€4€€€€6€<€i'€€€€€9S€k:A>€€€€€qaW€,€€€€^€€€€Tb2€x€xM€€*C)=F+L"€€€€€
_4€oxp€a€€€ +€€€a€a€€€€€7€.q€c€€€€€
3
€€€€€€€i€[?€?€€€€€17€€€a:߈€"€D€€€€€€SFO€€€4€€6L€€€V€€-€€€<€o€0€€€$L!a€€ն€€€p€€€Sg90€;u&€€5؂€€{€V€=&g€€€&#€As€:€€€€9aw€0€[q?€€&€€€€W€€v€€€€k€€}€:X.€/€€€?\€ €H€9€`€K€[€i€\h€ 챸€vc€x€Q€b€€o€€€€€€[€]y€]€€€}v€€€€€€o€€€qtT)v€€€€€€€€e|&€€8€€:€!€€B€:y$€ +܅^등€9V€c;€L8.€͑€p0R€僚Tq<€b€€o`€[6€F€o€€.)€u1€€€q€.€ÿ€€€ú€€€E]6€€€€E€u€€8€nF€
€Fjc^€€€€/€#€Ы÷€€€€ŌJ}€L€'Z€€H€Z€€@yU€€€€dqN€€€de€€keP€€-€Q€€.€Ի€\€Ajp€€<h€w€Q€5>€€;€€€5€€€€u€€܎€€€€€3€7H^€m;y€gF7N€€€€<=C"€n€Äk€fo€2QEM€€~:<€/&€€€€€€€€€<\€€2€€}.€þ€€€Gq€{-6{€v€H€Mز€S€€Q6q4€j€€€S€€€,)k€€€€%?tÖ§B֋€+€Q€'€€€€Â€€€R)s€}\€€[E€>F€€€€O€€€€p€€€<€€a€=;€Wb€ɾ€€S€€+€€C€€€?€M€€€!€Y€€€€€€€€€qR€€€€J€H€€N€h+€€€AU€€ń €€€€€€€\€L€֊ڊ='€€€€k€o€[Þ’9€€€€€€€€€€€ +?r+€€€6t€€€€.€€€I:€x€[€€€€ل€av’€Yu€ս{q€;r{€oF€€#€6€€j^\)o€€ް€€€€€€[lm€rK7:~v>죴€Vlb€7ÜŠ;€z€€€€€&[€€(m€€€m[€ª·€_€€U€/_€U€o7"a€[€o€n€o +€NTb€?€֥€€€%€€u€€€u€€€Y€e€Y€.S€^€T+€U€€x€l€Yu€€S€€9€Bʀ3a€€KS€€€€f€KT]€.V3+m€€$€&#~Һ€_l€€€€€€€ +€€€HY€A€|?€Ӌ€N€Uĸw{€t(€€€^2$}€€z€€x -€€V€5€€m]D€zÝ€€€aQ€€€€ev€\€lÅ®~\€j€R]3€]cT€€€i€€€€€€€8U€5s€€€€{€€^€wÏ«Fw:€H=€€€€r;€€€€€P€€4€Q€x2z;€#rK!ݾ€&€€€7݇€€€€5€€'€=€€€3€€€€€€€!r€7€n€%€H€s€3€ €€q€€qà¨Â€Â€ €L% €€G^Z€V^Q f€q.GK |€€€€€€€€h€€€x€€€ί+,t€€r€B€€@€W€€E€V3€f€}z€€€€<2€nd€€ߵ€€€€؈€€€€€Еˎi€€q,^'r€€IA'€€9€€€€€Y>^€€€&€€M€C€s€€,•€€
v1as€€€€N €€€I€€i€|€Q€n:5*€€€!€o€՚€€ĕ€€]€€€€W€o6y€€€q€F€S€€€y/»€ʟ€q€€€€;g€m€€€€€€€i€Fg0#ٿ€€CT€M$€€2:€s€€€*€ĕ'v€€V€€H€€VQ€K€€€€[nCǡoh€j3|o~€R^֥€€xP€€€PC€"€P€K׊€€€€€V€%ƒѳػ€^€:€F{€€vaÔQ€€r€€> €€%w€€€&€L\€€83€€€vӦ'o€R€H€͸€3 R€Nl3. +€€€€€vaIo€t€€€€€X€€K[f7€€5€€0H€€6€
G€€€€€t€€€J€€7€m0€€_€€ћ€]€8€€\€/€€€"€€€€€L€_€7€€€€€€€3b/-|V*r<n<NH2Y€6€iC€€,€WX€N)€€}€€̋€;K[[:|ѻ€.€€t/@Ǥ€~€€€59K€€€GwR€€ €€€`uq€€€X€€€€\`U€z€|€^€?€e€€R€€€2n€"€BMYrg~BÐI€€€:€O)€€.€`€€l^0€O€€|€€€הzc€€j€,€€g€m€€€tYe€€f€€a€Zn€]€L€€€€€€sP€BTQ€Wi7€xJ€hk€)€€2?7.N0€€€€€_y€/€S€€€B€€€߮€ꩿ€;/€€nT\€€€€€€bR€7N€* +€V€s"E€ms€€ԕPM€T€1€-/€€€€e€N€F€ +€€ã£Â€y€M€;€s€N-€+@€€€C€D€ed€B€F€Λ€€€z€gp€.€€.€€€(lh€€\RcH€€€€€€€€€5€-€[€9€€€€W€QgS€€KXQr€֢V€wm5€€€€]€˧€;€P^€<€€€€c(€ht{7E€\pM€€Z€€€€€€€€€TW€>rig€€j%.Â€Þ +€€=€"pj5€F€€¨€ +€U€#.[€€€:s€x€€E€³RX€ +|€€€S€€€T€€Kd%Æ«ZM€€€fNK€€D€II€€zt
bb8wj71€ת i€D€€€€€9€PC€t +€€0;€Ev€8€]€fO€€€k_Ԇ€vO€5/j€ +€€R€Մ€€c~€q%~€€Lty€-߈€N.€€€€€1€io€€f€7;€Wӓe8|k€z€{€_€€€#€:€%€€€DVf$+ɳ€€JV€>€€ӥ€f\}kg€€€€€O€€ €€^€ޢ
€€%€€€€Ä€i€f€Q€€€€€N(nK€€€€€k€€€L€€3€?z>€€|oE"€€k€3)?€"€€B€€€€€{€€C9%€"€€u€€€€€€!€€0'r9s€XkEP€Lw€1€*€ +€%O€jE*m€YcXr'km\€>€ +<Gќ€V[€w€
Jn€€|€"€æœ(Ú´Wi€S€8>€AE_zu€€€€€€€E
^AEw#€7€€€S€]5€m€€FC€v€i€€?i€€€€C€c.€=€u_€€€W€w>N€€€€€dG€E;€€€y€€i€W€yo€dU€€\U€€^€l€€€€€€€0€€€O€€=€ĕ€zT€€3€6O€^,(6€R€3€v€܅y+€敋€Q€€€W€y€W€€€x€€€€s€gXGl€6€€€)€\€M€=€M€*;€u€€"€€€€a€ €gt€$|€pqϦ€€€€€;€u^€€€W€`a[`€€€€€€€€?€'tÞ¾(€€x€x€/€j€€Ò€q—:ûn€cBm%€€h€€€gN€o€Gy׾€7€`#€($>A€€€€€€[€s€€€]XW;t€€€uB€b3_ €€;#<釽 €€n€€€€€€ѩ€€E€X€e€v€x€X€
€j&€€H€€(C7€x€xykq€€z€8 +@€€€7ӌ€w#j€\0€K€K=€€<€€w€9€6€€Y€€U€€[4 €€B€hM€€€€.€<€€€Ⴟ€€€vÉ»]€qÞ¶N9€]€rU|€€]€€=€€N=€€€€W€6€.,€€€A€<€JGXl€€T€Ê€~A€€€€J€€ÜK|ýH€PS€€ +,[r€|€&€€€o,€€E€h€€H=€|€€€€Q€€Jc€€€55€ +€€"c0>v€.€Ȏ€r8(2€€u€€J€RG€A't€42\Q€ L€€€€wv€€߅€€_~ʌ€j6€1€3€€>€江€|€6T7k4ß 1€I€€€€U€~W€U`@€{=€h+€€ye!U$€Z}€€/€€RG.€O€@€v€€G€€Sa€€W€€oyO€]ut€€n€€€mT€€8OM€6AyE4€€€gv/R€Gk:€*':€c€€€:€ɯ€7.7€€$h€V X€€€€Bnz€€€DžH3€€<€E*€5€€€€€z€€€tͤ€€€€5€€`Pt€x€C€€€€€€t€W߈€€€'!zC%€"mZ€€hn€]€H€€A$€€!€€F€S€€O€€s€"B€=€jÚ¡2€|€€€€€Ўϓ€€`€€€~O€įɞN~€Ş€S€€J€€ʊ€͞€€€k.X\Z^€Ƚ€€€€B€€t@€l€'€)€€€=m€ܮq€€
€>ú€_€€9€€€€€€2€€€€uj€€€t€?'/€W€€&€r€c:€cIlFh€€/w fb<€vY€€u€4€€N€n€€Ǥ€€d€ €€.€€€€a€:€€8€,€€6€€خN€}€€€~€€€(Y€%€€€Y޷€'bR€kY€)€€€€V€R€€,n9,€€€€€€l"€f €€€^"fЫR,ʃ€€€^€ G€€€€SC#€Q€ €ğ€€ө&€€€؊€ۋ€ăsf€€€€v€R8€€€€m'Ížoz€W€€€B`H;.Zy€€2€€€QÏ·<€V€€{C4oD€oX€€^€€€€m€€N€l4l€€L€€€€O/€€w€€€€z%€€]€€€€€€€㛩G}w€]€_ؾ#€€u>€€︶€€€€€U€€€LS_€€€€,€v€€€€€)*Þ€€Ԙ€€€8€€JGW0€€€€€ɉ€P$€jё€€€t€€x€€5Ŗ€€€ƒW€
€%'_?€%'€B€€&€|€€€€€n€€€?\€͛CA€€$~/?zA€€€€!R€b2|€€2€~€m}€€fu6A€y(BÖ‡8€€€U€w€=Jݺ€€€€Q ]€€€`=7@€€€Nz€mz#€€€€<€€#€\ߵ€€*€-€ €€3/€!€ɳwÚ‰~K€€cs€B€O€P;€€€€ȡ€€€€Λ€€b€L€X€H€€€€€€€E€o€€€M€€[L#€€€2d€w{Y€eÜӌ€€K€€|N`X^q€€€€€€€0:€(w€€Q€c€€|€c€'€€€vr€€ގ€€;€€Sm*€€€7€€g}€€€€1O O€2€€Úzc7€c€€€€7(€€€1€€€d.r€y5€X%€]€€(€€€P}€€€r€: G€€€€@€Rˤ€€
ҧ€
€M€€q/€i#€K€€€N€T€i€&€S€€€€V€DM @#€€<€€€€€B€€€€€€e€€9P€€$h€€U€€"€b:;K€&€j€|€J€Kì<€Z€qS-€€€€€€€€V€€x€€N<€€[€€€Ф€€Q4€^€€€€€~€8vҒ€€{0€€€€FQ€€9c:€€€H"€€ #2i.€€€]F3€€€i€>€v€t€ff-:_€Zݑo
_€ly€€€€s8i€€6](€€€RZ€€+€y€˘@€€=|€wS€€€8€€ߴ€%€€y͸€€F€€8 €jCs1S€€€€GĤ|%_€€€€€ÆBg€€€€g€s€6^€€;€€€b\1[('€€u€€641€€O€Ҷ j€€g db€Iì¸%€G€W2€L€€{Λ-_֧€b:Ԇ€€€€€T€€G€€€O€€ne€^€€aô€co€€oy€3€4.€g#€€; +€€€€€"€W€'kW44UuF's€€€~:€J3€€€c#€WL|€€vml4€€)qKက€€J\
€9€ b€o€€|€€€€NS€ޯR€€h€T<MX€)u€V€6€w_€€€Kt€€~!R1㊻€€€€€㰌€%t€€€€;l€€€[€€€ؒ€€F€€€€w€R^'{æ œe߄€A€=g€/€e"€€#Z€€Tf€P€c;JW€€€€€6ı,€€\N€XJ#p)€€!꼩5€€€c€
€})CW €O~€€€e|€€€B€€Xd7€€€d€q€€€E€9Hs€€€t€bYN6o€=&€€€޻€ݘc ~€€€€€€.0€€€n8M€ޣ€€y€€€$€€B]€cY€a€h€€Wz,€€/€€=€€`A?€A€L3€އ€V€s€9t€€t^€€€€
`5'€€€€4€€)€Vt€€~€€ʖQ]€r/€€€€€€€€€6€7€W-€'€€€€€€€yn€9€€zJ3g€?€€6€hb[a'<€€€€D1z€€€Y€7€Mf€@M€K"€
€?€€€€€njC8l€,€€h&€€€€1Ӷ€€€yS€x€€K€€1€€E€€€€ohT;€€.b€€€€y€i€2&€€€€€3uׅ>€€G}q€vE€n'€€€yn€
€€#
4W€€€€9€\€€€)u€R€€€YE€€!.€ €q€€€'€i€€2€€€€€d\*w€s%€Y€€<€€sL€€€*€Fȓ.€}€PMs€€€!h€ipӆ€Ċm[€0€;€€€0]I€€€€]0€|€2€HMX€€
€€@€€n€€€€€€)€&n€€(g€q€a€?€IO€t€€€
€€€t€=€€|€]€€f^YLwSEj€€€€€€v€p€]xY1€€*\{Mn€€\€€€€€€€y1U€A?XW€y€IOQM€DX€-€€€€€
€.t€€€€€€€€€U€€[€€C€€€€\zFrvxрIw .€>P1€€€€P$€€€€€€EN€€€M€€€JN€€ٮĔbX€€€€z€€]RN_€€€€€€€€€N€€E#€€€€€+K€"€€€56A=€€Z`€€€€€€6€~ו#€,€fh€uAT,lO€^64D€#€€G&:€x€n€Lh€d€D`TQ`@GH€€mU€€'€p€€€€+ޯ€€€T€^€€€
€€w"€gPN4_c0€颧O€ +i€€7€4€€€.€A֖€€(€€{€} +€W€€€€€e€ᚻ€wsÕ€
€€€€݉XВ€]w€€QAg€€|/ P€x€€€€€€7€€b€)€^ji€&€€€Rn5"=EG€jYÑ7yt|s@€€4€j€sg€~o`€€€€@Q€
Iz€ €€€€3 €€€€&€€Y€ۜ€a~€v€` +s€€W€€€+€"ى€€TK€€VC€l€€l€€€€Ȓ€cL]n€{€9€tf€€&€€€€<€€€€ci€€€ +#€$€€u€€f €~€€l€€€€€1€uL€€€€€b€$€€€€€wۥW1D€€<)€Ԥ3€€€€€mNf€€Vs(€J€n€\ +€€y{€]€4IA€€zy€€€€1€€W€&R€€€L€€O€ln=€N,€`€b€,k}ɕ€"€€€q]N€€E;O€€.)=Tٜ€oj€ۋb +co€€!,€€a€o€s€Q€€V€€C€.€€€€szc€€€N\€€)€g€e€€M2T€€Pdh€€D€€€&1€€vZ€!€ό̄€6L€€€€€€€]*€€†€€€&€€€4}€t€}€€€e€W#!€€€€€€b̟^€€€€?€€€?€9€x~5E€嘜€€pUt€€€_€wP€0€
€F€€€&_å€p€€€W-€€€l€€€q€€%€€f€€G€€3€€d€Vׇ€V€€%€ֻA€8€€€€ 6x€A{€€*€bb€W.ľ€M~€h¡]€€o#hD]8o€C€R€€€IÖN€€€+€€c€€ȶ9€pk€4q€ €€ee€O€€\€€Z8I€Cߦx76Vx74z€_€0€€€X€3$€f€8€€r€€!€F€x6€€F8€€r'€€€
;Ђ ;€€"t€€>q €€MZ€<€E€T€€€€Y3€€€7€€€€IR€€€Y€^)€epcMXF€€€€€€€?̴€€€€€€€€X€7Z€€€€i㴿€€}€€€XMu€x=€€€€€^€€f€€€}€O€€€€€T:€€sQ€€ZO€_%€€€1D€xDEI€v€€h!.F[€Ԥ€j€€€€2€uaY~g€)_€€€O]9&ɖ€^ڹ€€ +Ԍ€€1}F€€€t"€i€-€Hކlٞ€€€ €€€.€>€€ZO$€€€€E€€€ی€€a€€€€€€a€€\€€€€€
S€\5€룪€r€€ €€€nY€79€€Xn€u€€+Ø€C€],tm€€,€_€€€vAOd€€Nڦ€u)d€€€€)&€D€€a€$€&€K€€xS1€{€2€€6€€€€ԊYk€9͚€€€-€fpj9€U€€€€K€%€€#€T⮘u€t€q€`/a?cb2€n€l€€€{06€€F:€€;€a€5€€5€€Z€€€€€~€b€H€g_€€bW€}I€€€€4u&€;TW#€€^j€R€>€€€xY€>€€:€ԩ;€€/€€pI€&_n€NLc€f€Ԇ€€V€€.[@€R€"yD:€€€€P€€€€(€޲?€]€7€T+€€€p9ꦀ%x%€ €€]€€7€€€e€H|€ؤH€€@€€€;{€P€\q€€b*€€<€€€Y.}€€€i€€€\€kS'€€Ɩ€€€€rTvy$€€€K1€€*€€x€q€+€€€'€!o€€€€s€€€€€€€€qdI€€L€wܨj€tM€9€&€o'vY€€€€€ez€,€[€€|/€3€u]KY€?^p/j\ hG€€cK€€€€H€€€€€€fF€€yQ€v€X€Rg€€S€VW€ €€€`:Þ\Z€€€U€€€€6a6€€jM)=a3SWV1"€R3€M€€^z€z€<€$€/€6€€W€L€Y€€6f€€{€€,€€€P57€€n€€@€N€€€€E€Q€€s€l€€€€)€€O2eN€€ +/7€€ €:€€`;€€B7jp€€€v7€€€7€€€€ <M€lT€=€}h€€S€€'€€€7_€K€Q€€\K€T€x7€Z€€a€€€~D&€V€€€g\k€`€€€a€€€w€€B€€\€€€
Ϭ€€€€v€U€tN|€€€B/€QNKi€€i€€%€e€€€€$/=a€€C€€,€{€€1€v€€€bl€b_€€€€€1Mrͅ€o€€;57]€]€€$€€€€Լ€ +€mQ€€€٩U€€€5€G`U€€ +€€X€€€膹€
i€u΀H>€€W€I/{€€ €\€€V(_€~€€€nNG5fĢ€€4€Bx5Ǽ0Ay;]€KxF5€€€k€€€€€R€€€€"€€€€€{€'€<€Q€€€X€a€€€e€ٰ_€€Xł€]€_€hnV܃€+n€€€€€:]j€€€€q€€k€€€}m~h€€€_<€€€€d_€€.YNny€€€@w€€6x7l€۴
H€€€q{BU€€ͲJÊ©V€d€€m€!d$s€€?€€&€^€\€Þí§±"/N€Ym€{7€€'y€€";Ú° ]d^kQ-€ €Z€€€€€€ۡ?€1s€€N€_€lÙ¹y€IlZn€€XUc€€€
€U€\€€€&€oOa€Zw€€V€m€€@€>€€E€㾺e€€^I€t€J€€S
€€€€€'€€
NE€€€f<€€eT€P€U€k€Y€ʹ€€€€€WQt€€6R€kڮ€m€'ß¡2€wPV€€b€€€>bsظ€€h€?K0€N€€€ +vj%r€טK€NJ€Y€y€7/€tU€€€O€C€ ))€€n€E€€[€€€€€2L€€€€€<€€CY€€ț€€€€S(F€€b€€R€:€€Dn€€|€ӿ€H]U%z€3h߯€€xi€x€€ؕ€q€iÒž&C&€€(}Ƀ3€€;€$B>w6ß‚`€€/€i+€€€0€€€N€L€€€€{Zcz€O".€'€gΨ€s€€€€X€ +€3€€€N€€ھ€:€}#€€S̟€€G€p€€€>0€y€€7X€Ì€ +Ð¥C€€܊€.f€€Ҋ€€p€€+€DAƃ1Z;€H€Z4€!€3€€ut€€€b€_€?€E[€.X€tÀ؀€u€€6Iu
€€€W.X(l€€yv€az€€ݥB€€€r~[€o€€€€€6€€ܟa€m€€n~€€o€€7l€€d €m€€€7:CJ€[€€^~€€€€€m€f€€€€€€F%€€<€€€l=€7€€€ß€V€o€€€€€€€€7€m3€5€€€€79:€€€€€€4EX€FS€€€€T€t€€€€€€€€o&€W€Ͻ€of€€€€€€€8\B)€€>€€€€€Q€€*>€€€€€€y€€+Zp€B{{'€(€€€Z֚Ҋ€€€€֩€€Z€€Ӗ€€+€€Ք.X€€ZS€`>€€`/€€€
cpweave.SYMMM€/96€€€€€MPSTMPS €N€€€€*H€!€ `€€€€ €€ke~&€€r€3€€€€€€€,3€)_€.€€VN€9€.€€tKm€u\€\־€€lYYy€€€'€€€N€/€€¶€|€€€€€"€€€ 9ȶ€€€€p€€€f[_x€
€\xflyl€Ͷ€͢€uu}g€u€6/֤s€€e€<€€<€€S}3€B€€[€€€Ç€nUi€€r€{L€DPT]vS€€€€4€A€€S€37€€lm\۪B€€€€ů"D
}Ǣ€wU€u€t€€4€€€€!Q€€€oE\€C€`€€€]€Z€,€+겪€€Q€z€M€m€€-8,€ +6,€\z€p S€€f€)SC*€€€T€ +€€€Q€YY€€€€€€€gQe€7
b€Ŷm€b€€O€€€€€S€€€f€vd€€R€\9€€ޚ€€平v€,S€€o€ό€q€sU€€.€è€€9+€€:.A€€€€€^€_\€4€€€€P€€^q +€:€€€€
u<€:^z"€€cy€ +€1u舘€€€€㜧϶T€€€_€€K€"_€n€€5€€~€€€u€݌€-€€ +€€€€6s+€OO€€ €=xW9WGo€[€7j€€u€€€€€{€€€€€€€€g€€n€€]€~{€€O€€;€€€€€€€֧€€9€€"€;€~€€€€€€V€€€€1€€€€E€€€€W€€I€€B€{€€NP€NxY€U€
€€q€€v€€€€€w€o€]~€€w€j€mV€€€!b8.[~€]!€€€€€_~[€€;€ €€\€~€V€€€€)I€€C€€߷€€€T€;O€€€€^aR€€€u€[€€~€€ߛ€€€€€€€€€¬€€€€o€7럒߆A€m€W~€թ߻€w|€€}9z€B€+€€N€G_€[€(v€€>au€€€3€€€€€€€€,GaѶ€€/€€ݞ€}€€?€€€€[€€€€U€JE€-P€}a€€€Q€W€€€€€b€P삊€E€v€W̃€m€€za€ €€€
$€3€€€€€€€€€€€€€(€b€€€'˺€xҕ€€€€€8€!$€>€g?€€€€€€€€€€V€Ԇ€€€K+€>kCyWcKM€g$€€€€€ €€(€Jo€ь €~€€€€€€€€€g€~F胟€€€€|Q€w€e€€€€څ€€€೅鞸€€%€O6€€€ӬV Ý€€amksO€€€€€g1€€ҀqÈ Æ£Â€Â€Â€Â€Â€b7€ץ€€w€€+€€E€"€€M€!€";Ä´d0€€ˈ€/N€€€A€,€0€=P€€p€]˪€€^D€SÚ½h€€€_c€€pq|G€€IM빦€€€#€€
€€S{€G€)X,m€€V€i(o€€6€q\V€€€€2nI[c€W€€€(€€yѺ€€ڮ€€֎Fg€.€'€6€MqC€kEV€H€€€€3€€€(€;€€p€€ JD€T씯€€€€€3€€€]€€:€€m€€€c€"
L€ԕRX 2Pú€*€%€ €Kq€R€³€C€siqb€€v(€mq.€€€€ֲ€,U€€\@j€€Fk{Å«BV€€W€€s6€k€€€M€€€L6O2Y€Lyn€[€yÒœw€O€€"€€€€€€^€Dڔ€,€O6€€€D€h.€2€€!5€Z€4s+0׫€WU€€€€ౡ€€|€w +.z€€€e€€€€€\€€€A'a6Â€Ì Ø‚Â€G€€jjW€€€€€€€€)€€U%ʪ€€u€€)U€Ѧ%€u€€€9a€U€€3€€€€(€€€u€wb€K€Y€0_U€fR€7[Z€€€ €r`>€S€€€s€€€€€€V€t€€t€R€TU€078€€€€€F;€€€€€6€0€€€R€
֪€W€€!k€€%€€Z€(€(U֪`Pi@ԓį€€SA€hF€r33
€€€€€F€t4€€€€€€bp€2€€^E/},>|€€Ff€K€]~YeA€v€€g[€€8€€P€(€(z€€€B€NQ#€€W€€\n€€ǜb€€€r€€€€€€QyJþ0€x€j:wҬ.ai€2u€€3€€ӻ€u€€€FqX€€rϟ€b ƀ€€-}–扻"€€€d€y€€€q€€€€€v}€f׳€gKCVKukGWsc%€€ߢj;6€€€€€€€Y3€€€€a€€€€€€ߩ€*€€~M€,€t€<€?(s€€,€€€€€+€€€€€Ns€'_&€€€"€m[€€*_€*r€€(€C€€v€o€Vd5€2€G€m:€€N]q€€T#€€D€€O(€g{€E€m€]`q€+
€7U\€%€€€K2~&€+€biY^a€y€€.my€w€|€€`€€f@€$€κ[€V\€E(€i€€8€€u€€€€€m€ȖHY€o€€H€V€€€€€Ou€€€Y€€IGk€€€€(€X€I€D€D€€y€€€€mK€€FY€€E€€;R\€€R"€c€Y€p€€>€]€ѨX€€€2€!€]€F€!"n4‚€hD,"bG#€€€€F$ "A€€€€€Ð€gW€€€€€LQ€3X\€€€€€€€€mQ€€.X&R€€€€€€%Klq,€€vUe9ÔšU€€P€A-€€€€€?]€€€UmV€€€€€€€€€Q€€€_T{€€_`F)\€€+€€ +J€€;F€€el,K€€R€.€€M*€€F€-€b€z¦lyEY€€€€€€€6€Ʋ7+~€8Ó€՘€€€€€€Y(Τ€€€€]€€#€€D*Wh$€€€€€€€/€€7=€J€€~€~€€>Wt€€€E/]€€€>€19?€Ir\2(€€
€o)K€€.9€8Ùª]€ֶ€X€€€ƅ€€€€€€€€j€€-n_/€€€V€B€{€4€€[€€€ӱߥ€€€k€7v€w_€[€;|:€5Y€€€}€)D/&€$k€~€€€€€v€ɶ€€G€€€|€p€n5^Va€X€+@€:€€€€-€€;>˳@€<m€€€€€;€€€4O€€~a€dž€E€DD,€`bq%€€8T€€€€;FX€€€€Ox3€€€Í€€€?(€o€€|€ۄ€€e€w=2?a[€€€€J€r$€y0€> €o€Sł€€€z€€l€€€brs.€߼&5i€€€^'€Xu€-€:€7l€R€€Z€€€t€€€€YQ€NJ/C€€€.€v€€r€M€e€€€€>O€e7A€O€€&%Y+€€ +€€€€€€i€IS€v€t€C€Ü€€Ø€€€E€€€3€€€€€$)v `sm€€/€,€aΣ€€€%IZ€€rd€f€€fH4XR€Tl_P$€I6*€€€€€,€{K€F€€ ٚ€€€l€€€€€s€ €>€€G,;€€€€€O~€M€€::€€U€4€U:€€€y€O€€1€>Z€sVM`Gc€c€€+,€vÏŸV€€€€€€Qi€€€€7v€€o€i€€*€€€€֖€`€!€s€€€€A( A€€ €€yx€€Jn€b€Np€ʛ€€u€M€{€,€€AJÉ%€€:€€€€Xsj€€€ €€€
"€€+.€€€_A-֊€€ +€~ű++€€€€€€€€<t~€ݵ€!€n€g€€€c€€
};PXh€]€€JIȱ€€W*>I€€€Ify(€ݥ€{€€€€u€~€€€]€€+€\€€а€€y9€€€aOK€€€€,€[5€€ݵ`€€P€!l€€€Dƹ +€'€>€€*€€~B€€€€0€4€€€\€€}€€i€€>€|]e€€<]WI€4€€t€€€€e€€€*u€rS€BUx€*3IOp€€€€€€E€€"-€Uܯ[€xL€€K€v+€`e€€@o€€!Փ€€€€7€€u€Tk€€€e+€i€€ +€€€€€€`q|€€'s€>€q€|o€€%€bm>€€up€P€€)€€€€snq'^vÂ€Â€Ø g>€ѳ>]N€€€s€r€€€€€€€€€d€O7€~€P€€€F€€€X€€€+v€n€€,€€€€,€C{4€€€€€5€hY€€?<y5
€#€qC&€o^.rY€);?UWYW€€սQ€P€.-€̹€€€€€z€€€Zߺ€Θ€€pc€"~/€€9mB€(€€d€€#C€€€€J€{y:tNƒ€€€€€ _L6€W€€€x€MK}€z€|_€€€^€€-
յ€€[ € ,0Ѣ€€FLKs€9>Q@€€*€€€f€-€ƥ€.w€€ku€e€€€€I€€€€€!€p3D€V/€€€t
W€.TǨB˩轶€5€€J€|€€€€s€€1*€€€€S€€o€lx:€€q€€1€€=)€€€f€D€€wtuU€€`^
c€€€*€€j€€%Ŏ€€f€€€̮?€€i€€:h€€€€€d€<7€€€€CC/€@5f€'r€€€'9,Tǟ€+z€€5)€Mk€\€€€w€&|€€wiQqx-\€w€€^x€€€\€s€8K€Y€€€Q≻€€@€P€€€9_€€€€€k +D€ί€€€~€J€SҚ€d€W;>€€J€€€€X€yb_N€€LÂ€Ý \€xv€'x€€€€€J€€€1€Io€ZcA&€-%€;€
pW"€2ڡ~€€e|~s€€ +€=€_8€Ө€€€֒€L€€€€€€€€tL5€€€€Ew{3€€€€y€qz€W{}X€€€{n€`Ll0€€*€€€€b€ +€€K+€j€K€j€)J€]!€p€,gl€€2€€€*he€€€ AQ€€˪€€5L€#s€€B3€€32}€&w:€1S5€`€(€ €€€€Nc1T€d€DOHg€~OE€J€€ڵT€ݵ€€€€Z5\€€dyyIi9€€€T€€o*€€Ѐin€€ERCol€€€z€€gz€r€€KVVb€€${€€Y€)€2@€€q€8€€€ڃ€\€H€€c-9€€xs€(€€€€€€y*€€P.g€O€€sj&w€ȩ€pW~k€P€%+€k.L€g[€7/€€€~€€€€ࡅ€9pq(
ٙWX€€"€m€€€€€!€€ڼ€!€€B]€€o€€gһ'+˞uɂ€€€€€q€T€€€€t€{€€€ +}€o)€`€ݗT€f€)
€€€]^c€€G<€[ +€€z€€d€€i€^
€-[N_€:€ +v$€W|j€|LN€]Uy€CB€ €L€QÇ€€€€m;€'€€€€€Q€}%€€̘€f}"€#€€€|€€$€!€€O€€€€€(€€W€r}€}€€HR2bEln~€'f€Bެ€!€І€€ t2€-€Cx€J€q€€€ <€€€€p^€,eU€€2€€}€,fL€S%€€€€€9€€p€€€€(G€Fz€€tU€k)g€I_ۄ*€€\€}(\€€p€ +€ +€-qq€y€!€€>€c€€€€€€€m
I€-€€€`€€.€€S€=€I~€#v€€€€sÔ¯/V€z_NW€€€€7m€O€€€>€1€€/R€€€5€t~€€O€€郎€€?€Wm6g€eU{€ +g€€2_€€;€€„[€€€€ͫ€:w€€€€€9€t:€€€€EÙO€€ 5€2€€€€s€€€93S€;€ڽ€ޞ€€€is7k€;Gv€€€€,0€зVU€€ +€€b*€98€UBeÛ§Xk€€€€€-e€y€#€€Ü€€v€€Jj€€€€€o9}€K€׊€€ίi€Uj€€€U€€Q€'€w€€€s>€€f€d,(#ߺ7€r€8€€P€܅N€cJ|€€,€€€€€%
€€€[€P€^tR_€€€€€€;[z€Z€€)€€64€€€d,€€€c€€€j€K€rw€owV€€€€€`€€/€ꕬÛ€€*.u€֊I€0?€Z~m€[H3svV€l€vq)€;€€€E€€%€s[€€:Wy€7;€Z€D€ne€€€w€€€€€€j€9€€r€€xw€sK<cyv€€]ˎ€€q€=}a€ +€€€'ٿ€(€<K€m€:G€€?€$Y]eNµÔ€վ(€U{€€€€€€Jk8ωZ€w€^L/('€€3?a€v€€€G€€€%€`€€â¡p€6€Q9(€€6€>׌€2Է€€€0wR€^€€€€ph€Z€€€€M^j€€€€€V€Q€OE€l€€]w€€>€{€G€€€/f€c +€€ї€[ߪ€|Iy4w~€€R€J€€€€'€vS€€Z€€E€Æ€€€sk)€€€x1]v€€˓Fh|€j€€€ڎ€€ !vEQ€B'W€@d€€€*_€i€€€2€€€G€€z€~€eU€€ӌO€{a€3€J€u€`€E€;Ef€€€-&€!y€€.6€5/€~-€}€€E€€€6€€p1k€€e}x€B€€€?Nzަ€IϢ€€€{€B€€€€€ F€$G€€€€p"3G€€,/:m`€0€€[%Z€7%€BwM€€;€€€€€M€{€€€2(6€3€[,ÞžP߲€€€H€€$F€€€<sd-€U€€€0㊽€€4$€€/€5€<4€k +€€€x€m6G€€€-€€€€€NI€%€MZk€€€€*€ €€€x€lQ €r€̗,U2;`€€€Y€€C€^P€k€rסÛ1€֫€€8€}o$€K2€€sÇŸ(fw€€€€ѷ€€€z€€˨N€€€;8op+€€€€€Pp:8ԃ€̶c*€5p€dFmN€€̫€VWVH€€€5€O€€ZW€€~€€\>€€\hRR-T€€€'€€€k)€gz€(€i€€€€*WU€€9€€€Tu€€€€€€d€€€RM9_€€Ƒ€R"€q]e€Й€T€€€€€€€]^€€€+Ui€^
€€8€L€U*G€y€€€@߫€€€u0€€k(€ab€€$L>€M€Ye€1:YO€€€€@€U€€€€{%€3€€?€J9€€Z€Nrl€€NA€€M€w˹÷€[€^|"xm€€€€ €€H€€€€€l8€€€o€€)Â€Â€Â€í²«XiS€€9Q'E€3>€€€d\x4Ó±y€€2€˼!~_€€K€&W€^:Ò°4€€€W€q€€>€€€Ա{€€€€o1U€N€8€.€€ń€/1Ä€€€z€€€€N€{"€€€J€ph€¾€€€@€€,€ȅ_s€UgЕ€F_€€Q],i€e€€T€n€~€€k€€U囇€M€:€0}€Qp€Q€€€€>€€€c€€v€H€I€<€€&€p
sr€J<€;E€€Zȿ€)E€q€€€b$>€b€`€€c€€申7€@i€h€=€€6€€€€&€-€m€e@€€ܹ€o€)€ÏR€C€#€€€€€€H€€€%€f<~K/€€:€U€3-}'€€€g€€€h€dž€h€:€-€€€ZL€€7g€€3€€oÝ Î‘Â€P€nY'8u€g=Ç€€#7€aV€X€&€[€€€P€€€vt1€€€A€€€W€€R€€€€€€€€€€.yќ€€/€€
JӲ€€€)€€€bg€{0/€3p€€€E€VW€bؒ€€€€€€€w€€€€H5Z€Eu€?€€€b€^€\0€˘€_€ՓF€})R=€€€X€ٹ€€ g?ّ9€>s€€€€<€]1
€€€'b8ܓ€€]€/{Z€€€€€'€€h€X€€*€€E€n~=€€喓€€€€€}€€€w€€d€€Y"€€€(€nxNj+׷€4ttu€€S€t"€of€€€ϒ$€Q€€€€€ €v€R€:I€€b1€€Z3wN\€ݓ€_€€F}€€€€ŕ€X]€€€€€€W\€€.€€€€€Q€€€J€€€f%€8€^UTT€€
€]a€Bj€€G€€€€€€€€€€^n1A€K€€D€D€€+F€J€]€€€€e€€-€k77\€€D{z€;Õʞ€G9Ec€€nWU +~€€n€K€€€35€8ΡÛ€i6€Թ€€€€€€€€*o-H€€AoF€€€?€€€,€+€oy€€€q€Q_Z&9€€€€!€€€@€ވ€€M+€€€€€€€€6€SuY^%€€M€SExÙ€€€i€!M €€ ]€t3€€€€€€€cáš»}]€€B\`!b€€I|w;€=€€B€鳓:€o€€zn€€N€,€epP€5߽€€*€.;i(.€€a€x!Z€€€€€€€€€€aÂ€Â€Â€Â€Í Â€Â€Ø±Õ>|€€€k€I€€€>€p<Ma€€k€ڰ€€€؉v€€gF€€BLÍœC€€/`€€>€2O€?A€uD€K€€€)#&€€€U€€_"}€O€€€5€o€€€€€n€ +€€€:}€€y€€T€'€€€€H€<€:€T€ҫq€~=€€€9€€€g?<€l%€€€6€€€€€€€€€€"WF€+AT€^€€€€-€S€Z€€r=@€€€$e€€€€2,Þ‘z€iCb€D€k€€€C\€#€=€€bW€D€O€Y€€<G€€€I
K€€€€€€€0€U€€€=pXz€€q€|€a€€R€T€/€H[€€}ع€i€V|€€j€w˨€)€1€
g€€e€zξ>€€€z€Z€_nD€K€u €H€zm{€N€>1€€€€3€€€€€}€<€€B€€W€I €9€€_ +€^€€€#1_zq€€€R€j€€aQ€_n|K€€€€V€W/€€€Z€€€€~€€€a€€_E€€(f€€O€€€€€€€€cb1€€L€€€"_€|€PÂ€ë ˜Â€Â€Â€Â€Â€Â€}€—U€€W€€€׫b>€€_€€u€€€
_p€*€€€€<OWsx€de€€€qLjx€€€€€`€4€u€\€€€€)€_ON€#U€€_N€*€z€€R5€u€ +>J.٠€€x€x€v€:€€€€€€>G€€€tPL€c€€"1̃c1€՘€H3b€€€€Ä€€H3€X=€M€s€d+Sc1€€€€€ĈY€a€€X€€€€٣ƌ€€7&s€9€€d€d€Y€98Y7+€€€Ϫb€€€€È)€€$€1€#1€€€ָ€Q,€g€1€"1yj€€bLb€h2€>Ób.€ĔO€a€1€€€€ɾ€|G€d=€E€g€$€€€€l$€€ʱ€a€,€'&c&9n€g&€Q9€€€€€€€€.€69€a +€n€€€€€/€€€kq€€€A€c€)€€o/€€HD€€€€U€Jn@4€€>€&ߡ€;€b€6Ô©u€€€; €6€€€€€€U€€€ ~€RLUq€€a<(€TM\€&€þ€€€T€L€[7€X€b€c]€"€F€€€€€€U€ꪈÔ3Q€€€J€€€€€€a'€€€rS€€€ E€]`€€p?€4OXh{W€U€€€€_€.T€€€€€H€O€۳€€[Ur>€€e€]€€?€€%?\€q#€€/€€€`oG€x €;€€€€€6.€€*€}€]€€€€€櫛G^€z€#/€ +€€€€€Y€€.uUE€€€^ٰ€XD%€$€€€€Éz€€]*€€€€#€e€)€2€]e€)V{€h€€€v€€-Z6€€€ +€€€*€B€IB€U€M€€d$€€~€€€f€€C€`30€€€€g^l€sF€€€€€€Z€€€€-H€&{€TT€3€H€€€€€ €€S€5€€€zZp€€€€€2[€D4€€€]€@€vX€%#_L€*€€d€€€%\E€I<i`z€6fi€B€3€צ€F,€€v=€€€€€^€:i1ꨇ€Qͧy€a9€€€}€i F€€]X€€м@€€€Bz€€€,R€
€€N4€%lf>€ﰧN€٦€€€€€Jw€€M€8YCo0€zW€€[€F€€€5<n€^€€€ɳ€ ~€7€)€€>ރ€"€€;Ȅ<€€€€F€€€r€€T€D€€k€):
€>Æ€€.€ +€ԟ€wFqK€€M€€m€€€/_€€Îl€€t;€ +€W€€€€*€ +€€A€€€€€ aS€5h€€5€&€€€"޳€c€€€
€€Hd€ €€z€€€€P€n€D€63r€€€€@€€tH€g/~€€\€€Ӱ@/壮tY#€€G3€Ù€€€€_Y€€~€€F;a<€€€Ü€xRÝ«~V€€T€N€€K$ІG€€9€€€€€ž€28€€E1€?€€d€€Ob€€z8TK.€€€€O€€€€€4A/Y€€1€€€<€~€g5 €€€^I=I̬H€€€Ws€.€€ߑu€€¹€€R€€€€X€€M=€Ɉ€€M}€€>5€€€ +€Q€\€i;cP€1€M€€W"€€€€l€€B€\€€ѱ€€b€€€€o€=꾯€W'sc€€€€t€p€9)o€x<€€€€:€:€F€€p€;€9€€ѱ€!;€}€3€Z€ԣ€€€u€ڷ€n€€€€+€€y€EeoÖ€;€M€Bu€€€€€VÚ½4t€}€€Y€wZ€Ȋ€€T€€l€€,'€ҋy€€ϥ|€-€H€€D€0"<€na€€S=€€7€m%€_€€q€D
^Ms€€€,€€\€€€K~k€:€SA9€€1€€4u€€€€€€€€€€€€€€-€&€YB€€€€f€€ +€X#€€€€€€CÝ\f€0c€b€
€€€I€Y€kS#€b3k€͢Sg1؈€X€$€€
e-ۓ€t€^<:?€ q€s:€€%7€€@c'€;/€€€Y€F€E՘b€€V€y€€}€€€S9O€€;+€€˱u€&€€€€
*€L\=j}ؚ€€ĺm€€€€€€€JC€e€€r€T€€€M€ÿ€€€€€€oA€ +\€~€€€€>€€<€e]€zF€€la€M3Â€ê¢ Â€h+€€(€!Cq€-Nj~€€a€€u€0I€€€€PM€[1€9ό€/€!X€N€€€_€A€
€Gg€€€cx€ܓ3€A€€€h €€Of@€€€D€€€€ߜ€{€3€€€€€€bxc€_€€€CV€ߞ€n€`€n€).f€€W€<€C€B€=€9Ǵ€P€Ͱ€€€€p€ͫ€t€€€€.€€ߩ€r€€ EEϊSD€r€R€€$ڄ.€DҮ€PE%6ڜ8€€€€h€u€€€#€€'1€F€]D€
MB⇇€Yo/€€Vi{€ +}F€€€Nу€y€€J€*€€€€€€€2$€c€€/€DŽ€€I€€€€UQVo€"€€;V{k€€N@€€€€€|r3€€|€=€N€c€€d€€€€O€€€x€€€o€d>€`7€o'€UL€c?€d€/#ߌ€|k€€€&€}€€€[4€o€=<€€€ߓ€F€OL€€[€|€P€€€u€d6€&€€WW€d6€C€h€€€€€€p +€€€€m]Ú¬lP7U€€m€A€€€3€;ނ€€€€-€€.|€€€<€€€€€€€€€^€€x€€s05¾+s€9€€€}€€)€€€€€$€€€€F€º€J€R€€€:ϓ€€$€MP€€€€€€e08y€€€J€5ߊ€|'€Vʉ\€€P€€T€€€~€€€*€M3 €€€:€KuÜ©;€€v€|€€€€q{Â€Ò Â€,€p€€6€N€€€€€€€nl€c/€1X€€€/€€€€k/€7kz)nL€?€€v€€[lQOrV$[dD€€|Y€€€€€€<€uS€€_€t€P€ƶ€€€p€*€ t€m€€W€€€€€€-€=\€€U€D€€€€#€€Neűؓ€(€€7€F€€€HDF;w€€€(€9€b{€€€r€€G€f9€&€Ȥ<€w€€€€€.€ +€m€€€€€€€€E€€€ml€wm€ €€€8€€g€€€€\€€.q€|€€`m€8€€€€l3"€€!!€€€€€4TÒ’U€€€4€n€€€€€Ƌ€0C€€€ls€€€€€(Q€|ȣ€(€[€€A€€`H€QWo€€t€k^uW€f}v^€€€€e€^€w€H€f&€€/€Ѿ€\€!€Q€u€€]€c€7€€€€R€~€€v[€€#€€€G7{ih€{€€€€Hk€D€4€Z€€_ ù€xCk€U€ڋ{€F;€€€€'€~€€€^€f€€]ϧT€!>€!€%*pl&T€ €W€€O€€Y€€"€€u€P€Y€€Ml€€^O>C€€$l€O€m€€ٱ€Ì€€€
€€D€€€€Ȗ€դ|k€6€}€>€€€)€€e€€€=€€€w€3€€€€@.>€€5
I€f€€a€€7PM€5j#؎UB€'G* €gS+€φ€€!|a€€€€€dsܓ€|€€1€!5^€h€€€o€€€€€*{Җ4€€&€?€€/E€P€F€\€€€<u'b"€€n€€ M€€€€g€€G€-€€€
+% +€*€s€w€€€€ÑV€(€`€€T€<|[P€ Ý€i€€€n€€€€\€8€€.F€qf-€€€XK€Ì€ +€€€€€€€€cn€€€V€€E€€€€€€€€€,€€€€"€€)̧ +€9€€|€o€€6€i@?P/i€]€/8$€€Y€<€€€€€€€€€€€€€€€€XKz€7€€€J,€)€@€€€€ھ#€?h€\3€N€>$€€%Bw€/X€:€€2€€€v€€€åŒÂ€Â€ +€1€r€[O€M€{9:€€€€€€?€w&€€|€€€€€_V€€̻n*€€j€j{D€ic€€€|€9€€€€A.`€f0ˤ€]€+x€yFHGÂTB€m€€€€|8€G= Òº<O€€€€€€€€€€kx€2lЀTX€b=€u€W€€€=€€€eG€,€KWd€>6€€€dW€€€€€jԣ€mj+€€€f€€€€€€€€€€f€G€O€3€€€{€€€NZ€DŽ€X7€€h€€€€6p€€vzs€€׬€S€€€€y۰€5rA#?€€6€€€€]
o!€€ÔÍ [€v€€_b€€€1€€1€Km€€ ma€[Fë€/€^6€€Bz€€€€N€€Hu€j
€+€€€=U?€FՊ€f€3€€M€€€E€"€€-zH€OQ-W"€vX<€€S€€€p€€€{€€€_v€€_t€8ˣo€m€€u€€€€€~€€N€€€V€c€X%€^€€V€s€€€N€€€C€JTU€€Z)4Gf€€=€€Z&€€€)€€€€€€E|#P€w€€+€ +€€x€€€€6
iu€1.i €JK +q9€€€€j€f€[€n€€G€bs~
€_€[N€€n# ~€#0Ziq0s€
8€€€€€q€€bO€€€m€€€#o€€€€€ +p€xD<)^€tq€]€ή€ֵ€€€€t€€€€=€€=€{Eoҧ€€€€€8F˯€V€)€€€€€€€€€€€€C€a€z€€0€b€€€€a€€€ˆa€͘e€o,5V€€~#m]€;y€o#€P€€*€R_€~€€€9B€€QIFx€Ýx€€€,G€6%5€5€I'€€€€€C?€€.q7GHo€€€GH7€€`€€ѺH€€#€€HF€€€€€f9€€#€€/Q€€(V#hg€Ð€]/€€|€€a€€2€п€€D"xcÞx€1€€€K€€€€C?z6qG€=2€9€G€€j€€]€C?R7€r€Z€ €"h?€Ð€ncQMy€U#€€0-€€cz€ €j{R€}€€€€€€€€€⃅€€9BuurÄ“a€#€€€€;8€"q;G€]€€€€Ð€€ܓm!€v2€€€€€€€}€€_NF€湃"€h?Ȼ€€€FEq_€€F€€€׋#€€€€€e}Pݎ€€€€€F€€;#€A€€€`€€Av€;]€2tP€ۊ€€€]€€€€€€`€I€€€wN€6€€€€y€m€€€€€.=>€€*j[ѥœb€8:7AS€Ҕ}€€€\`€T€€€T€€ɗ€€ +S€€7-"€S€B€€]n€]€€€bh€Ct€V€,t€€€C€K€€€€2€B€5€E€€|€E€€€€wަ€s€€4$€;€€Ğp€€€€ €S*
€€€€D€G€€-t9€ӟ€?€~€!:€€€€&:6€%€€€€€€~2Ҥ€4{i€V€€cM,€€"€€€֔€€{€€8€€€*€€&l€)€B€€
€M€`€e€Ȟb€€€Whͮ€€€/€wal€€€E€€b€v?€€l€\€2 o€€€w>w€|(€_`€€&U;€€E9€J€€€1€%€€[€€~€€€€Vt€€Bs?oS€n@€€€€€w€QKd€€Yv€q€€€u€€v4€솆6\a€€€M€€kZz€-€~€v€S Ò•kp릶9€>Í‘YĻ€€€€VWaq€C€hc€€.8€q€f€€€Ƈ€5%€^3mC€€ѣ€~L€€Ép€U€{&€zus€5€€]q€6G€€?_€i€{€€€€€€Dڱ€fiE€"€G€€€€"Yݎ€
€€{
|€€._L€S€€€nD€€ l€€Y€a€s€€+Y€=€€@`O €€ϱ€€€€€ܕ€€ɳ€€П€€z€€/€/'gNUY€€#9€ڲ€M€€€2ǣY&-v!P€}U€€€€u)€r€a€2Л€€€€7b!.tJ'€#€€€€€Ӧ€€€€€€€€€?€€b€€]€€of€€]€_€€€K%€€_€€>"s}sQ€€T€€QDp€€XM€€€'1€7/€Ҽ1€Tw٥IǦ €
€€?€€ €(ru€k;~€€€"€€q€8€€€&9€€€I€c€?€€€-€€o€€€€6€€""-€8jF€€8€€€3€.€€}C?€€€€,€~€js€€ÐY/€y€€vy€€'€Aj>_€Tֲ€3€€€€M"€h€n €lAU)€€?€I€$`u€(o1*9€9€Mv€?{`wKY€F€€f€€RL@x'€LU€e#_€€<!€€€€€€=€€€€€€€E€o€€G*to€€€€4€€<€€e€€€€6€€/U€o{B€h{€€€€ €>€̳G€z€€8€5€ z€n€€€!€€€Zb€$€€€o€€t€Ōs5€l€4€€€ऩ€'€ <€€^$€׫N€€g€€€G +t€d€̖€€€€€r€€€%€€€m€€€X?Q€c€U5Q%€F€h€€zD€€€€H€€€€€€JQY€ +€€€€h€€€€৵c€€€0Æ€€kU€F€V€€€s.€$€F€p€€DX€€Ax€€€€ÖM!€€€%€€€€޽€[&€"€€:€2€€€3|€€>€u€€s€€e@C€X€€0€€j@€P;€Y€Kx€€l€€c€€dӻ€€Y€7€q€;U€M€F€~Z€€d€#LAU[€mc€8€€€緙"R€€ȸ&€€€€€€€€c#€€€€€€@trh€€e#€€H€}}(b€€5€AI€/m€/jDRŸ€€݉€€t1€oy€€Z€f€i fJ€€av€b€€ƚf€?€,€€€€€€€€€€€~/€€yW{O€€€€€€|v€€€g€€€Č8orFĶ€€€>>#6€u6m€€€ܴ€6€'€ ?Z€XUQ€€€[ƪJr€€€€r€I6OD€AԌ€€€8€y€ə!î™a +€B€o€M€€€€€L€€4"U€;&y€]C*€€€2€<€uD€€4€C€ZS€G€€€€€€wb&€{€€s€€ €€€€€*€€€€茩€8:€L€ yl€s€F€;HL"€€€€"9€€€€€€€€€@ovy€€M'!€G敤€€€€B€€}׿€\€€€€s€#Hf€€s€7€ݹ
€€]€€€:€\v€€x€€at.€€€;€€0r'€>8€7m€€;<[H€)fg$&Mí»N0Cs'€/Q€ +€"€i]€@WL€t€€€€X€€kl€€I€J̄€b€m%€]m€#€#€Md€Æ1€i€€€€€Iu`€I€€€mK€€&^€pv€€€[c>€ϗ€v&€€D}€9cZ€щv€5儷€€h€€u€7€€€€kxaN€€€p€r€€0€W€€Ĺ€€m$€0€€€?€b€G€8€b€s4w€;€€€ €4M€m€€€]b€ã™#€ȫ€xR&: 7@€w€€€€€Nv€€€V€wÕŠInΈ€z|v€€€€€€y€€$€#€€€co€SQe€€{€'€Lݻ€€?€湯€&€)U€O€O€9C€€̜€€KycKdn€€KXÓŒâŒÂ€"€"€€€€€v?G9s$€€L€{€€€E€€xt.€
€jG€c€€€€€€y€+FT€Ū€€?€€2h€ֲ4€€€տ€l€€Ğo̵€€€€€€YD€0€€J^|{€€€wc€8€€k€8B€]mzex€€€€€"@C€€v=€€€V€{€q€\€€7€ժ€1€€7k€€UM€d]ã³a|€yO€€€€nHhgF:€€ +w'::}€ +!€€
弇€€€€€€@€€€€€'€' T€u€S€X€€JXu€€D€22ei€Y߄€€w€€€€M€Mb€€D€€€6€€<h€t€;Fg€B€€g
€qYym€Q€5€uD5'€€u€€jΛxT<y€€1<'€Hx€C€uLE€Y€€ €q€€u|G€@€wDK€t€-€td€€€€€8€nos€€€€O€€p}€€€€j-€2€€€tt€»]0€+Z€(€Z€(€€€ +€€3N*€€
€€I€v@€Kg€3"€€€€'€)€KǦ€€€B>€S 0€€€€]CjO€€0$|€€€€8C€€{7~€€€€z€}€ä¤j€€€eLܸ€€€€Y^€vW€€€A€S€gP€G€v +ßšpJ€€/€;€€€€€{€QFf_€)#€€€€_€}["€€v€€f€€c€€€€€€M|a\Nc.€eB€€€K€o€RQ€€(€.€€Oj~@dyT€:mBkL€€#€€q~€c€k€ˣ>€€&T6€€xۛ€<€Iω€€€€€€&€€€€#€ń€€€€€]}€€€rƄ€'€]€|€€i|0€€n€)€€€n€~€€@h€€€€s€x;€kh€€G€€X€_€€H€€i,€€€€H€;€%€"5ç’²]€5,<€€O€€€=}Þ»=]€€€€y€€€p€A€7€ y€)€=€€ԙ€o€xm€€€€-€€p€\€1{€€€€€€€#Uï‹Â€R€€€€Ѿ€w}(t€q€€€ipl€f€€<€u€f€<€l€u€€O€€(€€t€€(€S?€w#€€F€F뇗€€€A€€c€G€€€€€4€€€O€€#€€€€€9€
@W)}q€k€€€Ղk€z +€]-€Q€€€.€€€€z։€€€€€€V|€I>Ä”Y€€i€€I€€€€-€€€€(€€i€t€U€)€€€W€€z€ €T9]€€&€T9]€|Ñ„?g€ĴGw €€€€€j€7€:€2€+O€€€€U€€€Õy€3;qqT_€€€6€€T €€€€€€z\o€u€K'€€wgX€€€€€€€kO€€g€€`€€€€4Ê›d'u €€€n€q€i€€sNq0A€SHÅŒw€€6Aӕ€€6€€€€€€€9€0A€€€Z€€;€€h€€€€~€uv€i€/€_€1€€@€N€€
€€€€€€€?w֎;€LPu?@€€ e=€€€Ѓ€€D/E€€€€f€€€€€R€€€€€€BT€€Q€€€[€€`FY€€€r~€י€€€€€e€s'g€s^€Q€€K€€o9>€T€€€Č€8€€€€€k€€€ €m>€€ƻg€;€sɻ€€΋€€ļa€S€€€€
Ò2>Y,p€€_€€9€>ۇ€[€^c2€!€%€€€€€k€€\€s€€Ή(n€€M€És€:W€€7Â€Â€Â€× \A€X€a€X€?c?€€€€.|€€$g՞€€un€Sd€€€V€/Õ€'€E?€€?€€€€zߘ€|€TN€€€.€€€€€д€€€u€Z9_':ka€€Ý'w€€€Vb€€€R€€㾕€E€#€€{€€^€i€vÙ»=€€€€€6K€5TmÙº €€€€€˾€'€]€+<<€̈́V26€HG€€7€Dz€€'{n€€€8€€ +€6y€€€Yh€€ƾ€€€]€7€[j€9€€@€€€€€€€:'€qк"€O€uW€€ €€€€€€}€€vŶHW€
R€€€€H€5€€€gG€b€€€€S€€€p€€€€€€€h€€€Q€€€A€x€€N€+€€€€ة6€€q€_€€€o€u€#€G€wJh€€*b€€€€€v€€i7€܇€I#?ܙڤq*€€|€€€|e€)|€M€^9€˞€T4€€€€€+€€€€o€6q€€€S{€€UQ{€€€€€€€€$€€€€€€S+p€_€0€KJTÂ€éª Â€Â€["]p€€€g€S9p€_€,€;€€€€€RN)€€€€^9Îs€{€€^€k(€€€€v€W€€€ w+e€@€€S€w€v +_€€~€€€:€*€w7€€V€€N o€€i€€€€€)€Z€€*€€€R€€€€c3€€€€SF€€€€€y€€€€I€€€€€€€€€€?꧑€vo€€H€i€€(€€IG€Å€€.€ї€€1€€€(€+€€{€€€€€€€[)N€塮€€X€€€P×µE€>€€€+r€€%€uG3€€>€€=€€a_ß›|€€ə€€€z€€€€z€€€n€S €}d€n?9O€€€€€G{f€9€:S€{z€€F€`€€€~€€t€€€€€€{}€ €}ė€ڀ€#€u€€€l4+€€€:+€€€€€€?€€N€á¢Â€ €€zs€5J3uÝ€v€
D€€o€:€€€?€^€€cӀ€%€€€€c€€€ƶ€€O8s€'€W€V€€$u€€$€€33€€€h€€€^'€€|€€q€€x€€/€€€]€€忣€€€pﮓJ€7\€€€€NT€{€€€€€€€€Sl€€€€*€€€€€c€U/1€€€€€€i€u€€yKE€€Ê€€€€'Úˆ2€;€?h€go€ٿ€p€€€€€€ +€€€€€S€?€€€U€[€N€€€oV€*O€V€^€€€€^€€€€q€€Z€zl3>Ñ‹a-€€€€€X€ʓ€€u26€€{€€Y€€€€g3'€€€Sx€€R€z€^€ӣ€?!r€"€€t€€Q&$!€E$j]{€Ǵ^€ €€€8€€€€ң€!€ F*€ Õ€€€€L€€€_w8€€€€{€€n€€ի€€€€€€€€}€@€€€A€€nS€€€>@x€€€a€€€€_xc€€ILC€€€€€s4€?€€€€*v€€€€IN€€€€qtj€€€|€€S€€€€)€€€SÂSL
€}€€€azt€-!2>5,8€€Ԁ€ +€€€U!€€€Ô€ECjđ€!5€€€gd'€65€rb€€o€ּ€€&€ € €€€€€€€€C€&€S-€{€/t€~ݔ€€K€€€€(Bw|OT€Ä€€€c€2€€€9!%€€l€€€Z€€€€€_€€€€o€€E7$€/€ €€€j€*€!}\5J€€€€€@5€!Չ€€€€D€€€d€€OEIQ€€€S€€€€z€%E翳O€!€€m€€F翣€€€€€€€€€€<|€€€€Sp€
os€-€€*kl€|}€)€UB€€'?t€€€€€€€€B€
€€*?ޓS€€€?€€€€€€€M€€w€L€F€}€?€6$F€€€€߽G€3ҧ€1€$F€€9€?:€€€z€Y €€€N?€€€€V€€€€€€€€'€€&€€€€€z€€0€€9Σ€€€Xg€bƟ~€€€€o€€€տr€€F6Ty€[€>€€€9€mK?€€€€!q€K€€€€€€€€ޟbV:€
€€€€€€x€€vx €;!$€€€€€€8kb8€€'€O€€<€€
o€€€€€€}€€߹€€7&€ب€c€€<€€€i€t€X€€€y~€m-€€€€*€€ʼn>€€€.NK€h
€c€€䆪€€U€€\€_€€€d%€o€}m€>_9€€e|#€€€€|€,€€€€€€F5€€€€3€€€€iGw€kl€€€~€€€€€Mp€9€&€w€€06€r€*6€Un€€€€Z'€€€€€g$^㬒<€*c€Q€~€€€7XŤ^€€€€€€?ݘ€€€PF€€€€€ €\*€€€€gݵ€€}€ +&€€<y€?B€8€D€H€€€€€€€wÕœ7€OIyo€€€€=€€€vB:gLÌ€M €G€€!q|€4F€€G€H€€6Â€Â€Þ Â€o€€€€€€U€m€€3€VW€€€WgLv€b4€€€€€걮?Z€]\€ܟ€€€€2Y€€]€>€€€€€€~€€€€sd{€va€8€Y&.€<€s€€y€€€yo€€.€Ӿ€S)€s€€€€.:€(€€U€€€J€I€Ti€P)€O€đ€wÕV|s€€':Et€€|\€8>€€€A€~€jTN€€f€€g]€V€€€€€Ç€͗€6€w€€€a€b€€€\€@€€€€2|U,€Ff_€€€z€8€€Հ€vin€€X€€j.€€€€ +€€€^€€€s€€€MG€G€€€9€M€Η"O€€€€V€€€€y€75€€€€y€€D€/€€ bÄ#׷€J€€€€€€€€€ݘ€?qY€.€€{€€€€€€€€+€€€Yf€€vx€708€
€€€<€€€€€€€[€€€RdM€E€Vo€€€€€€€&€*'€€€
€€€5=€€€€,€€€V +€H€3€<j€€r;€S<¸€€€gЗqm
€€€€€€€€€>€€wЗ>€€p€€€€€€r'€Z€€€€€€ӗ€€ێ,€~€^M€q€6€€€@€€0€3s€€€2"{D€€€W>€5€€/€β€€€€K€8€"€(€c€#\€€€€}%€€€B_€{€€€[€€€Շ€gyÄ´'€€8c*c€€uOo€€D€€€€մ€€€€€€€z€€ r€€€n:€/€€€u€s€nh€€<€/]€€H€€f€€Us/X€9a€€€*€j€€€.€€€U€m}%€ߡd€jÔ›e~€A€€s€€€€0€η€€€xO€$5€_€d€€€€>j€<€U€€€€R€\€zO€o€(Uμ€u€€f€t€Ü€W4
׉€€€S€:€€z€€o€O€K€_U€#€€ܿ€€€0€€k€S€0J€6€€Z€€€_€€€
€Fݽ€6J€W€n5€&€缾s5€€c +€&IΔ€v€STs€€}ޯ€;€€QR€p€€Ѧs5€€€ST€€̥€€W€O€K€߯Kz€€G]R5T€C€}€\€€%€մp5€€ST€€ը;€~€€Svs5궟€L€S€s5€.€€j€€€_U€w€€I2€IFI€€0V€€Z€€(%n>U€t€€€(€~€߰F€s€t€€QJ€c€T€€X-r€€€PZ€Jr€€_€d}€Q€€I€j€7€U'7€7kh€€€€wW€€€€€€`$€Q5^€8r€3€z9€€_€€€w€ܴkV€€€€€€J€鿚€bu~€€€߉+€9€€UV€^*<y€Ys€K€€€€€€t(€€xM€o""N€Xa€€€€k€#^€A€W€9>€.€€9&€2€_€m€€€ +?:€{1€€€x€X€€c€K€7Dz€=€€€€"dE€c€v€k€€8t€>€>XC€€€€€€}{'pCaÞ¯Q€+€€Z€04€€€Й€V€€kf€n/€€€?€f€8l€?@|Z€€€€[€}€€n€€€Ë€Ĭ€€€Xň€b€=€€vP€€€€0€g€n€€€€U€€€U€c€Ko€€j€€evP€ev€€s€€v˵€€vP€v€€€W€€€€€L€M€ut€v€€€€€€€€[€€) +€p€誷€€€z€X€€€€i€€€W€€€z€€X€rSÖ¯j€€AÂ€ê… Â€Â€^€9V€€€€=€€jW/€€7€Nͱ€€€€_վ€€€€[8€M€s€v€€€€€€€v€€L~S€€€]^€€€€K?€]€€€€€€&€j€€Y€€Q€€o€$€€€€€€N€tq€?€€z@0€€i€ug€€b€R€€?8€€V€€u€€€׷€€Qoa:@5€ €n€€€€׻Iw€€€€€e€"€€€€S€€߫€%€[€W9_W€X€€€kQ/€€7\P
€€?€8€€.€€W +̄χ€€wQu€€P]€gF€€€ €€€.n/€+€gH€€€%
€FwÈ+€r€r€;w€€€€+€€j€x€ꔳ€=€z€€É|€€€€€€€€€€€€X?€
€€€€D€9€qF5>€T€qI€Q€2€(€€\€pDŽG9€€GY€€€€€S
€€ €€€€€Y€€€A€€o€H€I€€ĵ€€o{€€Nڗ€kW€€v€€€jP~€e€€;Qr!&€o€-^\Ê€J€€d€€€(€
/D€€€p€w€€€€€€n€€_€€€y€€\€
n€\€€€€#€=€€ʎ=@uW€€€ €€r€k€8€^€€€Z€q_€jh€*['€€€€YOR€Y/#€f€|€€m
€k[;@0€€€€We%\å¬p€€€rv€s€ +!@U\€€€iEhN€€ܷ.u€>€€€€€€€yY€RW€{1f€B€ծh€€€-€H€\€3k€wR€€#v€€D€€]X€€€€€6(<€€q€&Rހ"€€U€€€€'€€};0€Uv€€w.€3C)€€Y€zv€€6sx€€€€€Ӏ€€€€p€€€€w€ I6€(f0_hL€q€d8€JG€€[€3e€€}'€€€€3€0k_p€"€€B53G€'€€$Z
K$^/;€€€6€€7€€€!€9€}(M،p`[€€€€€€hO€S€m€€€+f#Y€€e€z€€€€/v€€<€_O€€n€€€Pٹ#T€B€€€$€€hevY1€1€€€Ip:€€f€T€€€[€€=Y€€€ +[€€~€7€€8Y€o€~€Vo€8€€]€8€€-s)U€€€y2€€%€?
' ")Ke11€0€€€€€€€€JV&€€€Űs€J€€€R€€c, €€€€
€S,.€P,€W€>+-g.f'p0ï”1΀Ӌ€b€*€2Ivt|€_€qS€
€€
vC€€^€€6x€€€€€€€€x€€V€€€€G€Z€€y׽€€}€€3€*Ȼ€€&l€€€€L€€+€€€€€€}€l€€;vÙ¨1€€€,e€yw€€€€YC֯€>[€'€J€€d€j€uX€@€€˽3€SI€mv߽€€f€R€d€Eguyx€4F€€۱=x€€€€0{€>€B€s€€€€€€/ €x€€d€n€€o€€€0)€<€2v€*v€€€€mj€ٞ8€%Ë€€q€M.€€:€€q€[_€€€6:c<Ù¡J€€4i€Rt@0€€Ћe€€€€€o€]K€k€|€I_€€€€€!€C)€9^€1€ʬ€\y€M€€€a€$€=€€N€I€€a€€W€Tc7€€€9C€e'€a־Ո€€+C€x€ۨ€€€€€7€k€m€€(!nh%€€^€€w€d€€€€€€|€<^R€X€€qՈ€| €€€€€€Z€W€€€V+d€z€r€€0Z€€/€€?Ñ‚K€5€gi€C€ބu,€€迬_7€€€ €j€[€€€ˌ€€€Fsr€iyy&€€€€€9€€€€F9€j€a׳€I/}€*€|€€d?€€€h?zJ€+€E€۩j€€=P€€^€?€op€€€t€ӫ€€€'[€€€€.€<O^€€@€l^*Ý…qÈ«b€7€Mb€w€€`€€€h€I?€€?€-€+f€Ä€€p€<€cV#OÖ]i?€=€^B0M€€QC€2€€€€€€€N€ע*;T€C€V€:״€€€e€T€€€*€€L;€€€w€€o€2€€b€v€€>A*U{W€#€Cѵ€~€3ԕ€€€ €€Us^€[€j€€7Ӥ€+c€€)a>€€'€€€&€€\Ut€C€€€€Y€,͹€&€[I€@€€€€€€€€€€€€Rݗ€&€€€€€R€Ex=€€€€z€€€Q€QJ€€€Ҥ{€€4€M€9H:€ɤ€€_{€€y|€}€^€€€€€a_?ÐbeqH€XY€y€€%l%mY€€<€€ +\€c€€a€€s'€€€€Cv€€QÅ…'€2_€€€\€€€o|€€€€?€€-\€€P€ǵ€E€&€€€€€ +€!€€€%€X€€€ + €€Q,€겡*G`>t€G€[€€€w0\€€k€€I€€>€=€0{€€€€€€€€=€€€T€}€IĔ€b€c$g:€_€€€€!€€R€.8€€Qֈ€3€€€&4ÍsU€k€€€€Knhk€H€€€€H-€=<1
€T€ٌ€A}|W€1€€€o€>€!€/€€;€/QtcKÊ© €€€P€€'€€Ô€I€€€€&€€5€€hN€€€*g€!€€€5€€€ܼ€€€€€HD€[€J.€
Ga€€[€?€€.3€€€W]€€3€Mdk=€E€€€2€w€~€€€o€€t€€€9€€€]€
€"€"tp€€#€pU€€€Q€€€,€€€њ€€€€€€-VU€t€€Ú€@G€5€€€€€Kv€a€j€€%~€vc."}D€n€€ߞ€€€Ӝ€€s€7€€(j€u€€€XV=€?€€C€,y€9€ס€€g€€W€€}€€€€'}€a€I€€eYA€€€€]#g€€€€€€z5€€4/cš1€€€€#€ €€€:€€€=éœÂ€:€7€u€€€v€o€;€€€€-€€€€€}y€O€€€,€€7ÚŸ~€€,€Y€G€€€€€}E;€}€€g€#€€r2€€1,~€€€€€u€€xÍ£z€p€€<€€;€€Z€€€.€z€._륛€Λ€€.€K€€€.9~1€z€>€K€'=D.Fk€€k€€N€€€€5€]-€z-€€ +t€€€€u€7€c€€€€Jev€€€~$€Z€€[6€u€€y €0€*€mJ€a€€Ǣ€€€Ε,€€€€6€€J€_v€€/]儲;€€Z€€a*€U€tE^€kk€nmè¹²+€€l{€k€I.€Q_o]€t€€€€uG€€rtJg/€€€€€€n€q€€€€xl€€€€D€o€fxs€SĜ€€€ʺ€e€€€€€q€€€€}'ܾ€R_z€€€e€_Ǟ€€'(€j5EU9€€€>w€€€O€€€€€|€s€m€€U`R€}R"€€€€€€€€€n€€€[%€)|sԊ€€ou€€Uu€-€€€~/€€€l€y€|€u*W€€ALa€j€€€€>€€]€€V̛€N€€m6€ +€L€Nk€"€€71?€O€swu€x€€~€v€T€ޡ€€0C€6€€A€€+X€=€*€2€j€)€€%€-€€au€:€€€€;e.r€€W€݀/8€5`W6€€€€郶€"eN€8€A뺪ʓyI€€€+_€+€<€€€;€€€0€€w€€b€o€#€€T€€€U~1s€€€o€€€€€4i€€&칆€7€€€O€€ڵ€€€€€€€€3€€b€~o€€"€Q_€€€*€€€€€[:}%;€x€a€+€€Q€V€€li&€€€r€€M€.€€C€€€0€€€VA€R€€€€€`€€€|#€f€f€€€#€€:]ë’€€E€€€€€V4€€€U}€€{߶;€€(w< €€ €?y€€S€b{€€€r€€€€`€?o €€l€€m€€€€T€€1€€eeh€€€€{€€€Z€€b9\z€€€[€€€g€a€F€#€€€,&p€ +€€€€€€€ǿ('q€u9€[€4€€9€E€G^€€c€[ے€€k€€*87o€€>€€Ft€€Dᴪ€€€€€€€B€€€'€5G€`D€€P>{€9߶€€€€Jc€q€€ᙛ€€€~qu€€NT€q€€!€€€€€€€}€y|€ݸc€Xjv€%€x€a€€€jo"€J:-6€H€€€€.K€€€€€Z€€€D€]€€0J€€i€€€*€€€€€ʹ9€€ѡ€€`€€€tM€.%€€`€€˛€€€€Ts+€z€€e€Ub.€€€€U€€€€€€€€€€H/)^€€m(€€€€€b[€€€G€eyÑTV€J€]W cU€D€3TU€xs€€€€K€AÐ¥n,€m€)#fvc€ԇ€€b6&$€€€€4w€€@rw€e€;{€M€€kZ€V€€ܩ€€ €€€y€({€)~€c/€€à±Â€Â€Ü€\F€Q€u#€€Vl€* r€B€|UA€€€€V€€€€U€u€U€€&{€€€Y$z#|}gWK€€€€
€€€U€€\€€k€€Æ€1€€A*y€€€€€€€€€"w€X€d€€€€€€hD€€€€Xw€€€€€s€ +-g€€€€€€s€€c€ ×™o€€€€€€M€,€€w/€Gq€€Qo€0_€€€€9€#qZ4G€€p€[€€K*Ù\€€€}ϫ€SC€€€€€€€€:€=€€€tX€€xwO#€q€m€€;€€b€S€1€`0€€€&C€€€G +0[€o€,€1ÖdMJD@€!€k€ix€5b-&€€r:€7€c)6€l0Zb€€1g€b€F€€€€7€M€€€
FS€€T€€j6€€b6"€b€€€hA€1€€Ŋ1€€bM€)€MA€€b0٨h$F€XcL€)€`€3€€€|P?g€f€M€JP€Ao€0€A€€cA@€d€€c€d`l€€€M@€^e€SF#*B^€€I2r*€€fAm0XP9€%€JK}3h1bc€C €x€@+ €B1€€€c,€a€€€>3
g6S€jQ€s€i€€2€€G=Äc<
5Y€€p€,z#)!65€NC7€D&€5€€€7€€4€€S@€€€€€€0€€
k€€€Ϙ€Ec€t€yz€€S€K€@€€€€1:}z +s e5€
€z3€€€€€€z€€&R€ġ=,€d#€`€€O(O€€͈€O3€€€1€A€€€€>€0€.€S_€9*€€Ę€P€€(̈́€€;z3€m€€€3€€SϤ€I
f€€f€€7€(#z֬€€€Q€f€Þ1Q€V3q&€ؒ€€D€€€g€}€=ÿ€&€2€€0€[€ǘ€-F€Ùg€€(R~€#`F€€€`4€€€L€c8€VJF€Ԕ€€i€€€€€€lL€zہBÑ·#€€€€f€1 Z€€XÖ˜`IA€ğ€€€€,4€€€b€€€€tDZ€K|€€Æ€€€߱€€€иDyDGxG€i(+€€L€1€i€L€`4)B€)€8€0€€MD€@=MS€6E&2€̌€F€WǑ€€!€g(€-<€l)h0€T~€g8€bz€€9!~€4E€d2€E€2€bbѤF=f ^€€D_S€€€_€€€(€Q€€€€€G7€€N€€4$€€€€id€€QQ€4€e€K€€€ zW€€j€€XbͶ€X€3[€bj€w€€€a2_K€S,€€€€X&€€ +€€N€ʨ%-€k\€€&€€\€€€€q€€>€€7K`,€D€Z-€€C€€ͥ€€22€*€0~€€€€c€6T€8=p€ +FY€€€€j +€€1Պ€B`€€|€€όn$€|€R€G€i€€€&€€€T€4w[€G[sL&5U€=G€,€ў€Vja+€35€A€p€Z€Sdo€€€Z€!gM€€s<€€S€iN€vW€tZ8€`€€A€z€l@€y€N€w €€m€gDk\~€€F
g€*€€*z€€8 €12€U€1€B€z$k*€7}D€"=€=s%€8b€€€ht&7h€J€€€€€€P
€S&i €C€Tn€€€ʓUkj#€f€€€I€Ѭ€K|€€Էp€€s€"€]S€E€(€€
€€5Z€€€g
€€€#€;€-€€ €€€€BI<
[€Ҧ€0€hH€'€P€€€0j€€d€€Bc&
€,A€€j€ €€{€o%<€€€€_Ux€€€€{€€€€€€B€9&€3'IK€4_ӤLi€xNI€€!I +€€€&q€€Q}€€t*€Z^4€Z4@Y€k€c€€}€%€€B€s€€€xir@€nn<€€€0€T€(L €@€€>0M
匟€o€y€2W€^€€€€b€0€4!HEZ-Fi€€UA>g€C€€€€ZL€€b,q€b€)€!F€bL€€>GI€ǩ€|s<€Dz€5Ɩ€k=ۚ€O€€)€€,€Z€Xg€F€€€Me=Ú‚:,€€X€€€ €s)€H€€€€!z€R$R€P1&€€.D€€詇€DЀ€€8z€€.N}€#AbhB5j<B€€€3€ +€3€€P€€=€.€jL$2äºÂ€x€€€)€€n€€Ф0瘬~CIM€f8H€€€€,Hǂ€€€A€@€f!€€€k€€tF€€€P€€€€u€.€X€Ya €R€}€€€,j€€€€^a_`€€L€)47#<€€€€D€€5LHER€)H€W€€I@€€6 /R€0€)آ€€DP3#€e*€€ҟI€5€CE)€F}€)6+J<€ €Y€!€{€€€€J€X€€W`€€4g€M€€€€6%€#67?€€3]€€洫€€ƞ€€€MËœe^t€€\d€1_hN4g€€€€€g€S€3€JOj€w€=;n€€c
€o€)ś€€€€€€Ցd͈€H€€€.€€€€x˦€OK€€_g- €o€泦€ܹq€€€€'€L€€h€€d*<;Ʋ€l€€5€2€€
|i€]€IY€€%%%€€€̤€l€t{€,Czo€€€>€€€€3N€€ض€3€€1Ï€T€€€€l€[€€-SA\*€€#61€2€€€^0Q€S20€O€Ȗ1%€l€B€x€ I(S€€H€G€€J€1€€€F€€OÉ£J΀€R
€S€€R€Ǖ€0€v€%6€L˔3l€:cJ€r€€L9€lXL%^ğ€S*€w€€%2n€w€W@Isԗ€u€€!€M€€€L€M*GV€€7€€?c€HF€€+@€€a€
€€C€y@€S +a€!G€€ěc€€€12€ˢG€J€€€€€ bk@€€1h6€8|€hs4€B{€Sb€4i/€€€pxL$>fJ€P€#Ý =€N€€€Rz€€ة€€Ā€r€€x€€L€€€'A€€€€€€H#xpk€SQw€€њM~N€<%€€.€JL€€€€L%€€d&€=€€€?€XS֔€N€LY€€€€#€kf€€̞€€€€_
€€€b€8€€״H€o€€€€X€€pv€€9U€&N€{€-fz€€€g€€0ś€€]l,€€€<#9[€€zz€€€͜€€€€dM€n=#)€€q€R딤€€yYV€%€r€)€$Δ`€fÛ¬eS€ZÎœkJ€>=€€€€€€ٶ€€€Y2R€€(N5€€€€€K€L€bN€Y<%€€1@Z2€€M€k€$.591))FB€É€jI€$€€>€€€n^€Μ€€k€`€€€\P€U€1€,€cJlF"|€€+ +€SC€€É€€ + +p€\€€€;€€"€€€€€€>5€€€€€€C€uw³Zc€}A€€€€€dA|AJ#€€*p€:z,€ €Q€|€-€V€^€€€€€€€€€€€€؆€%€%€+€ע€€.lv€B€契€:€€Ӳu€1€€€K€pg€K€€D_*€€-€€€-\€€_{$W€€t͵€€€€€€-€€HCe€^osW€€€€€€pe€€K+€rN€€€"€ɳ_1_FO\€€9€€€/-€赥€E €[Ñ«"s€€B€0Ѳs?v€g€€€€€Y{tT€€zE€% €€gKse€=€€Dz€~]€l€(€=_*|m€€n€€€}€€eԔ€o€€j€}^=BiP2€<€€c€€M€€HM€e€€€€€€€€€ۅ€€Oz€€€€€€€@€ꋪ+KW€€]T€€s€~€€S€8€~ t€€€K€€П€€€6€€l€?€䟌€€€€€€€€€€e€€€̚€}f€€ܳ€€͛€_Px€€s|hṋ€[|~€€€KJ€,€€l€c€€€€€U€T€Ԯ\ui€e€?\€€€\€M€-€nO[€k::€]€€€w€€€€r€U€€€€Ñ€-€ҋJ€Jj€J1SY€€€z€€€€U€€S€€€Ѫ€x3€€€€€r/=w€{[€€€.€€€€€e€T*€€vosGoKk€€€nk€€€F€€€€€€T.mk€€*€€JO[€€€€€€€€€(€uR€€TJ€€€ݸ€Ѷ€c€M€€.c€ +€߫€€'€_E€;:;€€€€€€€V€€€@€Í-€€€€VÜ€€€€€6]T:IK/€€Q-ܶ€DF€€€€€3€€€XJ€1€€l€iC7*€€4€€?€|=A€\€€%z<a€i_€€;€€€H€.€€k€i;c€R€l€^€€?z€€€LQ€€€_€€47€€€{€RZ€5€€€€€D€€€€RZ€[FI€6€(€~€_€€P€€i€9sfr€,€€€[€,€"€jn€€€€5ڨ€€f €
€€€v€€n€€€€((Bd€€ +h€€€QF€g€€=€|€€H€€e€X#%ت€fI€I€€^I€hT€[€€z€€€€m€?+€vy€R ~UW€€€ +.E^€€g€Tĕ€&€€/<5T5€[€u€€yJ0\€t€€5€€€u€P€oQ€G€€F€€€€ֶ5€€(€€€€€Câ§t^€€€€ €A+€€€g€&TJOgv€_€€4€€€d€€€€€€€€€€7€€m€€€€$€+=h!€€€^€0€€ò€dDs€G1o9€ €€€€Vpek€€€Xw€ +€oוb|=€€4€F
L$€€SG@€€u€€€ގ[€ψ€€€€xkg€€*€€LT€&y€=€MD€€€€€}€€Rm€IÏ–.$a€€€t6€{z€z€i€r€€€orcE€€€€XI€€5(€€€~€€€€€€€€Y€9D€€-€K€€t€€€€1€€3w€€€€f€oÓnj€O€€€}ÛƒC/m=׉z9€5€Ы€8€€€€M.6.ޚ€8€65)9eZ€€€€€O€8cF€؀€€€4|€h€nxc€€€€€6€c€Y2w.€ǒU)€€Vo€ZH€€€4vb€€'O€n€R€€€€m€+g€w€9€€€}€€:+!€€!9<em€L€{Ö€E€€€Ok€€(€€€€€֌ +€€€€€€€€{;zDKW/€ajK€m€EO;4:€[€€€=€€€€TLآ€€€€€€€L€€&€^€€Ӛ;€€E€€€q€€€Ñ€o€€c€Omw'wcPmnKj€J€€€os€i=W€€n€m€€€9€cZw[€€G€€jo€€7Z;€[{{€Z€€€€-€€=€€€I€^/€J`€Gc€€n_€€€^€€€€m€€€€Gx€z€€A €~/€€€$€€'€j{€-€P€ +&0€€*n€n€C€b€€0€€€€0/€€€€€€€€´€mFh€€
G+v€/0€uӸ€o€€€vA€€g€€€I€€€€€A€]€€Ȱ€5€€€€€€€f$€sч€"et€-{'€av€r€IL€€{€x€Rd€)V€€@€r€€€€<€€- +€€€v€€6^LA€Ԃ[9h€€%
€T€€€€M)J`€€loi!U€€€€d 5€6 .Vl€m€uh€€€€:€€€i€€]€j€€€oBy,€ ,€€(#€
€k"€#UJpF€#eB€U€€&€E€ +j€€S
€E +€{€'s€€€€€€ͻ€€y€EEs€b¸ 'gÆŋ€€€€€€lj€€€眩€YN€+ Xp3€€€€HIHL€ؔɂ€€Rɵ€s€A€ €@$kjU€€€mJ€*€t€€€€Z€€ej€[ख़€R?{€â«Â€Â€ €€Ļ[0E€€J€€ d€€€AScG#€JC'€€j€€€€̫€\€€€€€fBP€€€€€
€3 €€€€1€tv6€€€.€€A€-€€D€€|€/Ȁ€€€T$oim€€€͛€€ؼ€u€€J€&Ó Â€Â€Â€Â€Â€Â€Â€Â€Â€Í³Â€Ç‹i€2:0€`€€ͧ€
h€ƎnY€Z4€ €4€Gi€€C€NÂ€ÙŽÂ€Ò Ö“Â€[€P€€l-]2€ 8€€€€€K€E€M€kE€;€€mkml€€€'€>€€€€nLa>Ah€,€ap€6XeQ€vk€J€€€n~€S_$Ñ„H€q€€z1.w€€&€W€€A1Yv€€€h€BKZ€M€Ҵ€€ډL€.ۢ€WT^Z!is9ڼ€€y€€€F€@z€€€`D€;€€€€€|"}>5m€H€ݎ€€€€%}b@;€e€€€X>€5€€€€l0&>B€|+€ +ß©hT€€€L'€€ +h€€)€€z€€€€g[u"€<€+€€{€€€€o€m€h€€Cԓ€p€€
1€€>€€€Ӯ€€€P_A}€W4€€€ۺ״€€n€$€€€[{€E€5€€)€€€€€T€€f)€€b6c€c€6€€€3u €,€€Z€|Z€€"€€|Q_€TQyyJ€€e€€€€€Z€€€€r|€=€€€+€€tz}U€E€€€;}€W€ €€€€€/€€€~մ€€€€€Ըnj€€i€K€€€e(€©€W€€W^-€€€{€€i€a€€H€Q€€€€hN€1€€€€€€v€€€o{l&Jr+€*i^BoP}kD}[S׺€S€€€€ +E}a€€€Ӷx€€€€(€€€€€€ €€4€,€€d€€€*€VK€_r5€]€(€€€S€[€$tu€€€R€€S€t:D)L€%€€€4`#€~€€€€
r€_€€€4]`€A€€€U_€|W€oM€g€€€~€€/€€B€€3.€€€€CV€€Y€€€~€€€€d€€€€€~€ҫ€K€€W€€€€€r€_mk€€W€€H€€vy;€-€€[€P-LHA€€€€/€Z€€€#€a(#-J.F)/!̖?€]€!8€ +mC}KC€€ً4€䅳lsf*€€€0€€N€J€Z_f€€€€J€€}䘙7€<€€€
€9}€€:HBl(€<€€€uw]pY8€€4('RO€€̶@€€Z7M€H€$!Q€€€N€hȹ€w[€€€>€h*€€€)€$€Ѿ€ޤ€€\€n€U€T€DK€h'A€€8€~-€vԣ€€€Ì€€€8€€0a€€u`K€€€
€€€€€€€€€)€€9Ez€A€iK€€€€[€€€~€-€€€€€ANa€€€w€(Xz€€€i{€O€€€€_€€€€€1X]€€€€$€€9€€€N€€3,€V€_z€€`p€ˢ暎€3jXzo€€)5€.€R€,€SU€€V€€€Lv€€ơ€€C€€]€Io€g€~SbY€e54€n€ݢ€MwG€€€%€2d€€€c€=ɺg€€!1€€tt€€&€€€€€€€€€€u€€€€€€€5S€€€!l€€ €4=<€€€R€€€k€€5€€€E@|1}€v€z€|€€€€€7€€DB^€ljכ7 +=ɒ€€B?€S€>ş€€Nߕ€€€€€~]€o€uq€€!€j€γ€&//\€;
6€€€€UȽ[Z€/€€€€€,€gم€€€X€"xC€Ew€7€€€€1€€"€€y€0€Mg!€€€€oYç¯×²Â€Þ¥Â€Â€.,|Í„?€€€4e€€€€€€€€ۊ€z€;@€!€€€€€Ƭ6DÞœ/Jk€[€€6>c=m%€uk;c^€€@)€€€:))€,y€€6^unuG€&€€€Hո€nW€[€€€\ε€€2a=€+€€€€J€L`R€€L€€€>a.€€€€BeD€€€€\t€Gq€Gq1€€ .€c€€€:.€]€€€€l€Cp€€xUl€€[€Ƹ€€€€7€€€€€€ €€€b2€€4€€3€nS€‚/;5€pC€€u€l€i€€v€D6€€€|€€€%:pm^€€
€*u€€€€r€Q€:€€€€:€n€z€'€€f€rý\€€Vi€€n€€ڻ€{€b7ꅩi€€€s(€mD7€)€7€€׾€Ўz\€€€z€¨$€€I€'€€€€€€/€8?ٙ€t€)€€€€€€ش|€E8k€€€€0€\€k€€wQ5€q$€€€€€€-€S-f-€€€p€€1/€€€€€J€€€€=€€Ҩr=nHB݅€€€€[C#U€:u€C€s€€*€6hJ€€:}€€€€€€774€€€€€€€J€€ +€€o€̎u€~€U€€kJs€?€TUzʲ:€€]d€;€W€€€c€€K!€€u11€€}€^€|€t€€7€€€€b€€9€€o€€Pߊ€€€€i%€€€Qi€,€0€D€€€{G€Ts€[€€€!y€€=€€€nC2Pu€Qel1€€y€f3nNJ#.9€M€€[€€q€y€€C#€€€€}b€z€`C3 €+/Z׮n€.0o€€€€€`n>€€|Yҗ€]€€€آ€M€€u7}€€€€€;€€€€u/}~%}€€o€€€
€€€o€~_€€r€€€€}€.į€€7Ŧ€€$fz|.€€€]€€€€€S]€o4€V#f€€LW€F€€b€€€€€*€ht€n€qo€€#€Bä˜Â€Â€Â€Â€Â€9S]9\Y€p€@€€€€]€€MB€Ä3\q€5€[€1E1çƒÂ€g€o€l€U€€0Ú‘.p€E€€ˎ̸€8פ`Ždt€€€€€€€€€# +€€Ovݖ€^€h\n湆6€o€€€€€€n*€V€/€g>€€+N)WL€€€*RL€€1€r€€+€e!\€€Փ€€g€'3x€|[€€€{€׿€sÑŸ?€җf€€€M€€€\p/USC€59j€OB€€a€€Bt€€ʃC€Ĵ€uf€-TG͖€A€€SkQ'€€7t€75,€€€m€]€ OU>C~€Y6€,€€€€€€ccog€1€}€€€€€€€€v€J€$€€-€€€€_€g€€€^€€€Ǜ€€€€€k€IZ€V€€€][€22׌"s€h€o€?!l€€9EEÔ<€€L€€€5€€!bÑ‚|€€Ӏ€u:8€€E^€+€g€€V_*€3O€Voy~3€€͸€€ €g€€€€€C€€€w8d€<p[|€l\€€€€€}€Y€€ӹ€J2€}q€p€
€*1e€/€€€*€€q/€€€€€€€mS+€q]0€€Y€€€€U1€;麛4ή€J€€.€€€+&#Ù¿{€/€€I€S€\€€8€€€<M€€€/k€c€oI]dyÓ€8€
f€f€31Jy€.€j€€€€>€€€€N€€€;T€€
SOjE€js0zWN€€€]P€€€€1o
.\€€rq}€€€7aN€€'2x€€€L€mW~€€m¹iz$€c€€€+RJm€€¢€€€
>€€B€h€€}Ì™/€€€B€N^nA/}€h€€€€`€€€€€€€t€€€A€b€€B€:€€€€€€€€€=U€€€€qI€€€€=E€€€Y€ဧo€€{r€m>€ǵΈ€€=i€€€€&€@|€€€€ .8t€m€-w€€ҔB\€€€€Z€€€Z{J:€€€C.€€{zZz€€€€€€u +€€krW€t!€=p€€€€x€ʨ€€€8€g]€€y€€f€z\€€€4y€ +(€½€^€z€JYySA€O€I€R`€Y€€U€€\€`€€-N8€€5€$€€8g +f%€PJmku€€v€€&g€[€VЫ€c€€^9€€€P݊€wm+€-€+3€€€`€z€€"€€Ψ +^€€(€\O€R€M€WjÂ…_C9€€€€€€Rè’€€;nl6€€H€€\s€€€c;€&x€€e€/IJ€E€n€-o€RE€€€aK€€}€€€€j€€m€€eyÂ€Â€Ç +L€ۃW€€€€L€€€n€€^5€]€p€€€]€^€)€^€>€€>#€F€€€^€€€:€Փ}Fmp€b€€€€€^€K€€U€KJql€/€A€€|€W€€?sqօ€€€€€€7€X€E€€€€€€€7€€>\j€€ + E€€€€4€€€€)€€p€$e€€€€€V-€€€€Xfs€€€•€'Ls€I€€€ӡw€€€€€pd-€F€€Ĭp€k1€?f€Z€€€ؖ€€€s€Ib€h&B€€Q@€€v€€€€g€%QT€4Yf6S€ Ӊփ€€;€€€€$Æ°m^€Ls(XMLs€F4]0 +2մ€|€€IF[€€€%€RLW.€€dGڥ€€9J.€€€€€
€€-5€€€y€€
~€€
€ۄ€€€k€€€ +1€3?;€s€€€Zs€€ wÛ¾^€)[€€€€k€€€€€kZ^€S€)€[€-€ٙZUr€€€,h€Y€oX(€€3W€€€€€€6€:€€ A€^€^€.a€Y€E€€€€€'€9j€f&:€€€*€:v_]H€€8€U€!€€€J€€€€L€€€€L€ϹL€s€DÑ9€€hB€ €€|74€€€J€€€€€€LYD€€€€c€>€fF€€.:S€-i€€!m€]€[ykm€€€€}<B€l€V[€€b€€€€€€€€!Kpμ€€V€cG7€AE€€€€qf€2€€ +€a|€€€€7€€€|€j~)n€€.€€€€K€€Gh~ +€ +€€_(€G€5^w;€€€€i6€w€€r::/€#€t€€H€_€€€€€ΑSs#€€#€€€€x€€â«Â€Â€Â€v׀Ù€€=H€€€lFh€€d€€3Å‚r€*%Z€€a€€€€7€[€€€bp֓€€`€#€d޿€4€m€Vƀ€x?€ɾuSG€€~€l€€€€ᕢ€€€O€=€S€€€7<€€f€ǂ_+~mg€5€€\€€€€ۄoCp&t€:€€0nf€€€€€m4€^€3ݹ€i0€€Rc€;m4€s€3€€€J€)(€€€8€i€€L€€€€€€j€s,&Þ«1€€K€€€lpg€€P{Q]€0€q"€b€b#_E€€€€€I?€7€cl€€€€€€€€[€€€€€ >€QX€€€O€1w€€€CU€ =aQ€:n4€€€r€V€€€GYz€u#yl€€€G|€€€:Ë€w€€8€[Q3]€€
€€l€€7\€€#,¢#)ٱ€€€€%E€€Y€Ϻjw€€€€[ŀ€m۬€€ +€€€€]€u€€€€S€y7€ȷ€€uabFN€€.Ė€€€€[j+€€€}€q1 €€€€J6€€€-€G€€e€€€*g€w€ʛ€녘DQ€j€€€€bqa€€ÌdP€/€€z€C€€$€p€m€€pd*€€b€€€I€€€€%€€9<€y€€ehr€€€*l*€€}y€€qI&€€១€€€e€H€€V€>@€<QT€€g€^€€f€€€Ӈ; }`€€|g€€€B€ +L@€u€ €7/%3"€€€k€€€M€\€€.€¨€~w€€€F€€s4€+6O€[€uY7€\I€€
zW\(€p€f(€€2âŠe€€L/$€ʆ€€sb€
P€6{\€J`$'€@€€€7€€€dduj+T+/€1Y€4€n€€€€f
W€s€€€€юv
€€€€w€riR€X€€€i€i€€=€j€B2€f€€,"€€zF.Â€Æ Â€Â€e]€€\(v/En€%€H}.}€#o@€€Y*(€s@3*#€€^€€s€}ážÓ—o€B€w߃€}w€g€€€€H€€€€€€€r€€€€b€€€€€€-]^R^€€temme€€€%耤XJ€)€A9:€€€
€R|ݮ€x€ "€g€Y.€]X€€]_€€(€€€ը€R€€QVPX€€c.€1€€L€€€s6<1€€d€€Е€€4Y€(L€5€mPj1€€€7€.€€€[€€€B€ujqט€ѷ^L€€J€}_,€B€ €€Q€RK€e€€€€€€€€짳€Vjqq€€€TjQ€€€€9€€€rC€YDT;x €s€n€€U€€Cw{^€€Ǚ{€Y€dnS€€€€k€€€rÖ€€RT€€€€HÜ»h€€€Ow€€x€€€€:€:€€xT1€o€cB€€/€_.4
€€€€€€__Qb€€€€oD€/€€^€€€€€s€€€_€€Kd€h^€€q€{>Â€Ó Ä“?€}€€€L€o€€€€=7€€€€€€1€|€€n€x€€€€l]€UE€€€t`€€^*W€a€€€€&Cw+€ o€€€€s +F^€€~€€€Z€€€€€m€€ef+TÏ‘B€l€€€€t€€8O€5€&€Kt€€qɓ€€€€€€€€ßR1€̙o€€T€'€€€7€#€x€fE€1€€€€ €€€€€q~€d€9€€@J_€A€€;€ €€_VÝ€€€
€e€}€€€€€b€€€€Ô€|€€€€€bKF€5P50e`€N:€2€Q€.€b=A€ €€€€€U€j€O@€[z^€C|€€wK€h€€UÇŸ3€ ~r€€:€P +/$€l€J€=X€€€€Մ€€€|_€E€o-QM€€[€€Hs€€2i€/u€~˼€֌€€<€\€€€z€€w€€!
71~Ę(€€rFm€ +k€€j€凸"€€€g€€€€€€xO€€ÄM€Ρ€|pK}€€€ݜ€€S€€JG4€€v€€€€€W€´€€LI€€
ʫ€7<E€W€_€E€\
E3€E€j᛻(ޱ^€€€ǻ€#€€€I8.€D€€
€€d€84€€xh€€D€€€%€}ʺ€:>€€€º€€h9€È€T€€Trs€€€€]€€€e\,n€€€€]€Pk€>î€%j€'€€€y`)€L€B
€/€A€xib€€€€€ +€E~€Ew<~€€ao€€U€€!;X€͋Ś€l€}€€Ȩ-€ +€E€€͛t'€€€槥 +FX€€€€:€€€H$€€
3i.€€€]F*€€z€ճ€p˳€j€$Eo4€€p=n€3€€€€€\€a€€€€€€_#€N:!z€W€€.€€p€€d€H-P +€v€߯€o€Ã€B€€€<t€€_q€€€b€I{€(€€'€€€1€ފ€3T€J€€|€€iO g€tL€€g(€5Bl€'€€>€V€€mh^K€Sx^€J€o€€€y€€€€€€`ÊŠ^ހYd€ €m€€{hD€€€Y€€€O€?'€kɜ€€!€€-m€in€€€€T!<€3€7€'€€€ €c$€€<@€€€€*=@€a€€4
/C€€€€€€ZvCL€V€€7€➺€lA{)€T€W@€€I€
€c€€=€€€^€F€O€t€€€*q€E€€r€€I€€€ӳsU€€ '1€e€a€€€'8€€>€€ފ€nuq€€ k€€Vv/\€€a€WE€EMzԔH€€€€T€G€Q€쿋€?€€pQ€7€p€€€@q€€€€€gWJ€q)yS7€€€€xh€€€
€€Z€€X€€€M€M€€€€€Jb€儒€*€€€€€€/&€4F€€€€€€€€ۋW€Mpß•|Oߤ€€-y€€(€€€€Z€%€g€|a€€u/G€^r€R€€€z€_€€t€€f6€€jLO€ƅ€€I€;-€€у€€6€€o7t€€€3€1_€Ⓙ€€€€(€€L#€(-€€ €pN€€€€Nr€€m€.€€D€d$€]€€€€Y +€€!\€k€€€€Q€€€€94€€€€A+€&€ ++€€ Ó£(Ô¡#€€€€€€€€[€€A2€I€]€€w_€€€u€€w5€Ó€&€€€€€€#W€€tש€€€€€€€k$€\€dI€K€€>€44WEKvbuN€€€€O2€6e€0V€!e€!€€€€O€3€€MC€/4Â€× o€€€€€€€€e €€pZ€wp€€Y€€i1€€€€\e€j€€€7:T~€b€€€€€j€€mt€7n€ |€6:V€?3QE€S*€:v€€WkKUk3€€Eg,€׌€O€1€€€t€!+e€€€` +Â’u€€€Ը€$€=€€bf€€€€[€€K€€€:
€8€H€€I?3O€qĪ€[€€v&EF€€€%€€ɹ6€+Y€8>€0]o€€€€:€€€ +O'9`€|`s€€g]€€€€s€€Ԥ€€n"€€g€€[;€~€hV€€.9K€\W€€ҕU<>€ظ€€€q€.€>€€i€D€€€=ä–€Ns€`€ WӤ€€€€€€y%"€w1.€1€€:ON€€[€ +r?€4€V€|€4\€€€€5€y€c€€€o€€`>€ +€€€€€€€-€+5€p€U€€蔥€lrBU€߈€€#E€2nM+)4A€c€€V€€_€a€€€€ˉ|w9€} €€NqmE.?€€1W€0#җ€_€€@€C€3 €i4€^C€s(€€€3€xz€s6(€€jв€pҚ€€9€€€Y€a€€vn€€€:€€Z/€€€K/P€Q€WQ8€o€€n€€€ls€€:€g€€q€!€€€cVC€
'€Il!a€y€|€ACb€€~]€l€€ F+€)€€€€€`€€Ds €+€€d€€
€€€€!€R€x€€S?:€€ϼ€€€€"€€€€٬€;j€€j€r€[€€€2{€m€A}€⼮€€ym€€7S€У€€€€.Q1f€@€̓چ€€€L€€€€A€Z€€€€W.€€@€"€€€€.€€9€€€ [L€%€ E€Tl€=€€mRp€€€€b€€uqx€A€€\Y€€€€€W€b€€& €€€O€€r€FR€n€€€€Û€€€ ;8€€j€€r€€€€[€ €=€Մ€€€!\%€€-€€`Q€€7€€€€€€€ҡ.€ +€7€€<]w€â‚ij€€4>€€(i€N€C'€h€€Q€€€ڶT€:€€b€m€€€T/tDK€€€€€U€!€€`I€@€n€3€Y€€€U€7€€9€€k€€€bT'3€€€€€jVD€€j€&€-n€€€Y€m€mȪ€€桦€>€:py€€€€€:5€ j€€a€g€€ €k€€6€€€€€€€or€€€A=€&|€o€€€€zh 㲘€R€URLJ €€D5€I€M€€€€€΄/€€€€=m€€,€Oe€;wlj€$yM05c€€€€€?€m^€€€€€hv€€-€7[€€€€€€Y€€1€€=€€ݸF9€i€€€€Θb|€+€€€o-€€€€€€€œsi€€€€&q+€€€€É^]€€€€€R€€Z€#xY€€U€/€€/u€€xY€€ծ;qY€fw^€v8G€b€€pCdY€I˖€V€2€€sh€€8׌,€سI€}€€=€=€}€€€€ˎu€€€€5€€۱€€1€€€€€{€€€k€€ (€ܩ +sr€cI€w€z€Jϊ€V:Gw€€'€7€2€c€'_€epÖ¸R/؀€€@€€€k€€Ʈ€{€ €€Jmxq3€€%€€H€969€€€€€]F€€/€€Wn€€€4~€Ed€%€<€€€€€€€/į€=J_€{€€€r*Æ‹)€3€€u)Uq;€,x€€M€^_j€},€€€€€€F€€€:€@y€v€F;€ +€€€;€€€€€€Ek€€€ã¨Â€Ã±u\€#€Jo€€€€㊎€€A€€€€p3€€€€€W2h€K€€D€€€€€A€S€€I€U€$€€<aR€^lE2€€ €м]€5€€:€!Jq€0€€\€€.S€€€-p€b€€ D€O!€€€zQw€g€€he€€€€Õ€u€b3€€€:€b€X€#j€s€#€€€x;€€€€€w€€xI€€\€3€€T6€8€€0)1K€~b€€€X0D€~€€€€€a%{€€€€€€€zz€Ӫ€-€€
Y1՛z€?€€€D/.€€€7€|$/bJHϱ€€€€KM€bB=f€6€c&€€Q[€]€[€€:B<€€€€G€€p{€€9€}SZ€=X€€€€+`€^I€€€(€€€ϻ(X€€'€€5ۃ@€€€6€€€€j€bJW€Kty/€€_€€/€!€}€€m€2J€/€€w€t`€€€u€€€e€€€€€p€€€N€€"D€€€€€ڊ+{€€€S\€€>€€€€€C€cƪ€€F€€€H€^}€€@€P€€g€L4a€€€e€€v€€a€|€€v=€€
€€B€x€x€€/6€€N€€.wzA€€}m|8€€€€€}m€€h_€}=€€€ :€t€C€r€Bo€X€s^€€Po€&'0-8€€€€€€€€ô>€%€tP'#ז.Bf2€ +€€9}€'j€x€€Z€€€€Ƹ"?ƕ€V€€
€€'€€xRv€n3€ȸ€€2€€€€u€€M€€uAz€1sc'€/w€€€|€l€€2€€]€€k1€_€€*ƚ€€€€s,€€€€€Bm€€v€€€2Lj€@m€c€
€.1€€€2€€€MMg€A€€J*€€ݨz€N-:3M-€[€€€€yb
€W€€€€2TÙ±,W€€0€€€b€N€€IJ€€`p€u€€'ß¡2`î ª\€€kt€€€i€a€€>Zve€~€€Q}€ۃv€T€€€€€F€,ޜ€€|€D€€w€{Hy€€}€€€€€€€€€€€€O€€Q€j€€ߵ€€/l€F@€P€-0r€€€c€€ʀ^1"€€s€€€€T\p€S€/€A>€*v€D€p]{\9Í€M€€&€€€€I€ +&gH*)€2€"€€T\%€€€z}€j€€€€{{€^'w€p€[€€{:€z€€€€Y€=€gш€s€€€€€E€€€€ €c€€@€}€8V€€€Y€€€;a€€^~v€€€+€`€s€t*@€€CK+U€€}€€(€€-,,<K€€e€€€€u€
€"z€€78IwM€[€€€ÇŲ[€€g#,C€-€KVV€@pOoÄB€ټ€r€Ex€E€w€€6€€€߮€€~~€€=€o€€€€€B\€odICE€€€€€€'€€[€€J*€€€>€M€€€€)"FÖSa€€€€؊€;_€6€€€;€€€€€(€K€mH€€y€€€€€L€E€€n€€ZBq€€[_LO€s€€kjÇ¡8A€€F€qEc€€\SRqQ€€R€€%Z€m€€€€U€€€)Yz€*sM€€%€€€€€€?
ctanglee.SYMM€€€,€€€€€€MPSTMPS €N€€€€4€Øfq~€€F€ ?€€+39€€€€g+39€4€€€€€n€€€€V€r€€s€]€€€f€€c=sY€2A€€e€|k€€M€€'|aÛ„l€+O€r€y.l{€€€€€€p€ €n!_x.B€M€€l€€€f[8€!€fâºÂ€tyuv€k€&d $€3€'pN€€€€ !^{H€€€€o€€€€€€€€€€
€m€€͡€vȻ€€€€hn€€€[€€€zmeu
€€*~p+€€€€€oG€W€€/€oi€lloj€;€€€?€?q€€™€`€€€€+f^}€€€omn€",h^€€€lk€m€[|Ù€€@gq€€€+€;€:C€€€€€Ζ€€€;€0€€€`€%Щ€wuvt€P€Zq!€0€=€€€€|7€€€M€€€€€[€€
€€€€€/€{'€[€€€€.|€€{7€۸€z€%€)€ €%€iۮp€3^€`€b)1€P€€g€4€7€#€€װ€€yl€€€W €€€䑨L<@€'€€<.y€B€€€7€€,€/ €..€d€€€€€€€B€Ä€€cg€€€쉯€W €€€€€€€€€G€€kW^€}€€ㆂ€€Y€€€€€آ€€|y€u]€y€€€€€K<€€€y€€€>#€€€€€L/€;€€€€€€)€€€+€]Ljs€€€J[dkv€f߫€k€~€~M€ß€n€f€4;€€wj€€>€€€€֧hv€f€€€€f€ m€E€}€€€€€€j€k€€€€€N€€&h€€d͞€ٛ€€€€€€€€k€7h€q€~@€:€f€)mC€€€€I۬ŋPı_€€€€€€€€ì´mFi'€,€€€€€€f€vJ€f€5;€€[€€€€ٹ€€€€€0q7I[€U€F€f?€€oh€qi€%i€S€€~€€~i€€€ֿ&mà €-K€Z€€/H;!Y€W€G€€`€W&{€~}yW€€€Y€7€g€€ζ€€€€€€R€€€h{€WJ€€€?€€!a/€€€~{€m%€C€€€%€€€€€€€€ݚz!ÞƒG€€%€Ú€€€w€d€푯€Ja۞€€€€€€€€pÒ•3€Z:€::€C€]A€€€€€&€?I€Z€/€€Ô^€"€€1€€€€€€€k€€XY€X߸€€€€€€€u}€@8!j€+k€o€n€€€ق€€1Ǩ€>€uK€g#&6€Bí¡ºÂ€Â€Â€Â€Â€f €z€Ы€€€€0€?€€€€€€k€Ža[8€.€€€,+9~€~€€x€€:€*€€%€[€€€€€@"€g€BL+P€€€€?€€{€&€{\€€€1]€g€4€{ℤJ€bw€€1€T_€a=U0€€€€ҩna,hzTeG€€€*{€€/h €€Z[€€€€h"€€€'€€€9€圚€€UiF€6P7O€ +€€&€Pu€?o€ԕ€wW€€€~€€€€€€€% €€€€€€€€״tÖ´W€lnm€€€€xb[ €d €€v€€€ݖ€r€Cßž!!|€]€
[€-€€€€€8)^€€€͑^€€€€:€€g/(:€€€€HR-€€€€t€€€Qi€NU€]€7€b\€€€€Ƕ€X€>€gN€^€~{€€€€€%€SÂla€O€€a€€€ €@€{^€%€Wv€k€€€߱h$€?€lZ€€€$n€)€€i€€"ÅŸ<€Z€€oq€_9"RP€€J€€ş €g2Ѭ2o€€€€€€Z€ԡ€6€\€ռ€|€Ð€ߎ€€_Ê¿^€€€z€€ޗ|€3G7ÃN7€€L'€€€S!B5€€€€I€Y€s€€€B€€€€uTp€Z|€J%z€a€OE€2€>gI€€]€€€j*€u-€E}€H€€€<€€€€1€%€,€; _€€p39€€u€MM€€P9<s€€€v€€+€€ +€€€݅V.q€€t€JuX€N€€_€`€pd€€€€€€Q€€€€&vUTJ€€Z'€€~€#O€€€2€
w5vr€€€W€
€€€€€€B€€K€-+€oQ*m€€€€€€U€Wt€YXbRL€€W€€€.€d€8*a€€€j€MFئy\€|€b€T€€€oʈT*~׿€G€Ч€z1|(€Y€€%!€€
€€R €€]€4€€g)€€l€€€€€€€Rde€€€€.€€O€">!€`€K]wº↊€"€€<€k{€€W€€€u€€€€€[€D€N^€€€Wk€^€€dL1€b +€Q1€€€I€€€^€z-R€€€€S€|€SۅI€€€V€x'€O€K€y€Vx€€€€>x€€ €€€T€:€!€2AaO€[W%[€€\€€Hvr€€€Zo€€€wy€p€=
Q-U#4€wRPl€f<v|€€FC€€€n/€x8ꔺ€S€«€€/€€¯€b€€€€€€R€€+€y€€_€€€K,T€€~€'_€I€L~€CE^€€"€M€€(€€,€€2f8€€u€€€|€Qg€€€€€€t€a€R€H€G2y€/U_V*€€Hۮ€€€€J]͖€€€€€€+€€€S€_A€Hs€m€u"ÓµR€€v€<€€€km7 z2y;v€€€€€5€!2€€d€3Õ•-&m€G€$€€|€H€$€a€18€€€ €י|8J€!€l.€{y€&€$€€I"€€€ry€ €€€T"J€WL€€w€€t€)hy€€5-;€c^€€?€e|P €€€€€:€a€€e€#€c6x€€<ᑨ€€K€€€N€€€-€€€RPd€€}jqq€€€€Vß‚mQv€Cs€€€<€€r€€€Ek€V€aZ€T€4€€€€€€'aY€{]y€v€j€€€€€uÔ€J€,,[X€P€€7#€€€€€d€€€€X€\€€€€€{€€ڤ€6€€ܒ€n€ڔ../€€ٹb€y®€X€I€€€3|€€€€?€€€€8€€.;*€€u€€W€d€M`0#€€€€G€R€€€IJ€€}€QƗ€€,€€f€s€^{€€€<€€€€€€€wз%€rJ€;€"Z€€€€fy€0€€€€qs€j؛€€€F€[}€.L€€ܤ€}€Ɔ&غI€€€7€v€€€€€)T€F€€V<€€A€w€c€~ws +€f€lkѯ€€€€5€€ؾ€<€€7( +€€€€e)€]>€€€€€Έ)€€€€Rqj€€€€€€<€͙€€O€9€€€€€€€€€1€€€MB€€ €A€W€wPXÛšy€€€@€€:fr'}€€€R€u€€€>" +€€€€€8€€}€~2€*€€NN€€€€€€€zQ€€w€ab€^g2€,€`n€9€€nLM€€;€׉l:€A€€F€};f€€€U€€€€R€€€€lH€o€eh3V;e}€€€uÙ¹u€€€<€€o€a€€€;€(€R€€€€;€EY€€n€€€€€€€€:߉€_Pâ«6Ғ€€\E€€€€€€e€€€Ɋ€{€v€€€{At€€€€€€€U€€|€=€6g6J€€HG€€YEBM€ۑ€€€€€5\€K€A€ƙA-€€€€€€€w€€[€€€€C€€^€€€€ۆ€€3€Vx¾€€€€€€€€M]I€ €hlr€ւ€€w€X€uɂ€€z€%€€€R€ڲ€5u€€€€€€i +€y€€€i;y€€€V0€w€€€ީd€)6€ v,Ù²kÛ’-€€]d€€Iɶ€€a€€v€(€5€€€€€€€ €€s€"€€€€€xr€€€€€(€qr€€€€€Vt!#€€:€€€€€FFJ€€m3€€€€€€€:€€pA€E€€€€€€€€€€€€€M€U€€€€?€W€€€€]€<€Rv4€_}€€€€€€€1}^€€3€@€u\a€H}w€€2׷€tu€€Yg€R€:Z=€FV€Ӌ €ݔ_€€V€€z€*qk
€€€J€€€u€k;*l€€€So€V€€u€€€€ +€%€€€L1 €}dn€€rn0O 6e€&€E€€€ €€ €*@Y€2qN^€H€Bn€€€\€€€T€B€€€Vv€€OR€€A]?l€€5€T[ߵ€€€€€€&€€`€M€<€~€€->€€€~o€φv€?o€€€€ +€G@€Î͞^_€
[€€€|;€€{Qe€lP€€JZPs€€€€€\kzM€€[Â€Â€Ê n€€䫨€#€7:€€=€~[~Au€>€€%?;€€€€=€E\€€€ur(€€€o€€€Ny€€|€€€€ +ym@€€€}'_€€€-€l€€€[Q€€€U0€ѓo|R€h€€€€&€€˓€€O€€€Y>€€€Z€€€BY'V€9̊€€!€€€g€€<€աsN€€€€b᱕"€€€U€€do`Ý´ (€Gʎ€€€€nï«Â€Â€Â€Â€Â€<€-z€g[€€E€ €|€O€€€€€-€€€j€€€̓€TlUa€€€€ݾCAD€ €p€€€€€€€Z€€qU1€)€€€Q€€€o#€Y|D€€€z€€€JMy€
e€€€K€GQ€!h€N€'€€€€[>z?€€,€€€h€€|GW[Y€
€€Ԙt€[9€)€€€'€€.€j€€€€€2PB4€€€€€d€€€€€€€€a€€K,€€fn€€b€€€1,€€_:˻<€S<=7€€€€kA€bX]€€€€€`A€€€3sA€€€€<€€€S€KwW€€€o]€€nT€@€v€0SP€˻€%€€€
€D€.€#€
€!€M=TҜ€€€€€€[€€€€€P€€9€'€fe€€@€u€€€€€CA€€€Ӄ€€c|h&E€€€€€€€€g€€v€€€|€C€:€€€֦€^p€M€€€€€i€€€I€€€<€€€€€€_€€€€€rr}u^€€@€€€€D€G^€Q2€€€€2€€=€€4€€€2€€€€|ɵ€€€*jk€J*€5% +P€€€#<€v˥€CX€FW€6€(€b]FP€€€J9€€€#€€?ÏŒI֓€A€€o€1S6f€X€€€€|€€€X€€€d€@O€€€€s€b6€€€€€R€]€~ €€€€)á’¥%€€J\e€ڑ€\€ד€0€€€€k€€€€7v€\~€€3€€YN€€%`€`€=[€/€D€€B€1€4{€€TOx#€z€€d9g€€k€€r€€%€€€fRYά€€۳ +€Ԙ€_€o€|€4IU€€€€€g€€€€R€€€€G€€3€€€P€23V€€.€€3€€€€€ۉ€S€€ €}€€€U€M€€z€;N€u€.€WK|€Y€€ǯk€w€t €€€€?a€u€]€3€!€€ €€0€€:ū€€. €€€P€€N€F€}€€_ۺ€#€€€€S€€€ʟƴ€€€O++.€/€€P€ČZ€€Ó€S€€A€_€€+p€€u€€US_PO€]Æ–dA€€€+d€€€±€€€z€<€zٛ€\Mv€€d€,H K€=€qÂ€Â€Í Â€Ú€€€CP€€€l€€d€
€€P€ӻ€€€-€I€\€}€͈€€€€W€€?&€€M\€€€€U.€€€{m€EÂ€ä¡ Â€c€€ɯWVx€w€€cxF€(F€€kÉ‚#€͂X!€%€€€€€m€s€€€€€€u4C€p€ 4O€u€8€€=L€!€€NL0€oR€€z`€K€€€€)€ԽiÇ‚"€€) +€Iz>MQ€k€U}€€€€€z'€Fa€€€_€€=a€M€€€'\[€'€€€^d€€€€€€€ݸ€€€K€€Y€ €f€€
€Nuz€G€C€M€(€/YFx€€{€G€3źcsK €€Y€J€€b€€€ €av€€€x€€i€€€€€€€€€:€V`€vT€Մ€'ȱ€U{€Dxv€€`€vO.€€€€2€[-€€dCK€€€.€¯iYF*X(+X[\C€€€€€l[€k9€P;OG€F"b€[€I€|v€€€7€€€€A%€€E€€Px€s€€ﺧ0€
€^€€€€M€€€m€u€+€€€)€7€5t€|$,€€€c€߱C€€:A€<;D€;;зY€€€€€€W€Y€|%€€a€H{<€€€!B€€€€;€€=€€€€D€€4€Ժ€€€ŧ~€€€i€€ܦ€h€*€€S€€€€€€€€e?[€>€t:7€ܕ9€€}Oo;4€€ƺ]ˎ€€%€=€ch€]€O€€;€€€€€€€€R€€€€$ټ€€ë¾I€€€€€{€9€͜߀€W€DÞ‰;€€€b€y€€€€€)€ũAb€^q€8€j€#€€€€5€"€]€€ˣ\€€V€Rx'W€ +€€Uk€y€Z€uEM€yi€2/€€€Q€o@€L€€€€€l€€ٱ#$€@c +€€€€€P€€\€€;€\€}Ë•IoÕ”;|;z€"{€v€!d€ó€€€€å“!€€€Q5v€?€ոg€ +lD€@F€€€*9€€U{€Y€|
/€€€€G"€€€€"€/€€€€tT
+€€€l€€nj€;$€€&3€€ӗ"#€€!B€€€k€€ +]€o€€€€;d€€!Ƴ;/€k€b€€€=c€mP€€€g€w€#€€€E€€ӈš(€gk€A€"D{€=}€€p#€VQv€cj€j€€&€€)k(t€c€€ڸ€€R!>€i€7€€ي €€€€€€€€€7ޞ€€€€€+€€€̩՜×A+G€€€+€ +€
€"€€W€€3€€€€€:€€€€€nw€)€׶:€€U€€€)I€€€&m€6€Xm|OBr€€y€€L€nlQ€:e€)Q€䲰]糦U€€€€!€€€€€!}€W€€€€€3G€{%€>w€€b`tg€€f€€€€€€€€€ €€9€€qۡ€€€€€4>€'€Ó€~l€`€==€x
€.€1€S€2€Fpkfktc€€€ԸZ{[€zΟT>€€l̤€€P€Q€€V€€€wB{€W€€€€€€€€€€€€€2€€T€€€E€€=€I€Q€€€€,€_B€ƞ€€&D€€€ +€[1IV€s/0"€礮^J,gx)O€€(€€2œ€e€€`*€X5O^€h€€_€ c€W€a|€€;L€7€C€€9$€€|<=€t€E€>€:€€€SU€4*€,T€€€€€d€e€P€€R€€€€€e€€€€€T€€M€;%€vu€€P€€`€H€€G€€€€€€đ艣€5n8€€€€)Ž€€€xƢ€€€€€€€€p€hȹE€€€q€€H€ €;+WV€€€z€ؤ€€KE€€€€*=M€c€€€S€€7ֲz€€|€b*?€W€€$rD!WhY[€€€3€>€€y:€€I€€j€ +
€€le5y%€" +4r€׬<MtS€>XG€j4K€€ԵH€€€*€€€€€€@€*€3€ބ€}O)€€q€€e€ +]€€€5€€€u€h€s€€€|b€€ff9€€;%€E€€"€€=È>sÌŸ&fQ€€k8€%€€€*cm€q€ı€€A€ԟ€€ه€€€F€v€€Q:f€+<€P€€€P€Y€€€:€€€#U€<€€9€€€€€J€'€€1€H€€SA`€ȑ€~iE€3€Ao€€o€€€€€NC€"-€€€€€f
w€ƪ€€€#€Ps€!d€€€SW`€q€6 €R€€<€u€w€€€#€€]L€|€€€#TXI€߯!~Gc}€€>€€V]€€9mR€€HjPb€J€ϚU€€5€€€€܄€€€#€E€Vo€b€MNq€€€;€€€€€€€-)OT€}㥆ʀ9 +€2€@^€1€€6€? +€8€}M€€5€€€€v€€€/3€u6€€€#:"Gߧ`W'€b€v+€t€€e`€W€€€€趘€€€v€€?€€€]AbnC€€€€HTm*v&€V5€-€Kտ€€€€W€f€€%}d€e€€B}SR7€)g+€€4յ€€€(Y€T"€nf€€€€$L€€€€s€=?€v€€€€$€NjŌ2hj€€9€j€?_€€N}€M€e€€*6€,€€€€€Ê.{€€€€]€€€N€9€€bL[€MT4€€mm€€BE€9€€€0€k€€€~T€4ٞ€z€ɄY€D€;€€K"€bt€IA€7U{5xm€U€e€€€€m€€J{z€b€ʞ€F9%€ +€€€€X€€N€}€K€€€qj~+€Cw€b€˰€€k€€-€cs€€ꣾAo€€€~€€-€YRWY€€€j"€€uzW€€€€€€[v€€aw€i u€€;?€;€€€`€*€«D^€)€€/{€;€O€^€€J€€]€p%€G&€€€_€€5_ËšÔŠb€€&€
ə€#€€€€B€P€Iӱ€€s€#€Pf€€€Ѵ€€€€)c€€€#~i€€€x6Oc€€€€€€
€L€€A€€€ +M€€{€€M:€€:1€W€€€€1֑€€€I€€€v€AZ€]T€€6€c&€€€€#gQ€i€S€€€OW€€€€7F€€;€€€€gR€F0€7dz€€€€€€X€k~Qi€8€€€€€[€€1€T€L€€If"€q€€€g€R €€€\ǟʵ€€ €z€€€€k€k€€€€Y€€€C€XGj€g€€r€€€€iS€€#F€€KM€S€€tJ4€0€F€€鱗€e(ܓ€€~cÚ(€0€@$:€€L€M€€€;€€8o€P€€{€€€V€~&€€€TA€p_€ €€u€€€R€G€€l€i€€*€€U45}6{€Q€€ۇm€€<)hÙše€b9EvД€ €€€
€€€€€#€nx€k€€d€4€`€r7i€Ӥ€r0€€:€$€Y€€€€Mì½Nd€Lr€€€.€~M{€*RJW^€NU€€$€€€€€€m€€y€CD9=€b€€t€€YQ€€{е€"€€x€XNá„¥sa
€l5€:)J€€€:%€€€€€€€`
€€:€€c€€€€€Td€€l€€@xaʼn€`€€€€V-{i€€غ€€€l]€V€ȳY€€*€€€€^€€€j€€$€€7€Q€€M€€7€€&€€€€u-€€cÒQ€€_E֜9€I€€Uӄnh€;5€ n€LZ€€€€L;0€w2xe +o€€€i1u€€H€7k€Md€€€€€E6+€€=IS€h€#g€€€DW€€€€'€RQ€€€#€;€5€€ S.€6S€k€{]1€€^M€€€€€€€€€€€D€1€€€~&vB<€€Yi€N{€Cq}€t`# +Ԟ7€€5€€Ik(e5€7€q~€€Rf€€^€H6|€€€{`€|tˀ
€
$2€P€w)€e€Tzqh€€€f€ €x€€€9€€&€€€i€€€mA€`€J+€G&€€3€€€GtT€p€€€€€€YSE€€€€yC€\'&€=€^lM€YA€*€€$€€'€€U€z€€€>€^€h€6€y€iΨ€@€!€€H€'€€€j=qT€1€˚R€€€€:€€€€c€€€`{0€€]€€€F€€v€€€€€>€{€€€€€R€/€€~€=Tބ€€X€u€€z6€DZ€U€~€€C€{€:Rݘw€€€€o\€€T€€E€:€~ +7€ɷ€*O€€x€€bj LB_m
K€Ȍ€mƢ€r€Z€€€-€>}€€ €?dEJ4€(O€€€sK"€€€3€€'€€ku€/€r€€€y€€g€s}€Z€€€€0€€€z0€UBÑž`€€€€ã€€€mJ€€f€l€B€€€€€€€€U€€€_͘€€€T\€€€€dq`3u€€@€€Ç€€-€}w€€&€€X€€€€B€€€€€€€H€7€s€Ԛ€HP€€f× Â€Â€Â€Ô±Â€Â€lG€̨€H€€_€€€þ€GH€c€€€H€ €€€x֢€€€€^P€€i€K€€€€gʹ€^€€€€€-€LV@€€h€f€p3€TO€€)€€€뚦€€€r€1€€€h6r=€€A€€€€€Q€W€C€€ZD€s€^€€€€/,€€7^€€€U€€€€mU€€€€s€0€2a€O€€€ȓy€€€G€`€€/€€€€@5€e€p€G€]r€F€G€€€€€k5i€€€˧0'>€€=8F€7€€€\€]>€2P€€€€lyuUhz€€2mz€|€€€h€€€€€3€8€€r€cs"€b€€.)€V€T€€€€~€m€6K€€€4€SȀ€i€€ɿʀ€~p\€I€n€>Ƶt€€€l€R€|€x€€̯c€€€€€€€Iop/€€|€€€€€€€€€€€`€€*€xT€€є€€€€<€*€M€~€€€@€€ȑg€€€€YV]eP€!€€
l€iޡ€€$ֻ€€g€€M€Z,qbv€W€^,Yz€€J€€5€€c|€ty€€P€€€€€8̃€h€B€I€€€<}Ze€€ܬ€.€䨦€4W€€5€A5€Sf\IS€P€d`€€€€€j€dz€€€€€€€A€€€R{€€l€€€€H€6 €o €€$?k€&U€kDx€\yY_2€€~€91€*€#
€ÖÙ¨)o0y€E€€€€ +i*0€3C%€€?€4ô€O€€8Ҋ€€€€B€=€€€$^М€€T2€€p€xu€€z9G€€€€1n0ɷ€IR€qz€*o€€€€F€€em€€€€֨€€X€s.|€€x?€s€7P€€5€>€€s€Je€=€€<€€ €€:€’€€C€Eza€€€€3€od€<€€\€€
€€Sg]€?l€€€6€€€€€€€Q€v€€€Í€€o€€€€€€XvS€>€u`€J€ؘ€€€ €f€€jw&Z€€D€ݴD€€%€€€!h€€€_€€€€<€k€z€,S€€ +€€lmg€€V€€ €€ [€€€
€
€€쉰€€]€5€€€m€b?€mOr~€㗺€O€€€,ט€€€\€€K"€]€ن€€€€€€€d€|4#€e€€€v€i€շ€P€€O€2€€€€€€j€fWz€€e€kO!€e€€q€}€Rn€€€€w€=dTCÓ€€d€8€€€€€o€€€€€Q?€8€€k€~€€L€5[€€Z€€`€€hY€P€€€[€F[€€€€9€[€gg€€€€€€Yۓ5€€V€€€|€6€€"€q€€8€€€!>€U9€€{€€!u€V€g€<€€€€€c€€\€a€€e;€=`€€€€€Ėu€€1€€€€€€€}€€€D€gQyCG-€x<€xb€gQ€€€€A€G€u€ ǧQ
/G€~€€1g{"糨€F€€.€ €;€>1€€€
Ѩ€o6[€€EÍFup€b€\€Fտ€€€€€&@€ €gQ€€Q€€x€lU}€€hTÖ‰?€€€e€E€€F€€1.Ù·<y€€C€€€O€dk€€q€€;€P€€€ €x€>€€.€€Ѩ{€Յ€O€€€.€l€?€˲h€4M?€€€6}€€ml€€i€€D$Cq\Í Â€Â€5€€-€€€€`€€€€Y€Ʋ€hY€€)€'Yb€€4€_Lcs€ъ€dvд€€mM€Ä€€€&e:€€R€€€iL€|.€~-€7D`k€€Wn~€€€pz€€€€€€B€€h
€€€B[€&C/€i$N€X %€€€E€€€€€f€̣€)*A€@€Z€,F€B-€€Qٰ€p︱%XW€€€€€€>€-k.€€€$€€€€L€€€`€€+/y€€€€€€€y€€€t€C€>€Gn€€P€s]d~€
€€€€€HŴ€€lDL€€,L*€][#yz€l&€DM€€€l€
€€;€€'€€ZVc€Q'€h€€€!%cÂ€Â€Â€Â€Þ u€8 +€€€xw€€€€€"€€3€€=€€Ba+€€€€€M<€€€€/Ӝ€€€€€€o€€€4€€@€€]€9Xhn€€1€G€€]€xHvM€€3[€f€Ԛ€?o֦€€€€%€€ۜ-€lU€p€€€€€€f€Oh€?T€€Y€€€€x€€€ɿ€윺 €V€€€/€*F€t*E[P€€€€€';Ofʮ€€)€Gs€€€?€€c#\€€€€c€gu€(g€€ +S-€SB€€1€€€u€€ˣ€€<l€€€<€jE€€6€ر/€l€y€E|€e9€€|€-€€€}€tYZ€D€jd€€f€Z€€€&€&3;€r€€€
?/|€€€f€€€€€J€€€_r=€y€j€I€€€>€€€I€€€#O€€a€€B€€u€€
c€\€€L€;H€€n€8K€€[gP€]€€€€€I€€€€i€P$€k€€€€€€€€€€*]€€{f€€€`Q€€r;€€€€|4€€€€€eQ€*€x€lv€€€€Xm€€€€~`d€{$€€€€Z€€D㊲€€-x:€€€€*€8€€E€€€€z€V€}`€o۽H{4a3€j2€€ިK€N€€€1see%s9€€<€€QFw/s€€€|€CQ€€€Z€P
€€_€/uo€€€q;€€€€U€€+€`€P~€€€3€€€&€ß€)€Yg€mvs€yG€i€€€€€ɘ{.€€I)5€O€€€F4Z€€€"€€€€ZE€Ô€€€_9:€€/N€&€€€zX€€X€A€€€€€ €RX€€€€€"€{~€€€L€€?:>€@><€{€5<r€䉲X€€P€<WD€€€€€€s€€O€r€'Y€€~€:Z€?a€€€€>@.ͧ€g€€€€&Xf€%€€<yRSw"€€€2€€e€€€€Q€FZ€lMؗ€e€`c€|€€€€)€€+€€€€[&
€€€Șͬ€x€€-€€€€vI%€ulg€L€€dd€.A€€M€€m€€[€€€>xr€a[€#€€€g€€zLwb€€wV9q€gh€&€k€E|3€€`6€m}€l€On€ €€s€M€€€*eU3(€x€€€B€_€;6€€WL€€j~m€€W€*€R€^J€€g€€Kh{4€€€€€(€y'€X:ڳ16€Fߊq€?€€[13 ֗Dyk€€E€€xeo
€€Yƒ€ €W€Ϟ/€lcU€€€€€€F€C€p€L€€€€€\€tejv€€€€€.9€€Q{€$€€€m€€€a€€Χ€5€€„,€€Z=6€k(*ރ€T€(€rd^K#€€€€€|€€€€VǸ€R€A3€R€y€€69€€€€#<]2€ht€oS€€€€€w€=€
€€€=#€€ڜ€R€v€€€[_>€6€€?-€€h€-p.€ܱ~&€E€€<m€/€]€h€€€I^y&€€o€€&u€g€aw€x€\4V{€D€|.€€F€fÕ¢]€]v.€€qq&V€7€\€;+ի€€|€1y% €;4€€€g€8€ϴ€jI€€0&€€€ۘ* c€Ɖ_Ε€!g€€e€N€€€[€€y€€€'Gr €€l9€w€s.'€g€€€X;€€z€{€€|%N€€ c'€ +c€€L€ћ€€:X€€F€€€€€€ €€e€?€€€s€€"K€€€h€7€Lgy'a€€€€ +€€w€U€€€€€€€€€€=x€€€€O€€€€.*w€€<€}€s}=Uv%&N€|€9€€€_b€S|€€Vmw€€€*O€€€ƚ€ުr€€PQ\6€€}€ĥi^C€€€€&Ӵ€€_€LU€€€L€€€€€€€x~L]€€r€O€:JF!€€€€€=€€=€w$7€f€€€y9€€€€€Hۦ€o€€€l€€€€F€gz{:€€€€€€9€€Ӭ€€2€€€€€€Fo€€€€€\€€ӣ€€€lb{€€Mlc€m^s8€€€7€€€€€€€€3ٱ€€€v€€€€t€Ôs€U v?€€€€€y€€€V€ +ɧ€€€€v͈€€U€€\€€N€€+€?€€€b€[€ |)kâ½…k€€€X€3€oޚ€^€€>€;€9;V€P€€r€F€€<€€ޞÙ!€ȼ€€€|€€AÔ§G€€€€x€ٌ0W€q7€5RL?a|€vn͒ۘ€[q€mzA€FWuoġ€€€<O
ǫ€€/€€j€{€€C€€z€€€€€+7€€€?VY€€€;€Oy€€€€€+'€€€o؅€€H€€€€€'€€Ñ€s€7i€€z€€<€(€€zGzg€/zG€+€u_€€€ZSB€€{€ژ€€G€€€o€€€€y€€،€/€g€€€Z1€€€€€€€g€€}€€Dx€r€€!i4€g€€x€€m€ç·Â€Â€9€€~€€€€YK€z%7P€E€H><A€€G€CEK8+9€>h'€rD샤#€€^€€€€;€€€?Dsbm€j:€€~v€֕G€a€<A€zLn;€€€C€A€€%€ €€M€Ø€0€€€w€ޗi€€€A/€8€O[S€f€€Km€€7€€ݸƧ|€W€€4€€€dX€€€Ϟ€€y€€1€€q'€€€€€F6
Mä«|u€vo€i€€€€KÍ…=€Z€€€s€H><€C>3Ó‚p€€f€€^t€€€€g6€€€€C|€@€€€o=€€€€\y€v.W€€€5€@€`€'s4s€€€- €€€d€€z€€€€R/€κ€>€kjnli€€€.€#Y€€€o€#o €}O;€€D倱€iS€€€:€/€€h€€ߟ€D×—H€€DÒŽL€r€tKþd€/€}]€\€J€€€€€]'F_€b€'€€HZ€€wF€€€€x;€"€€€€˵
€€€‚€l€hg'8Y€Wmy€€"€l€.(!d€€€w+€̥€k€€~€€V)€v€€€j9€€Ҕ€€€€bx€€€.o€€€h€ +€k>€€*r4€M€€ê±i€€i€€t€€nj€€€3€[9+(€X€_€€e|€€G€€€x€€G€€€€p€€*€€7€€€€€€€#€W€€_€u€€€ €€~?€1€€+3€€6€€/
€w€|€S€o€€3€€q€€_Dv€U€2D~;_b€€€€G€€OVÓƒS~€€ع€ˣ€€€€€UY€w€€€€€c€6€/€€ݷ"€€4/P}€€€_€=€Ifj×侊m|€ €€€€€>€W€5#€yȕ€€x€€€ 3€€€jMW`€€g€w€€€d€€€€€2€~€€̸;ˆ€:Ø„<€g8€%€t1o€K€|€€€€€€=tE€y€€€€2ɹ€M€€€€Vmc€€€,€€€€€€.d€€€€€€ߗ€€€yc€%€€j€pd+Z;€6€€€€`L3q€€7⌖<€€٢ٶ€c€!ٖ€€C*€€€€o0€[LF€€€o€3Æ“o€€`€€Y
€q€&€€F€€€K0€M0-€€€g€€ER5aZ€F€€P€€€€g€ €8€€€bC€8€€`€&€€4 €]€€€`€S€€€€Ƹ8S€€d5€܂€ €z€!>€2AJ€!݌€ €M8€I€Z&€Åo€€€q6~6€€*}€"€€€)€`L€€€€€)qTj€€€€U2\@a€o€8Z€€€x€P€1€<€ +p€€€€s€€,( €P+€P€€i€ԫ€K€€€€€t€b€Rq€/FN€-€0Մ€HN€OMAq/€%lB7蹥€€€3€Ԋe6\>)A€x€€p€€3*€€f@7Y€xEc|€ €q€€€M4€,€€€$€Ohb€O€ €€€NAI€€L=€€MK1€0M{€%&iO€€i€AiiN€)€€''€Y'D€€z€/€+W/€`€_l€€YFc€€€€G€€ P"p€€f€?`
Ђ=€€€€G€€€A€€r-dL€€€&2€€f€€€g€€85ʖ€€_3ZR€€㸔$j€g€€€€€€€€€s{€E#€@%€€€D€€MgC€̓€,€&& €€h€j0$€![€VgS<€
€€DR€&([€p€&@r2€€,€(€€5€1_ €€'€%€z#€€^0€ +@ €€€€x-&= +B€G€€n%€ΖЀ€`3€€sw€€[me€I€€Ȅ€b€E€z€8ɕ€€=@_€Y€Z€€€8€b€€€€&€€€8€€Bd€YhA€€€/Å /py€€(F€3!)€*€Pc
€€H€€€$Y€€h€€€€€/Ō€€€)yZ€8_b€€€&'€9€6€m€)16[€€€€€@{O€€€€2€38'€%€/€ƕv€/€€€€€T0[%€R€€€€+€Czi€A#€ZU€ €€€€Ӫ€J€o€Z€€%No4€€T€€p€€€|K\€9€l€€2k€€ķ€g€€\5€k€Ȝv€cB€U)€€€€€€€9€M€"s€y€9ɜ€gN4O€œb€|€€€€€€L€€€€)=0€v€\s€€€<kFZ€bs€ds€ü€<€f€`+S€€€_€€xQ€_€€€s€€€€€J€€€+S€€€.1[&€-M€€a€%|€€4K~x}€b€€€€€€t€&e^€€Rs€%€xÕ¥l&E€/5_n€1€€;€I)€€KȪN'+€|Q€y€9€ƤͦL€€.€P€d€xaF€e€K€Y€^l€€l€€B€€q€`€€€"yo0ߊ€€€á—€ q%€
€$€y€€€o˻p€€€€€tK€o€€€€'€v€ +\ɊK#T€̬k€€*.€€UҺ2€ aqwZp€€Ô,w#€{~"<䶺€dӥ€uJjJ€/€Af€j؈[!-€€:Lb€2u€q€€€€€€€€€:€c><ff€€€{€€|€.€€€
€€€[|ǽp1#]clǵ€8€€n€€€€=ÔŠeit€€*@€€€+ί€2€€€?€€o=7€€˞€€p€[ޅ€!3€^€ɗ€€€W€€€€D€,€€€€6€€€m€€€Vd€ +ٛ€€€UI€€z-€wnw>€€€#W€€€€~9%€€€€#€€€u€J€€Ο=3}€˰€€€€€i€€€~€€y€€<€;€qKm€€tY€€.[XU€ZRZ€€€€U€€€€S€€€/€€N€€€€}€€€€€߆€Os€€€€€O€€€€€Ü€€ €s6€ӿ)€€€Ӳ.˾<gz€€+f^9€€f_5€€€€€-€€,q€_€€t€{€皲k€+*€€€€Y€€€€€}~€V€y€€€}€€-€nlm€€8€€ٵ€€57€€€€d€bϼ~€€€€€-nS€€€€@{€Bg€(r߸€€€€€ɟ8_€8EYL€€)t€€€€ޮ€€€€€)Jy;€€ml€jj€Pp€M€M€MpP€ x€>g€r€€€P€€ҡ€DA€O€h €€€y€t,€€hB€z€9€€€>€nh€€€
€y3b€!€€_g3e€nk€€€S:€ۚ€vG€667Q€v€v€-€.c€d€€5Z€€.\€€W€€€€spX€X3€€w2"€€€#€R2>*€M-8€€€k€cÀu€€R€€€2E€€D€Z€[V€2€€€€Z€€H,€€K'€\:E€€€nV€€\Y{
€€€=€9Wi€€7€tÞ¬4€ilnF!€€€3t€€€€€€* W}€€G€+€֤€€€<eʔ€€S€i€€ҩ€Bvmo€I€!j€€€Ϳq€;0€€ +As€€€u€)b€€€€L*€R€˦u\€9€€PmZ€€;)€^u6J€€U€€fIÂ€Â€í²’Â€MԌ€€€@S€€€€€P€€ۻ€€f€)€€€€J+€R߀€€€]€*€CMh€€€\€E\€p-€aw€;€€€€ǯ€$S~€kV€w")€€€:€*m7+€PPaЋTG€€i€
€Ŵ€<€€4aZ€D€t6€€g€€€€I<€€€{x€e Õ¯P€D€G€€€€)€/(€€€%=W~3€pN@€/PQ€nj€_€€X€q€€7€€€Rc4gI€}€€(Ղ€Յ€]€€€€O€€.}€€€n€F€€&3€c2€C€!q><€€v€o U{68 ճ€€$€S€€€€W{W1*€ä€€Ad€T€€\$€T€?€€w€€@€\€@Un€€?A€€!€R€;€ig \ €g€ €€€s€€€]€€€€€!Â€Â€Ø Â€>:(\E€J0#|€+5%€€€*€€€@sS €€€€k€€€€€+€€€€€PW}H€€ꫯT + + +€hV€€+€€€vFg€€`S€€@€€7 +p€€ €C1€€€
€H€<
1€€@€.€TVB€(T€K0MFe۩€€ €€0€Ãuwt€€N€€€€€sÑ‚Ä«; €:@ +q€q€$yb€€€€iM€n-€€€Ѵ€LL€:€н€Z€€€D€€!\€€Z€%€€J€€€€?€€dJS€€€_9V€€€^€€C<€€P€€€€0€€ +€5€€~€T>J1€€h€Cop€9€7M€;€cÆŒisaO!wL€4€xZGQѴ€€€aõ€,0€€€i€s€€-FVɊ€/F€€€€€\0€€€QA€€P€€€€€€4C€[LAr€Q€t€€€"€y€)?gB~€€€$€€€€"g€€DC€"q€€:8Bk€€<€€1,€s+€€ €€€€V{͇€€r2€k€€€ȬG€Gr€I€€€€€€"€ris€İM+€H€€uu=#Ĕ€€Z€€s€€(.*€>€ɹYY€€€€€€€€v€€€€€€^€"e€$)׶tt€Pm€y:€z>€€X€€E3€(€IT€(sI€€v€e-€S€ M"€€€9€€l€€}>€ +T4Ò+J*e€\_0€€€€€€y€y2€€j8€r€O€vvaƅ€€?€€83€€L=€€-1€€€€+€6v€rm}c€]€€€€€N€€Qj€€ €€€v€€€€€C[WkgK€ce€€€
€d€€€%6€€&`€lm!}€€H€€ g€I€€€€€O€8€k€g5?]vٳ€ÖF#€hbBx€\n/€€܀a2€€CM€*€<€JH
eB+W€€y€M€€€`F"€€€€4r€€€€$҇{IX.=w:E€~€€p"€[€[€€€a€€#€:€]T€o͞VW€ €€X7€ 4€ՈS€€€`iO€€8€-'€s$€AW€V€Uu'€€€€€0€€=I€€7T€€u[u€€€=<Q€w~E€ty^wPwH€€D€[R€8€q€ d;V}€n€.€.瓿€€n€€€€z*€€€L€~B€&€€€B=4J€€€€€.6€_€€)€€€'€€€o€s€€€€/€€iћ·€F€€$€€€I€5€€{€-x4S€lMǖ
#€€€3Xg €€m€MW€€3سq€ €&€€ͅ;Г€€s®V€€W€R€5M|9!€€(€g€€€n't€ €€€.€0]_(€€€A\€ /v€€Ng€€€[€i€](;€€A€8€n€€)ߧ€<R€\€9€€q€€€€<€€€€€€<€€€€~lS€€€qostT)v'€€€€€€€
€€€€€d€€mвNɺ€€€d€x€€X€//€€q€%nI€€€Fu€€&€Ϥ€€€k€€6€€/€€E]RF€€[;V€x]€G~]€Gu1>€˺l€ €G€yA#€b€%€6€U€€q
ǧ;*€:€€ZuL€€€QLF\€€€€gB€h€€"€j€€€€€€€j€€9€S€.€€Mb€€A€€€F€V€€T€€2€€€€5€€€Q^(G9€€€tfo€€€€G37<€9jh€€qcK{cgtK€€€€€v€€ψn€)€q€€€€gH€€€€*N^GnT&zQ€€€€ €€€€€r€€ṻ-w޿€L€€f€€€æžÂ€Â€pc}
6€€€U݀€G€N€€€€€€€€€O€?m€€€€€r1G|_€€^€€€€€€z€6G]€>€€{€€€€Q€€T€[eN€€wmɢ€"€Y€€t}'€€R€€8Cښ€R€€Κ€{<7˾€€€€€€€€€€R€€uSd€3€2E€k€;O€€€€€€€€€vrHi€€€m€€X<€U€€u1!H€€€->€}77S€€€€|€€€@€77€&koExKF䴒€€€"Ó£Sݸ(o€€€€Uz_€+€Q€€zL€p€'D84€iǣ€€b€€sE€&€'€€€̬€€€Ý€€۫~#€€€€€€€€.€P€⊅k"W€€€€Ñ€V€S݌€€€ԥk(€;€1Ú¡+6€€€tÅl=€փl}€€€€z€v€€€€€€€`U€[˯€ê€€€`€€Û€A€€:€M€l€M€׎JL€€€u)€U뒼€u€ކu€+֙€€€€t]€€j€€[€N€€€€€€€3z]€€€€€l€Bʀ3aç›Â€Â€Y€€€Z€€u€€€;€&€€ț +€d€OZ7€k€€ €~€&€€3x+€2VTC€€€P€€¤€-€€€qY$€d€€€€€}À%ZÓC@r€Yv]o]+€"Xnf^C[€€€€€i7l€€€€¼lK€*e€i;v€€>YÓ—'€ݨ€5z€€I€A€$€€€P€€€€€9€R€€€}'k€_€€]€€€uP€o€]€[€€€€€€H0R€x2z€€-r€"]€MJ€3O€w4€ҫ{[€=€€€1€/€€膺€€r€7Ǯ€%€H€sN0€ €€ €€ ਕ€€€L# €€€^jx'€€ 8.€€M€€h €€€}€€€_€#í±—Â€C€€€€D€.*w(]€€€pO€wr€€€€€{€€@€U€>€€€€€€.€€\€€ol€€1z€€EtO€-<€€€Dn€75h€n>[0€€€€€€U€om+€€€6€!ÚšE€g€€€'€I€;€€€-+A_{€ +€€y컌t=€^€H~O!}€ET%€4€€J\5€€€€|€€€vx€{6€€Zfv€€8x€=€€l€[€€9€€0€€:€5€€€k€€€d€Qߦ€o€€€€€:€l€€€I\yb€€h€ßT€€B€`19]y€€€8€
m€Cm€€ÏS€€€€€k'ß”}€1T€Bs€<أ͊€€€€٬h[€€g€€€€}n€€€+€€€>+€€-€€å›Â€;€lO€€M€€`qF€ޟ€R€€€葴[p€h@€€€Ø\€u?mޒ€€i€Ń{Q€€Ы€v€nE/=n7AG€€6€uG€€€z€€€l1€o"[€€/€!쯥7€€€J€q€€€.€_€o€€"€g€€€|€_€7€€€€g€6€c.|mfr<€?NH2€€€€C€€L€wX€J)€€€€€
€5w€€€€w,€€€]Dw_€€Iǥ`€€k€€l€€Gi€€€ €1A€pUq€€j[€€€€€€]€€€€{L€4\€€€+€€€€˸͊€ޔ%[€€€€€)€€€m€€€Ϣ€€Ћ€€1#6{s€O€€€nUBo,l\€€€€€€L€bU€€n€̴€€€<"Y€]uU€ €€€€€p]t€d6€W€*"€€€J€€lw€Qu-1%€]€€€€ +€!\€|
]=,o€%€€7€€€T€€€€<€W~€€€€MJ€€€W€€€U€€`[€D9E€J€O€€€"w€:€€€}€w€€@€20€€Vo€b€B7€hb€z€€na߳[
€ +€kq€€W€O€2€€€Q€t€-T€H€€3€€€€€€֨k€€wnuV€€z8€5t€q_I5:E
€N}€€€€€q€€T€*'O€l€€€€€j€][€/u€q€€,l€,€wI€Få»Â€Â€Â€Â€Â€Â€Ø¸Â€i€W€W€⢖€€€y"€€J€Gn€7P€€E€w€€F€€€€Z͸€€71*€zb€€€A€€ +€€`€€€$k€^)LT€cc€€-€€€€ĥNY€€€V€€q€€€Te;€z`Rw€]€€€€€€͌4'€*B€m€iomj1€€Ѣ€D€€|€€€"€`W^€€dO€€/€C~€€€€€€Ø€X€€€€!Hn\ €_€sݸl€€#€݆€€Ą€€€€€€oY€€€€D€€€€U€d€€€V€^€€€W€ozOO€.€€n€̈d%y€0€#K€g€€a€€׈€z€̂S€K۔@€N€t€€y€;€€€€D€€:€q€€$|€€€M€LvtX'&nK€€€ €€€€€og€2|(+€"Þ‰D€€€gP~€E€€$€€(€'€N唼?€€€QZc€€o€*€9€€x€€V0€t€W1M€-9€€€€1{€n€€€p+]`€mT€y€fG€€ +€
lPrC\€31T€DQsf\€€(€q| €(€:ӓោ€€C€€€€E>o€ӽ€[€[€i€€€€€-€<d5€€SOR€€y€o€b€€€d€}€€_a€€$q#€*€Ò]€€€wy€€€€€d€€r$€bl€€€€€z€"fS6X€9€€€€~J€€I`&€€@ף€€€€€ls€€bA€€€2€€€€€€۸7€^$€ +]€€'7€J4€e€oy€>;|€5€€j€€€€g€E€€Q€Sjx?P€F€€o/€+yA€`€€L€w.€€T݃-€=~€€K€€€€€$€z€&€€B0t€:€€€€€€€€€c€€eSM€PS€H=N€€€bx€
0bL€€€€€2€€€"훓€[€q€5g€€,€€€€G"0€€y€|€€5kk€€€€€AHRl€{€€sg€€'}€7€c€€m€€€;=:€€€€Ƃ€lrAjP€€€w€€Y€€fR]€T[e€€€b€€ O
€ €c€>€€€o€Ic€و=L€€€r76M€€€YkC€t€
n€V*€@Հ €V€€€B€Z€&Ot€T€€€St_€쀿€:L€€2€g€€€€$€m€z.€€€L€fV9V k,L;€€€€€_€€€€01"'u€€|€Q€€€B€+;€~l€9}€uT€€'r€/€
€"€Cu€€2€l€€:L,Cߘ€/ +€P€€̑Z€€€€€+€€€€€€€=5€ +€€"}0>v€/&€€€8(€€€€€h€€€€€ € ]€€€3€i€€1€€F10€€€€!€€G0€1R€€2F c€_€U,€€7hAu3G€
€c€€>€PN€€€€7€Y€€Ճ:€€€€€,RE"€€'nT€€)€6rs€$€To/€€€K€ +#€€&1{€€'€€€Z€€n€7€€€M€€{€€8O
{6a€€h€!€€€Z€€€€<€P€€€PN€տӡM~/y€F€€hL€€̂"€+€€U€È@˼X€8i€Nc€€d€e€<€Q€€€hg€&u€€6t€b)€€/€ph€€€€!m€€€€€D€€€!z€&ހf€CP€€€1€ba%I47]€F€€€€€€€㺀M€A€}Õ´b€H€€w€}ß·w}€€€€<€
v€€€Ñ€
€€g€i€€=€€?€€P€€W€lu/.[\€p€⒲€E€%55€2€w0€Ù€dP€z€€6l倀\€Ð€€Ux€6`€e€n^€€ς€€^€€€+O€€€€}
i€€V'€€€€Mb3B-Â€ÆºË Â€q€a>Ä·h€€8€€t€9)t€J
€€A€ €)€€V€Y€y€φm<ש€€BF€Ķ^\€vp€€k€€€€9j€€€€€^:€€7/€€H€|=€u€ƕ-&€€€€ 3€`€€L€}€€€E€bj
€pÞb€*5€€<€€€€j€È€vjh$2€6a€€€~:€Q€!KQ€ngq€xxΌ€€{€N€ +g€€€€v€€€€€€b€€C€Yq?˻€t8^€€€€€€€€"€€€S`€€;x9€€>€€€mf€€€€€€_€€€€|Û®?ɪS€^&€d€'€€€-€€€€€€€€€-€€€€€x'ԃ€?w,h€€€€fR}-€^n€¢€€"€v€k**^€€Jj€€y€NyE€€€B6€€4%€'ToÒ„j€€€c€jt€€x€€5Ŧ€è¶Æ’W€€%'€8€%'€€j€€#€6€%8|€s€€€m€€€øu€€€ €€[€ €o€€€gd€MB€€7€€6M€b2€€€dF€€€€€€€:€0€y(B€G8€€€€€€€n€€ET€€€€€}#€`€€€€€Ko€9€€Gs€ĈM€€€I€ +d|B€:€€s€o€€nA;€o Q€lNQȃ€€jǪ€€€€€€€Y€€€+€€€€€D€F€€€GU€y~K€€̄iv5b)€\B€b€.€owSc3cL€€€€€€€€€€€€€7)aT€(7€€Q€c€
\T;€€€~€€€äšÂ€Â€w%€€ڔ€€€€،€€€Fn€€€D€2&e::C€€€€7€q]<€€`€6€{€€57Ƣ€€€€€"€€Wc€€€€€`s%€€€p;€€.€Ke1€$€€F@E0€€€J€k€O€€€3 €€C=€K€€Ƕ€::€€`=պ€€€JR4€3R€€HÍN~T€€€€/7€ST{
€€Π€€rO€€€€€€€€€€M€+€a€€B8(/M€€ᶺ€€€h€g%€€€€€"$"o€€#€€7:€€Bo€€C€€€G€Dz€€+€€u€€rKs'€€BDOK€€G€€€L~€"€€";€€4s€.€€e4€^€€€i€€0H€€€€€€€>r€-€, €my€€€€:€I€€7],€€{RZ€€€€y€+t€c€€;=€€€€€€€F~SCK`e€€€€€$€€€1M€M
€ €€€€J€2Oa€€€€B{€€€;k€s€6^.€€€^€€€€up€`€€€€€|],>€J݆€€€y€@&ƙ€`€€-Y=R_€€€2 €€Y€€e€Kl€€€q€v€€€€€€€}€€غ{X€€€€€€€€€€€€€M€€a€€|[A€€€€^€€ +ڀ€€€€€3€€5€-€€pi€ €F€€P|€Z€llԯ€(qKက€9:%€€€€€ +€޷€g€€€€f%€€€€€€€€8Ò€g+€R€!'€&€€€{€q߉f_€€!Ò qŅ€q|€\ +€X€w€€€€]€Ã€€t€€)T?€$€€P€wY€nR€jeϼ)€€€p€€€€ŴM€M0>€€€€Ne€e>Ö£t;€€€€{S@KC€€e€€ũh€€+e_€€P€M€Y%€#n`€€'k€€C€€€€€€A€,€k€Iv€€ZqX€G€OY€€€35e€€€€p€q+€?€€€€€
€€lSP€Ó€%_avX€Az€€9€€%N€;€n4€ޕ٦€€€€v<€c)e€€€€€€€pe€€{c3€g€
l€g;Q€%€€RW€€5;€0€€$€€.€V4€€>€€ʖR]€N0€€€Z€€tms€ț€€€€€€invb€y~€WlzJ€€€€€0€(€ +;€2€€€
NE€v€€gZÞ²6€€€=d€/€€€/€€€u#€~(Ô†p€Q€€€L€K€%CӶ€€€xÒ€x€€K€h3b€€E€j€€ohtvL€n€€€E€y€͊eL€ɑ€˞€€b€̓€€€€€€€€)}=@kÖ€A€;QG€:€€XWg€€:o€€ĕF€€€€det.€€h€d`€90€€g`:V€S5€2n€€€€d\:w€€N€,€€[ i€:T€€E€€€ +€€€€}€U€€€9€€€1-€I€ز&pG€€5€€Ĉ€M€€€€€Ӗ€Dj€sx€€€
tvz€:€€€I€€€Hq€€N9€€€t€€V€~€g€E€€×q€H€S
€€€~.€€€t€U€€>0€H?mDZ`Z€€/
€€µW€€€€:€|€Q)ÊšS€l€€€õ€€€>M59aɷ€€5€6€€€€€€€Wi/,€3€€€gA€€€$€€€€€ +\[ O€#q€€€€:€€€D€€n€;€€€ c"€i€?WIen€€j€€€tu7€-€ۇ€%€€€ɬi€]€€ +€€N'ߌ€€€€€€€€T€XL€€€€N€€`€€€€4m€€€MJ€\€€€D남X€<€th€6G0€€(:€€'€€(4H€ €Ճ€€(С#€€€]€€$€OhaGI€W=_CuiR€ox=#€€ D(€€-€€€X@9€€F€€EO€ZR€o"€€h€€FY[€W€$.€€w€)f€€€_e'.€ +WÂ€í¹›Â€nWn€%€_€€v€€,I€s€/€G*€€€7€o€€n€€€Y€uS€@€€€€Md&€€d\€D€
I€dEC.\`€€€͆€€m4€€;€€j€ +&€ Q
€U^€€U€<€|€€€V_€-U€̈́€€\€€M€€€H€7€t{€€€"ى€TK€Õ€d€€Iֲ€##Kz€€€€F€€s€€ +h€=€€€€<€€K€ci€6϶€€€ +#€$€€€q€4€€_€6€€€ +€u€Pc€€€€C€€;€€€€6€~€5€€€0O€ 5€€{h€€mNF϶Vc(€H€n€\€€€ +Oo€J€€€n€€€sk€K€€€€€5€€€€€€€€€I€ÍÛ‰eC€€S€€Gb€w^]"€y?€€$8^€€$+€€Ҥ€*€€ǚ€€F€Oo€M!l€€q€o€slP€€V€€M€€g€€€€{c€p3€qs3€Q€€q6€P5€7b"C{€$*€o€hi€2€€€&€eO.€€x€€w€€€€/D6€€€€€€=€qe€€C€€_€€@€€€5€€aÌŸ^€€9€d€ɚ?€€9€€€j€D€6€'€€€€€?€M€>/|U€M@=0@G7H€€z')_€%€p€€€€[€Y€€:€6€€€€€ț€€€€pi€5Z]Ô&€K€Z€€b€€#V<€€€`€€€€€€€z!€}l€€€€`&€3€€6€zԅ€;?€I13?€€€i€S€€J€€€qd€p8€g€€€€€axE€€€!$W€€v€ѡoS<€==€k:€€€€€€pp€€r€lC€€€€IØœC3€€€;y€€ذ€Y0aGP€€m€€€Oؤe€€S
€Q€€i€€€€>€b$€€€åŒÂ€Û¤Â€Â€Â€`Þªq€€4€€:,€@'€€w€€€€0=p;€€€3€€+&€€yZ€€C€€€€~€€€€n€€V€V€ߋ)€€0€€€>€€€€€th€€€€€i=a€
|€&.€D€€€.€€#S€€h'Zщ&€b€€͛TMuA
€€U€€fA]ؾ€€|€€vK€€€J€€€€€v€%€j€€€€|F1k€t"€I€€HÞ†llY€€k€ €€]€5\€g=€\"€€€IF*,u€€€}J€;3€€z€€€sI€?+E€<€j€룪€€€A€€€nY€€8€€Xn€u€€+X€C€€,t}_€7%X€€^€W삾€€€€€€N€€R€H€€SL€/i€€€$.€€M€€€m€€€€€+€[-€Ys€i€|7€€€€€€€€€|߿€€€JG|i€]€u€:M€3€K€Ϙ€€€€#r€€€€M>\D€4€€XiS1€5€€j-€5€€W€€€R€Yׇ€€€d]€€€€ã‰Â€UU€€} /5x€€>€€€xY€} +/€x€€€€€2€,€>€€€6€rkwC€
€€RRK[I€]€€6€€F€€tq€€NƄ€€P€€€Ñ€‡6€
z3J€Ò:€€n +€€WCMp€€€2e€q€€]€€ד€F€€€€€t$€€kq€€#n<S€2>€€e€€r€€X€€€€€&\€k€€€€Ɩ€€€€rTvy$€€€€€PD6`[€€.;^|\€r|I€€1€€}€€€δ€H€€€€€qtI€€L€wܸjJ€€ǿ€_€€€,f€+t€2<L€€€T>€€€€€u\OY<?^p[i\ hE€+€%€€vR€€vz€ll3€€€<€a€}€€Wyg€€S€VG€ €tS€oC.€|C€*€‚Wz€0qV€€€Z€€@€U€€€€€M€€Z2h>B€€$€/€6€A€k€&Z€,€€c€3L€=€Mc&€/+T€
€€;€ܘW'`ߊ˛I€QV€€9€ +6\T`€J/€€L€SE|€€€€;6Ȼֿ4؎j9€
€Z\€€€݅mw€€€€B€X€€€y€€>4€€)j€€l€€€€€€s€e&ג*€I/€€€&%nA€'€€ €U€I€€ךL€€AO€VrD}€Q5€x€€€€€5€h€nG\UO€€€{€M€€€K€€€U[€,aR€€S€€€d€t€!€c€
€=f +iulWp1€T q0X€€€€€P€\B€0€€€j€€€{%€€€Ľ€D€€^€I͛€P-Dž€1€?€Þ€€€€€5€€`U€€ +€€€€€€€b€Gu€pY€€|€Sn€€^€<€;LعÄ€P€€Cȣ€€€€j̈E.c5€Bx5Ǽ€€€€.€'<€€€z€€q€Bc€B€€c-€€€€;€€3Df +€€STƨ€€€kLÄ°F€€0Vo8€€C€bA€€
€€gTO\€+.€€L€€€:]€v€€€€~€€€g€€€€€x_€;€€€€e_€€.i€Nny€€€Ý€€>^€€lX€€i;€€€€1€€ U€€8€ZLRN€R'#Vo€ !#€P€\2€PF€€€=€OcE^€7{€€€€ן€€€€€h€&t€q€€k€€€€ 7C€nl€€€3;€€D€€˒€€'€¦€vS€٫€€€€€€á€€WZ€€€€)€Z€€€€j€€€€€9€€€€k€€]Z€z%EXÓ¥+1͸€j€$€€0€Q€"€Y€T€ZP[lƣ€_A€ 50€€v
v"€֣@9€€{4v€5€z€€& €Uu€€6m'€1eï ¬Â€.€5€€6€€ƥ€€Y€€€g€€€i€€€ݪS€€€€€4i#6€7€€€€6P€л€C4y(€I€€€€z€u€6/g€{€€€pF€`€€R€Ú€Ci€€ȓ€€€€SL€€^€k€7€€e?6*€/€AA€€€€€€@€p퇼€9€$B<€Qv€p€dRÚ“2$€&€җ<8€T\€$€€s€€|€€-€€€#€€€;€07g€f€€€€€€€"€€€€€w€>€€W€€+€€u€|€€€€N`€H'€€S€€€Nw޻€€:O€€}€tN€JÌ¥C€€€1]€€%€ٸ€r!€€€€Zȃ!-€y$€7€€€Iu€€€CB€|u+m=v€z€€€€z€€€I€€TUCĘ5€b€Ba€9 €g€€€€G€K€€a€€€€€ß~€€ۻ€ƺ?€,~€€o€€€€߾€oX€e Ķ€m€7:lJ€[€€~~€€€€€€€€Í€ow€I%€€"€€€l=€7켧€~+€€>~€€ow€€€€
wS€€€€v7€I€€6~{\_UaZ€O€€˛ZSMP€€€ozl€ay1€€j>€oF€€€/€€€8€])€€c~3€+€€}€f€S€3€€d€r挆€€€€ e}€xm}K€\]R€€l€€<€€€c€€iqy€€€€q€%.5W€,€€8؋+€
cweavee.SYMMM]>6€€_€€€€MPSTMPS €N€€€€4€€€€Ir€€ €€km€ir€i'€€€&€€€€€6€(€|íº¼Â€Â€Â€r€€~€n€€6€€€3€€/37€+€€y€A€
€Np'€€.€€~B€]€€€€p€€m€€€r€l€8€€€€\8€w€p€c€m€]€yf +€€€€}€y€€Xg€<߬]€€@€6#8z€o~/€?€B€€x€D€€-/kU€-S€:UW€Rh€€€€€ €˿€ә€€jm\€€€^qiUM-~!€€C€€€€cQѿ{*€9€€
€€`€;E€€€€€€G€€€/j˺D€RY€W€eW€+€€!€J€0€€tQ[pH,.\€€r€€ÂLU€[=€,
€€{€€B UT,€bhϲJG€€Wl€€|U€€ €€+€€€{v€€x€€|/pX4€E€m€nGN€m€€e€€€€ls€€€M€m€L€€€?3€Q€-/V€€€€O€€€€€€€:.CW€€e€V€_^€<€€+f€€€€€<€@€€ +€ц:€C€=€?ױ€€Rԑ€:tDL€Rǥ€€€€εT€€€_€€sy"_€n€€F€~€€€€:€n€€f€€QB€€n1€€€o€€€€XX€E?€€€€7€m€€€€:€€€€€}€€#€€€€€€€[7U€.S€€€€€€€€{€€=$€€€€w€€=_€€߻€€€€~€€€€w€>€m€€€€W€ūq€d€{€€€I~'€u'€&€*€€€8€}€€€€€€m€[o€߆r€€B~€€|€w€€ˑ€q+€w€^€€€o€Q~'<-€S*€€€€€€;5Y€v€€€€6€€€€~€R€€€€W€T<€w€€€%€€-€€&€€N€{€€€€0€€€€#€€€€€g€€a@~[€€€qu€€n€€€~_€€€€€€€`€€€€W€Í€;€OX€k€7wo€€?\€€(*޺€€€nO&t€€€/|€€[€m€~€€]€€€€€€€A€€i€uD€(€€\€0vn€6€€€€zк5KY+€€Dw€€€€€44€€4t€4€{z}e€€
x€€€M€'C9_€/}€€€"@€€€}€€€€€€€nkhnlnk%Jm€€,€€€?€€€6€w5€Դz€㬾€€€p`(.€€-€v͘€€€w€€€-€~f€€€>€a>%€€€ €x%€b€€{€pv€€^<|€(€W€€€p€€€×€€€u€*€€7€nm€€€w€€~{€€€\!€C(
€€j<€€€x€€= v€€~]:€€p7€.J)€€/n€€€!€€€€]F|=\€€I€€€€€X€.€@垢€{€T-u}5Oj€€€::|€=h"€€€€€€€€€rM-€)NiF€€€€z€G€)\,k€€V€i(o€€6€q\v€€€2na[c€W€€o€uT€€€xM{OmWM[kG€€€€ktSd€€€€€€w€*€7 +րB€€€€€d)vʷ€€€€€3€€€]€€:€€m€€€c€"L€ȕZT(2Qڀ*€e€ €Ku€Q΢s€€€siqb€€v(€mqÎУ€ڲ€է€\@n€T€Fk{€!€€|€€€ +€y€€€ji€€€P&€'€€j€€€< €m€€t€6€€I€v€H/€d;€€W€€6€!Û‚xœ€x€m2€€€[&r9€€€"T€€`n€z€€€€€7;
zx€'€€r€€€]&z_€€€€€€t€A8g&€.8€'VS€:Ĝԟ€?0L€T€(€€3€€צT€G€€€€S€€€n€&€g€}3QHow€0€Ɔ9€€€€€`€€l€€€0o64€€€[€A<`€€r€€€€€E5€O_w/0€Z€€€€<v€€€€TQ^p€=€€F;€€€€€6€0€/€R€
֪€C`€€€€]€€xU€JZ€*kU0€4 €€Wt€€ |4€b€€€z€(#€#€€2q~k€X€€€€_€K߅€$=!€`XK]v0€€+*€ €€Ľ[€€ǹ€€*DQGyл€؆€bw€€€Z€r€]>€€0€p€€€€€=€ì€ȳ€EY€3V€й€€w €H'€€€$€qME€Þ€€€t€5€€zߤ{€€/K64w€€€€ [€'ne€% Ì€€d€$7Z€-€€?€€緺^€€>[:€Z€[;€€{(€nJ€€€ؤ€€€€L€
€;Ý Â€d7(
[€V€€~€€€€zv€59€(˩€€p€K€€€*€ Þ±B€X€€v€€P=€€2y€w€l[€]V€zO€KWq€Ͳ€€€€€?€€€>2nչ€w€JT€€€€d€€X|Z€<€+,"}€€B€€€€Ri€€€€€€€€€U_€€€(^A€H€€ +€€€DNY€€U€M8u€Zk€ٓ):{€ȫ€2€P€€*Dq"€€L+€[c€-€€€€ɑ€9€2W€€5€€€€€€€€€€"ã·¦S$0€€€€€"€€€€: +€.B6e€B€W€Ju€€I€t€€g€€€2€,€€F€b9*v$€x€@v1€€€€",#€€€€€"€:€€€€€€*4€Fw_Xv€€|€'€D€€`II€|€€_·E€€p€H-(€€.€,€ٱ€€€€€€pk€7]HU|€X€€€€|YAp+W€I€€€€€G€G€]\~q€€2€€r6€€*+(€€€"€€€,€€G€€€6i€f€Z[bE€€€€€€€+eu€WbV€€€5.~€¡'J€€9Z€€€€€9€€€€,€€|€€\?\yM€rÕ€G€€€€€€€/Ǔ€€€`~€s€€€WT€€eÙˆz€€€€€€d€€€€€€[€(€K€€:€"[€k€€V6€\€€€€€€}u€j|€€€]€€€€€€%]q€€€(€€wUS€u€=€€]€€I€€c'}€u€€€5€€ӹ6f€€o€€€€Pv€€v€jaq€€.€m€€€€.t€D€|€ +€,€☯+D€:€€€€ͷ€;>€3W€<o€G3€&8€€€tO€€~Q€dž€€€DD€€@€€Qu€.Â€Â€Â€Â€Â€Öºæ¢ Â€fo€ts€€€€€€€€['€€€6!€p€€]€€CO€€맢€Ҳ€€(€€€€[€T€ €ACJ€^g2c,€Pn€€€[W€%€€€€€$€zТ€€€/ٮ€z]ag!k€€{€€2tk€€!€0.€n.€u€€€y⮸.~Ú¶[€,dY€@€€€E€€€ۙ€€€IÉ»l:€€€w+€5v+9€€.FQm€l€€€€€ +€d€l.€
€€e€€e6€<€u€,+M€"€€#{7€€4Ê aI92Q€}n€&€l€€€'€€-J€m€]€dk€€S€]^€€€Î€€€$~€(€T€ԗ€€;J=u€€€€€€W€€T\W€€s +g<€€'€€D€€€m€ +€€€€ZWT<tƽZ€{֢ƞF€€€€€€€Ѿ€€€€˫€€;Z[€€€€€€€€€o€yn+|G€€€۔€€ +€€€e€€{Dz[ +€€€]€€€€€;J€/dw&€€€o€€D€€€]&|€€Z€;€€>€€cWv€mE€7€ճ€€€v€<Tt€€€€c€=8€€7€op€€€€"€p€*@UJB€€/€Qq;EW'€呀w€€1€€€C€€€€€w_€€sqcC€B€€€@€€€1ž€€O€€%Æ·j]€k€.5€€C€€ €€s3€۩>€*€€~B€€2€C€€€H€|y€€z€€€€€TWYÕ€€€*)€tx€7€O1_€€o€€€7€H 7U€&T€€€€(€€G€€€€€€€€/(鹨€€€g€c€]B€[A+Û…~ۮ4€,€n€€€€Ҭ[.€Zr€;€€€X€€€r€€U€€g_€€€€A€€€€€O-<k€€€o€€€E`}v€s€;€€[P€€€?€A€€€€€r€€€۔€€5€€€€$€|€€€€€R€V7:ppG€€ZXLT]€Swg]e€€f#Þ£\€€€D€AEËŠW€€€ȫiPy€4€g€!€€€Z€€€€u€u€€;€€e +E€Ң€€€€`€W€€€€€€€ԙ€€L7€€€x}€f€m€z€:&۬€€€]€Uf€€€C€d.€Q€€x€€€€pUo~h€€ݴ€'€G€€e€€€n€€P]€€O€;€-z€m€Z€€K€€€D!€€€€€v +€[^€K_]€Lu(€€€€Rw€€v€€€€€A€pL€V/€\U]c*q€cT€€T€^ۊ€5€€J€t€€€€€€cTj+€\QN1_~€u€Q0€€9€€€€€|€€€M€€€U€€-R€€€€*€€€€4w €Uv!վ€k€€€€2€€2€€€€€€R€€€€€^d0"€z4n€:x€€o€€^j€k€ +€O€2GÏsX€€€€+z€€U€€
€€\bqE€€
€.€W€€€€€Z€(€€€€(€€z€s€€Q€,ugf€€RG€'n€_8€h€€a|g€ €+z€%
sE€ί€€€~€J€Sښ€L€7;>€€€€€€)€|
€ľܬ€Y€€A€€€€ O€€€€€P%]€X€€€€7Ø€€?ݖ€€€6€+}€€P€^€2€€€z3€€&€€€/€i€€C€pkÉa€€€€€ihq€:€€€€€€€m€,LtT€<€€ާ€>€d€€}€€€uL€3€€*€€€€b٥€?(/€€€€.€€QU€(:€A€tY€€€
€2€€.heE€g`AQ€€+€€€5D€€ s€€"3€€€2€|€&w€1S5€`€(€ €€цNc \€d€BO€`€~_E€J€-ßµHL€€Z€€€VM€./]Z^ZV€€€€€€ +€/2@€c€l€€€€{€ex€Y€€\{€€e€P€€P€w€€JO€€sđ€>€<€€Fb€kɵ€Û€D9\€€€ª€B€€iU€kÏ€€ҕ[d€I€y€€€[€€2-\V]sQʽ[s€s€€€€€e€€€€€Ò€€Ҫ/Yn€€€€€€€p€f€m€€€}€<'€€=€€€€€€€#€ϔ€€s€\€€\֥€1€W&€ٿ€€¤m€U€€€*
EY€]^c€€G<€Y€€z€Y€QR€€C€€€€XJ_O;€t€€W|n€(€OWU€€€P|B1€2€8€^€€Ӷ€|€83€2ʻ€€P€po€tx7פ€W6"€€/€€!3d€€k2€€(€€6€€€€€€€O€u_€/€€€€€€A77€€€w!o~€ €€_€"t€€-€€!€€@€q_€€<€€€v^€,U€€€}€€1€k€€€!€z9€n€€!€ᬻ}€ѻ€^€>WU€ZÄ™vqS€€T€DZ€E€€G€ UHo€€€'€€€€€qcsWgg€€€<$M[&€€`€€.✓€=€€~€cv€€€ċԯ€€€€€€]€€:€€€€>€Sv€€€$#€JY€7Í€€y{€€a€IY%€€$€Wm6g€eU{}€3PWY |€€QaŽ€€€e€€€{€€€€€9v#:€p€€~€€{€€€€QFw€€€e€€f
€v€€€€€€f€4€
€€)€ €€'€1€€€€_€€B€€2€€LNu€p€€)€€€56=cK€q~€€€I€€€€€0Jj€€€€€o)}c€l€Vt€v~M€ܨRC€
€`]€o
€{ +|W€w€o-€€€hFo€€€o€;H€m€o~(€\€€jϓJ€€€€)[€€€€€i€€R€€€€€€€€WaG€w}€€€ֆ€€ֆf̔yZ€z€n,€€€c€€I€€zA€€S@€ۓ€€O€{€MB_€€j€J€€)€€H€9i֊€€1?€€B~?€лH3sz€€l€vq€;€€€E€€%€s[€C€€€ݛ€€s"Yׅ€€O€€€g€€€€€€€€€̗€€vn€€€€h€€€€.€dG€€€€€€€0[€{W€€€€hQ€€€ڳ€€€€9IV€b'€€tgp€€€j€ޫ€€€€>g
€9Q€€N€€€€€"pB€1€€c&€€xđR€.q€{€€݄€€€U*€€€&€€€a-C}+{)€€*€J€€€€O€€€ҔW€-€€€G€€€W€Q柊€97K€€€Gs€€€M~1
3€`_€}i€€€ +ʗ<€t€€+.€Vr|漯€€1L€€€€€7bÀ€s€K9€u€+ٲ3d]€tB€€€~F㙇€€&€€+€R6:€z"€€€W€"N€W€€€\€P=€o€€{4€€€g|€€€€€€€€_€T€_D€Seh=dha€€€FE€€€_€OӿJ|~€:€S€€V€€>f€B€€y€Tz]m€JϢ€€(€w€b€<U;('!ԓ€>€€C€€ +€€Rmk€€€€!тޔ +€€0.+wru€€€€{s€€ +86€€€[,ޞV߲€€€p€€dF€€€€9€€€r€€8€€€W€€6(€€/€€€5€<8€k +€rG€€€l€€€€€€€€€€€€€)M€D€I€`c
c€~€!€X!w€€Ú- +€SÞž9€€Jgl<€;}_p0€*€q
O€q€€€k€€€€€€€E€€$€>w|]10€€€L
€v€{C€€}q€€€ € €€y€0€€€€*€{@
@€C€€€P€C0ێ€ZT€€€5€2€€W€-_^ȋ€€=€€U€€€€€€<€OS>€€<xR€-T€€€'€€€€€€€^€l€€€€:€媪€0€€€I€7P€€wr€€2b€oj€&€ԗ€x€H€R"€q]e€€€*€€€<8"€mGW€€€#€€NU:r€V€s€€!S€cՂʑ€k€€€;€€*€€€mh€p
€6(f€H€€qnpe€:(€€)€€z€€8€€_R€"H€€vH€%f€€€€€z-€€€4€€€:
r€6€n€€÷€[€^€|€"x€€€€€ €€H€€€€€6€Jj€€+Y€€€€c€E€!m€€Ír89€€ €€€H€yG3€€w8€D€€W€€€€i*\/'Ò°4€€€W€q
€€>€€€V€€€€€[€(€€b€€€dq"C€€€€串€€€ߋB€S€€€ ~''e€w€h€€€ €}SOQT|€`F.€€[€N]€o€5Юu€%€lq€€€€€€€+Ù¿_æ ¯*€l€7€{ù€€€€”U€€€€€€;€
€€€3L€€€€€5€€ڕx€;E€€Zh~As€€€€>g$€€€€€K8€€W
€€-€٬e)#€€€€_€ۑ€€€€€"€_X€CE€€,€t.€[€€€€ €€€,wC€€#€€€xL €SNI€€€H€Ο€€€€ș€€€t€€€3€a€h€dž€Bx€:€-€€€Z€Vʛ;€€A€6UG2CsLC€:€€€9n€W€€\Œ=A€W€G(€€€€€Nt1€€@wq€€€T€€R€€€€€€€€`V]€€9=€@€€4(€e%€€[€€€K€)€€Y€_€4i/€oue*€€€ɩ€
€€€€€n6M|7R€€€Q]€'O5€€€Y€`V&€€2€u`€€€€€F€€€€€€€€€j€|[€€s€x€&€€dG€€€€€€€€C€€v€Ôn€&
j€pov3wQ€€€LKw€€€A€€€€€Lm€Y}€€€+6€UE€rK€€€€\€€€M€€ €€€€8K€_€€ +M7€(€€€€[:€€VIU"'€inf€€€ϗ3Hp€€€g [a*€&`€€}€€%bv9fj€€9q5vO2~-.€€+_W€bu€e<€€f€U€€€€€€-7€z€(4€VB€€€UGE€T€€€+T€€R6€€€€t€>€€b€*€€[L€€R<€R€;€"0€se€€€4€€€€R€9-€{77\€€D{z€;Õʞ€€r€€ +€€`€o€Ou€d€nUS€€€q€€L3€€€e€€ €€€u€Uy€€T€€f€€€c>P€€Βs€€-€€V€Mܯח-€@€€€!€€G@€ވ€€M˨€€€€i€€6€S€€\€J€u€€.€€€€€€€t€€€*€€€€€zI€Q€ €€€€bᚻ}M€€B\`!€KO€Շ€€1-€€>;€c?x€K=7€j5U€€8(€ܚWl€€_€€€€€€€€€j€€€wn€€€y€?x€5'€A!€?€€&w€hp€-€€€)'€<G€'%€€€€
€€€€€hG€€€I€t€̹€0m@x€r€(ʬ8$€2€€J-.€Û€z€P€/F€€€_"}€O€€€-€o€€€€€3€"H|*i€€'€~€€m€z<y4€€€€€€€€€1€€5Ò¯e}€€€ք€f€"€E)8<€€€€4€€€€}€€€€"Wf€*ET€^€€€S-€S€j€ʵ€z€€€€€€0Ë°`Ǭ`€cLƳߤe€9€;R€S€/qe€€€3€:n€B_€€€JK€€€€€h*€Q€€N,€€€€a9€G€€€k
€€€T€€*€€€€€M߇€;P€€€€{€t€_€€*'€€€€q€€iA€m(€J€€€€€€ +€r#€H_F€€G€€€kÛ³u€€€€€gG^€y}b$€c4#[674€:fR€"€€b€K€€€b6€€ZLÇ—^\€€A€€€Z€uX,€/7€€€€€€€_€€€_€D-€€k€€€×€€€b|€€€€€€J|}J€€€I€_& +€€C1_€:|€H€€
1_o€€€€—U€€W€€€€!1€€€寢3;€]€€€/L€*€ࡹ€€窹<ϰ3s€€€^€i€!&€€N€t=€€€!s=€T€€iR€HU€€?׀€J€€&€ƾ€€€4%l€:€D4ު*€Ρ€€€€€s€€.€q€€b€€€€Eb֨1€€€&b€Ԙ€#1€€"fQ$€€€€€€cq€D=<I3€n€h=O€€€€8€[€Y€yj€€g&j€9\€,€ļ€€,€€€|€(€O€€€G4€€z5€B1€€€z~€€ƔFbR€€€Ì€y€ +1€Dbr'j€€€h€p€D€5€€;Óh€<C€€U€k€G€R€@€€4m€€€w€D!€€jqW€€€€bweꖾ€€&"2€+f€€€AN€#€͖>€&€€€€;€b€ +€€€€€헚9€X€€€L€1<€߽SU€€€0€€ًk/S€z`€.€€€€v8α€€}€5€TL\€[€^€|)<€€=V€9G€.€€€*€€€€€SnI€f€M`X€€+p g m€j€*py€€€€aR5S€€m€€€#€€%€€9€uR€ױʮ€€€y +€S]€q#€€/€€€`gE€x0€€2€`€€€6€€€*€}€]€Sۃ€€€€€€Y€S€€€*€,€€]"€€€Oh€r€€€€€5p€"€ 9y€
,U+!€&w€€€€Ƌ4€)€€€t€Z€y€e?Ü;€W€/€i€h~$O`?€V€€€€€n€r&#€3€Ì€€€€]l€ņ€-€b*€€6mjD€€€€^ͱ€€€€€%R=C€L€€1@€€€s€j€€cȘռֳ€y€€4€€\€€%€€€D€E€€H€€X2€d8€€€J€x4€€I€U€€ēF1€€h[€€,=^e*o€R'€€r€޶[€€@XwC'-€€nT€€^1IXιdxV-€h€|€B+€€€p9M€9€€9€€;Cy€€€€53O€ܬ€NNr%€z×Ά€€J;/R€8YC€€€s€€€€€€Rto€€€€{U€€€M€€ "€"€@€;€\€?D&4€I€hߎ"€1€€€€€€j€€=€€€€p€c€j[€B€€E€ oc€€0nز€€^€w€€ug€©€€€C€/€p€W€€"€U69€M2o€:€ڞ`S€5€݄56€%€8D€g€nj}€€€4u€€A€0B-€ujH€%€€J€€€€€7>€ +€€€s€€Cy€5K€€T€€€i€;O€€d€€
-j&€ ?€€W€=yf€F:a,€€€€O€xR€€V€?W€N€€KX_€t€€#€€€€€-<€[€€X|QG€O€"€€€€X6€€
Ւ€€w€€€€R€€€]€3Í¡n€€€€&€B€3€˨'€€€3€{(Κ}€Ygx,€€N €€€J€€€€€€€€Է;0€€€€ €€€€Bۗ€*€#٠€c€€0g,€€€P4€fy&€€€€€€;€€#€€€€Z€€€€1{€w€€€cՔ€€]€€€M€€€x€€Ywo€€<w€q6€€c€#vx€f <T€ԣ€€ٵR€€z7€€0€€ €2€€XT€f€X€€D0.T€€m€€C€€€€€€€Y(€€€7b7€€€U8{z€D€€T€€€l Fz€%b_R€€€€Y9€€€~€€ۖ€€€/cz/€#b€]€W€|€€<€€€€K<+€€€o^€{€)€ag,€€€0m;o0O€€€w€8Ò¶@S€ӿN€€#€€€€e€(r€b€x€€@[X€€[€€T€€€_€€0Gս͒CÔ*a€€€ €=€€€ē?R€>€UÚ°[Õ²>€@g~€%#j€"€T€€d€G€?jL€n€€Ur€B€#€j€NUcJÜ–Z€€ք€:€€5€€x^€pqUW€c€€€€€€
€D`€̷€€a€€ë¶W+€164€,P:€*€#s€€s€€€€~$g)€€€Pa€€€'O€€J€u~>€t ts€u€Qϙ€GEM€J€'€ €h+€\M€$€€rZ€t€€C€€€€>P€q€IBo%€€E€€€€y~D€H€€€V€€0€€€€F`a*€8€c€€"€aEH€'€a€/€€f€€
Ú¾U€€€€€€{€€P€€h€G0€€€ӯ€@€€€+€€€€€)€€v€€B€€{óC*BC€€3€€[ +€€…€€€y5€n>€T€€}€€+]+€€=€O_ʱK€͒i'€8I[/B€€h€€(O€+#m€€)€DŽ€Ob€2€}€pH €€€i!€€ k[€m€+€€R€€€€^€ٗ€BI\€8€ү€.W€!€€f4€€u +€€J€w"€€ڵ€Bo€ݷ€D€€%€N@_dž€&€€G€=€|€'€€€€D€]È·~"{€€€/€€€€[€&€€€€o€D>€€€€€€€&€€€€€=:€€€€L€€€€<€O€€€YC€€€€ʉlr€€h€G]E€€9€€€€Ko3c€€`€€€€!o€€€€`€T€=€€€€7xO€W€€€€\puZ5G€€€iF€€ϳ΃€€fB€׈€€*€Yް€€€€T€C€€€y^*€Z;€€€R€€€€(€*-€€T€€ +€€f€)nv€€;B^€€\Wh€€€€æºF[€€€€€|€€€j€€ke€Zn€;€Px€?3T€nR€c€€€/€€€'€]€x+*€-€€€€(€H€€R€€Aw€X€€B_€)€€€€€~€€€^m8€n€€€ +x€€€S€KuC€€€€€€€ZQOJV[dD€J€€+€y€p€€g€n€€ޗl€t€`€€V€€€P€€ t€m€€>€l_1€=k€€€€x€#O€€€J€€€rw€;€€€O"€TB€€k€M7QT$"#€;€€€€aNs€€<€5/€
_1ȓ€€,€€€̅%€ +€€
€c€>Â€Ì mϹ€€€€€€€Ek€ԩx€€€]€"€n-€€€T€€<€g€[€ +€~€ʹ€€x€€M€€[<€v€x€€Vc~)€€"-€€*4€€F2c€.ª€€€€^€€'€€€€l€a€€€€N€(Q>€ѯ€€^lB€€€7O€€€€€€22€€€€€$mзa€€Q€€€€0#~€-€€ €€l€W%€q€€€Eo€r`gttÊg€€i€€ٶv8€€J";€JF6Xig€{€€p€€I€@3h줾€nK{ε€'N€€r€^€€3€<-€[s€Y€€€€d*6qE€€€i€B€/€:C€-Ll"T€€€€€€€€9L€9€I€€€,€€€€€Q€€€Bޓ€$l?O€€€€x:u€;€>€€m€€€i€€kk~5€7€@_€€T
G€€Iâ”±5[€[M€€€3€€€€q5B2€€_u3o€€f€€€alG+€€Õ€€€€€€!€t?z_ØŸb€€€9€€€{f_(@q€f€k€€€)nË€r€p€€$XÒ–OH€€P_€€P€F€8€€?K€€€€=€€R0+€€€€k€G€€€€l€€$n€M€`€€QN)€€r€Q#€€€3€3€4€€/€€€€€€}P#€_gd€-u<€€€€€e€0bO1k€€€€YK€Ì4({€€€€€]y€f)P€#TL€Q€€€€€€€€[€€€€€€r€€Ep€S="€>B8Gxk€€M€€€U
€€€€)ڥ€€`A€36K€€€€-?€/€€€l€€kf9v€€Z€'€€ +=€60€€€G€ə€ +W€€߷€€kpq€€€€€ָB郌€Ͽ€c€9$c€,€lL€\€€€€`€€A€€r€0€Ѐ€€€;_€€€€J€]€/€€€€O7€€€7jwh€2€h3€{€|€9€€€€A.€4€eb€€]€r€€&B€G€-PBÈ€ڬMٌ€€x€H€€€y&4€@€.€OLOC]€Oo€.æx AO€€,Ö‚_€€€€€4€€€v€€#W6€€€3€w€c#€€Ov€
€]€€Gæ±µm:me€€€2€€ay€;<€€3€c€{d€€mV€/€Í€€ _€n€€"
"s€€2€€<v€€€€6€€€78€O€€vt€ۆ€€€K€€€n€€€€€'€€-oq€€ €€I€€€€!ֶ€€€€€€f€RHű€-€1€€/€^D|€Ωf€€q€O)€€€΀w7]t€€€7ӆ€X€€€iB€€\I€€.€?:]€€€ +c8€96_.Ğ€€€€s€€€€€€3fG€€€&Ç‘#€t€8o€;€&€€€ͼ€€_h€€€€€€D€6Sq€S€€&€1€*v€€r€€8€€€€3€꼀Z)€Cf€€=€€Z€€M€@€ +q€€s +€€@€Þ€H1V!\ܬI€€z:R€(s€'€€€€
>€€€€>€€?€^?€€€x€€€€€€'€€€%Zi€-s€
^6|€€€€€€bO€€l€T€€€V€ո€€~€€€/€€u&]€._W€€й0€v€€s€m€€€€t/€€€€€T}€~€ީ€€{€€m€€€€w€€׿€2€ن€€ņ:€J€:€͆€€
€€5€5€€€|€€€Ⱦ€_€g$7N€€€1a€]k€€€Ԉ8€€H{8€€€€€\=€€€€P€€€€€G|€"Þ€[2€€€
€R€€sDxo/€k€9€$#hC€€r€HF€€7€äŒÂ€Ý€o€€€2"€#€€€€€€€;€"€€sDx+€€€€€7€€€€€€[€€u€'G€€€"€!w€€€€€;€o€T#Vs€€S#hO€€€€W€€€ު€F€9B€փ#h€€€€q€€€€7€}€€€€€€€€€j€€8€€R€x€#€€D<€€t=G€€u€#€€€W#n€€[€€ro€R#€(€M€]P#xϛ€.$€€€€7#€€€
hoF€C€€€o€€W#X€)g€8Br€€3BF€€€Ո€8€€f€ڞ=€€:€€_€€€€€d€€€H€€s€€o€C€t}€€€€€;€€~su€€€€€0€€€{€G€€€€
€€M׃o€[€€M׃o€֧w9€C€€q4€€€[:€€€̣z€€Þ€€€€€=€B€€p€l€€G]DS€}€€€€-M€i€j€#€sh\€€i€bh€JT€€€Y湊Cyy€€%€w"€€2O~€€o€€g>€€€z۳€;o6€9vmF€w0b_5v€VÕ2€€€€EC€]€€+Q€Q'€湜€€Ok€€€€€:€rË/€wl€€€€€€€Ю0€€€{i€Ux€ƚXL€€D"⟨ €ZÌ»ÖÞ’È®u€€€€€€€€€&5d6}7Ðmk€€~E €b€k(€EfW\m€W€€0€€€[.€M_€v?€pl€€€2 o€€€X
n€€€€p€f€kxƇ'€0€€€€C2v~1/€/€€<€€€€€€€̱€d€€[x€€_€޹€>€€&€PF]€m€ۿh€Z&Ɏ€€€€€€€Fe€[:W€6€z[Z€4z€N~€+W€€Jm€€€€€d1€i€6Ï Â€Â€JRYB€€€€€€€€7€V€€7>€€)€v€i€€€O€6€&€-€€€VV%€€€W€€Ys€€€€g€€€€€=€w)€€7€€€0€^\ €h"€zܶ]€€€ʰi€€€€€€€€(2 €*€€#€€€€ƶc€€u € W9€€mÞ³A€€€rK€€P€€€€]€鷟T€€€U€CWI}9M€T-n€€pN€v€€
€€€Ŏ'€MZ€B€€A€€h€8€+G€€€€~d€7€€€`k€<\€€As€€[U
K€0U€€ +t?€r€€€€9€€€€U€ε€€€€€€ +?€€!€t€*€€雉€H€SE3G€€I€€;f€fGP€=€€:€€€€c*€p€€7€HaES€o€v€€i€€G€1€€1O8€X€T€€gU€'€]€€€€^€M€֖€€€$€H3€€Qe/€€€€€L$€€}€€A€+z€€€€€:€9|wPE€<€€{CG7k€€€€€ޮAS€€>€I€$€Vu/'€€f€9€M€€€€€€€-n^€€€W€A€€€&L€€€ b€+f€€€€€8K€€€€€€KUZDZ€€н€Yy14€€,€€<S€>€€€6€€/M€o{Z€h{€€€€ €>€€j€m€€L€€€4€q7€€a€z%M€€0$"€€ƹ€€͹€C€€TV3 +x)€€€%;€4߀€zu€€n€-€@!€€A\€H€b#~€ȑYY[_€/€r€€^€:€€€€y~€€Mt€ꋤ€€€€Q€€p€·+~\€/Z€z€p€€€ҽh€€€H€€€€A€׻€€}n€€€{FBx€m/L€}b€8^€€€C€S€}€O€€€q€€€`'€ O€€X=€€€€€ZP€€9èѾ€a€b€4€N/€:€€'€€"€€€€€€€j€9?€€v€€S€0SP€€€€€N€€
S`€€=€€€s'€q€#C€x€Q<Q;€€C€€e€>€3€H€زqE€h€a€€ÙG^€s€tP2€€€€€~Q#€#(€FP€€wP€KԅYJ€€w€9n€€#€LɎ€ +€€8Ȼz5֌0K€IfA€€?;R}€€|€€€l€ԥ€€€€(€<z€}€h€€€€€€a4g€€€€€€€7F;€r€€6€ٴ€lDA€iok€O|€€r€€hUˣ€€t€€V€€V€YU€'€€€€sy€{€€€€€f€}_3$€€#€€€ Ͱlp€€,€€€*g€WN€Jq€Wxd€W€€€1I€H€€̖E€o€€q€K€€QV€€€€'€#€d€`ƓPG€€ڈư€q{K€€r€ڇƑ€€@€€Q€(€€7+ +B€€€€VS0€€"€€M&!|CZ#€€€€H€€{L}€D€€G€{€€€€W€€€(€€Sʲ€.€y€0€Jd€€€ >㩥 m€rҵ€;€€Rfo€o€R€€'€V€€€€€΄><€̪€€€3€NЙg€Ȥ€€3/+j€Ę€WbijU€-'€€e€#U%€€K€.€-ha€{€€€F'€X€€€A踿T€,'€9-B€€€#€G€wtE:]{c€€{€]€8][e€B€€€€€SpY€€€>€*TM€
+T€t€€~€Py.R€<+p€€€PpgEz€€€€B€c€€€€€€€
€aK€€€€t€€:€qæ‚*€<€€Ո€HdF€€~L€^€8€:€l{€€{E€€€>€<€€€ €€<A7USg€v€€:€€Ah€q€€v€15€+S"€gy€W€€€%a|€€€z€€S€N€!€1$O€€=€[.>bȩ€z€!€t{€€€>€cR|Ș|€€€<'€/€€€€㌹€€€u€i€:€C€€j€€€%€`PL€z€8€:€€;'€o€Sx€€€€C€[€€u[€€kf€1€j€3€€€€€.€€ţ€€€€|kހ€>€€€€5€N€}€S#Dܣ€€T}€8 €€€€#{€
_€o€€1€*€Ԭ€€€€s€€J€o<€€U4€€€€€€8:uQ4>A€~€䞚Z€8€N€?c€€€|q€€#€€€&€b€)€€8€€3€F€€€€€y€€A€€€-4x€€Q48€€€ˆ€€P€C.ۢ€€€1€v?€%€M5€€I€€€€€€€,x€€€€hLL€€€€B€wfhf€€"f€€C€ +€€€€.(W5Ú©Y㼑€€Â€€T€€c€7fE€8€€€€ͽ€`€%€€€€]€€€€I€€€;€7€uFٚ€Έ€D€&yx€€€€c€€€€G;€o€P;€w霚ݙ€€8/€€€€€Ҩ€=€€翅+€tQq€ܿ€Z€€ +€€€€ݧ-€€co€€€"€€€€€€€k€€X0€t׋€6€0€€€€€7€€ܓ€€zQT€€€€€A€€€:€(€€_€€O*b€€IŒ€€B€€NLO€\€G€€q€{\€€€€T€K€€r€€€€€€q!€€Am€S€_€~,R€qza€€S€u€€)€€€€€.€€€?Z€€qM=€€QV^#n€€7€|€$€`€b€€q€a€I€€ܼ€t€€e€?€|€Z9€€€€-€*€y€€€O€€€€ϼ€̶€€€g€€€€Ėc€€€€2€RD€€€.€@€o€€]S €€ny€ Oy1€'} +€€€€K€€€K€5€€€j€%€Pex|'€€F€?€4€w€€€€f€€4 +v€3j€:pB€€O€€€€€5€E€*€w€€h€€€€€€€׎€€ €€oM€€z€oT#€€K€€€€OW€€q€€€€麶€€€€€G€€€€O€€€d€€€€€h€s:֧€€€g€yQ€{€[N€>݈w€€€E€€Q€?€-€€aP€ o€€€29b€0'X€cQ€w€€€7]€€€€€Xx€€€l€{&€€=tq€I€€X€€€X€€€€+€€€t€€€F€€€`a9
p?_€G€`€[| €?€€€=ð€€€€c€j܃€€F€€Ǧx€€€
€€"F€€5€€uT€y€ j€€2€o|€€€z€Qç•Â€Â€Â€Â€z'€€t€€€€€9t€€p€c€͜€€۔€|€€€|<€n€€€174i€
€€€
€4€s€€€s€€y€€~€€€€€€)€z€ܨ€€€€7€k€€€€€I€U€? +€Wyr€€€(€€ €1€O€Ș€7€&@€k=Tu€g€€€€€€p +Ϻ€3€9<€I€Eg€>€€€K~9€€€8€z€o€€€6€€€€€N€/)€€€€y<€€+€€43€}€^€E€j€6€€€#€€#€̥D€?P7€€a€_€€b€7€|4€]s€ۡDgG€?€{€€]€D0€+=€er€6€€'€ge€u€i-v€€u€3€.€€Lj/€€€€I€€0€c€€€€z€+€2€€QSt€€{=€€€€€[€~€€_~€€€ +€€€€€!p€/€€€€*€|+€€p€€€.8΀€N€€€€b€7€€€€€€V€qsU€W€s€€0j€v€€€a€A€€G{%€€)€2w€€€>€€GZ€€=€€€c;€&X劓€€€€c€S€{€)#€€v€.€PaV o(€}€€€€ O(€5]€€^€€x€{x€?€L€€~€<+N€€€.qvt€€€)<€N?
w€€Oá½Â€~€€€€,€υ€€€€EP€€€€€D€€cO~€c€Ez€€€py€€"=€€€€OD€€M€]W€€_ﺣ€€€~€Q€€>\€;|€% +kF€€€€n€;=€n€€+N'€€U]RO€€€€€€g€ff€f€€ib€€€f€€€[:€a€€€ư€|€€>z1€G|W€€
€?€Y€<€>€FӢ€€€Y€-€€t€p€i€5oB€]€€o {G€€€€€n€€u€€6€%E€6€€t €WF€€€€uY€€€9€€|'€n€€5>2kb€Gn€8:€pr!Y€€€G€=6et€^שz€€€€{€€€rj<5u45€G€=6€~煉€€Q€€€F€€r€€;€t€€€S;€€€'€€€€€€ŷ€€<3€€*€€=v€€Vu€2€€€€€€€֯€€€Y€€€€}€rB:€€€.z€Y€€)4€#A€0€]€?€€€€€€€€€ €ΊοN€€€€6€€€€Ĝ€YtQ[€€€€S€€oM€€€€7€hbʶ]€[€N€bFt€€€€Xg€€z€:щS€€€€€€g€9FV~t€€t€)€US€O€€€€Q€€€€8"€+o€€&$!€E$h]{r€€S€ {€€8€^.€ң€€€ +ϡ€€zt€€€!3U€m€W€<€€ +€€€€o€€€€&€€€€h€€Ӭ€E€€€?#€€;€€€€T€€ި€€€€'Vb€t€€?€€w׫h€]I€€€€T€€?€-%€I€3€€€Q€€O€€wN€€3€€̟P
sN#€€€€S
€€(
€1€@7€€€@5€R€UCj€8R€IR€s6€€w€T€m'6€€€~€'€9€R€@€€€€€=€€€€€;€s€€۹S0€;€48€V€€ I€IH€€€[€€€€€€€€]uR1`€=)zuF€o\€5€€€F6€€<\€Y€F#€€o€€p€€€€€qUd€€߅€€5Z{€^€F€€€€€€€€5€€€€G+€'€€€€€L€€€9€4\€€S\€€0€0€6€+%€€€€€\€€+€i€€**€^x—M€€€8€€l€€H€€{2!€€€€€=D|A€|€€€;€{V€M~€€10Mp@€S.€€€1€sp€5:€8€€€1C€€ʌ€UB€€€T€€€;€3€֋Ί€€?€8]€ €€w+€€Ggw2>€€€€€€ܩ€€o€;€á€€|€€]€;€€€€€7€#W €t€b7€€Zì£w€€Ö8T€€]€€€€€€4€b€D_€€€€,€}]o€€€€€s€y?€€€€>€€7€€)BH€€v€ €€q€€€w€€€w€€z€W!€z?€€€!€€ĕ[€L|€h€€9€[%}€]NҦ€€€s€t€€€€€€€€€Fs€.T€€€€1€€€€O€S€€ {€2b€€/9€w€€$u€Q8€€€€'€€!€€€€€€€€<af€(€=[€Η€r€-€4n9{€[0€l€@!€q€€€€^q€[€xN[€€€ègD€€€ӎ€€[Cxßj€€Ñ€J€€hH€N€€€u€€*O€ €€€€€;€€€€F€8€3€m2=cW€y€TV€€€ʺ€€Ά€€G€I€€€;B€€A}T€€€߷€€€€He€€€€€׃׃€€
H|.€€q=€€€€€qo<E€q€€c€€ؚ€g.€Ý€p€atQ€?€ͷ€€{€€€€yF€€x€€€"€jd€€'T_€€€€\€9?€G^j€Փ€€k€F€€€M€€/€€'zs€€€u€#€޻€€~€o|a€K|I€€,€€€*€€T/€€ã®Â€g€€o;v+€`Df_WzHÞ K€€€€&z[€€€€/Q€N€€€€€sD&€P}€ +Z€€9z€a_€€€€E€€lz7n€&€€/P€Vw€e€v7€€€rK€€€1G€€Gd~€Ï#N€€€€€€€€€K€€FH€€€€€7€€€7z€;{€n€r€€€n€€€€€Mtg1€ߢ€ߔ*k€,b€z€€N€Y"/€€r€€?^x(tY€€€€#€€€2€ €p€€GL€€7€€6€QT€^€2€€€€\@o€g€€xG€€€€d€ҧq€3€€€€eE€M€€*g€€€bj€€€}Y€€%€>z5€€€€€=DNA€v€€"G؇y€9r
W€ W9€€V€R€U€€/€j€J€+€€€€״€q€€_w€W"㓾€€€€t?*€€€SL~€bΨ篻€+€€€€€m€€}M€€€4€€m€>€€v€jVr€€€€b€/€5€€?€€L€n|€€W€ +€U€€l[
€€l0€ͣ€€€me€€€€=t€[(~€R߼|€€t€€u€€3~€m_
|H€€d€€€@#€€€;€1€€WRo€mϜ€€ը€€€€u€€€q€wT€€€€€:Hn#€€€€棺€€}]|5€!€€€ߢ€—SR€=€€c€P͵a.7=€W€Sf1J€€€€Z€€€€A)€€€>€n€€-%€€ć€€€€€€&€€€2€F€?€€LA€$€€Ї€€€€æžÂ€Â€Â€Â€Â€Â€$€€€€O€€€€$€1u€€o€€=€€I€€ܶb4€€€€`€€Ý€Ey_€}HÝ‚x€j€n€C€€€TS€ը€€~€։€€Pw€€V}'€€ը[XF€€€€,>]€bL€w€€N€€€€Z~€€ €€P:€W(Y€j€C€€€€Z€€5JÖ»>B)€€Qr2J€m#~€
€€€€€€W5€€vÀժS€/"€O€€€OP€€€S$€./ +€EWÍ» €€€=€€€n>4K^€=€€€u7€€€L6|Q€St€€̂ә€€€*€€€ɀWJ€0€É€8€cA€€FL8€€€a€€€€€Ю€
!€€€2€嵊€€€ +?5€{1€€€8€h~€of4€€€€s|€г€0€€/€€€~2€^€&d€3€€+€ß€i \u€€o€8Σ(€€€€€€zq/€€Y€<Go€L{€€݂€€&;zC€€€€%€zp~€€i€€€€€€€h€F*F€)€€€U€€U€€€€€€mӖ€}T{€:€€:€€€€€€€W€€€_€(*€|€n€6€€6€€€€4Â€ß k€€€€€€>€€€€€}€?€n;€Ag€€€n€n€€n€€ʧ€]Ӝ€jW€€€7€€€€€g€€€€€>€=r+€€z+€h€€拿€€€:!r€€€z€€h€€~]€€Ñj€\9€^9Z{€?€^€Q€€€€€Gk€€€€
Op5|€")uD|€#€€xV€<u9€€€€€T€€~@k€€€z}€h- €€L€€€sק^€v€€€s5€i€€€2€€-€€v7€€€€€W€2^QÂ€Ó }€V€€€€€ֲ€ķ€v€€€Zԛ€€T€iÞŸ{€W€c€€€f€g€€)€ռm^€€;XW€€y€xl€W!€€€€Q€€€3€€6€€ݡ€T€.€ėS€€e€Ú€_€r€N€
€€%€€€)€€]€>€€€€kP€M€\9#~|€€€B€N€9€)F5><€{€†€€€€!€{t€w€€€€€9ܼ€s€r67:€{€€€€€€€>€€€€y€W€€€€Aq€€$€'€€€€€€€€€€?ϮĿ7Â€ÍºÕ Â€l^;€€D€Q€€P€^87{Ep€i4€€€S€Nut€€€€€€€€׹߻z{Z€cl€H€7€y++€F€=€z€d.€6€Gs€€€-|€€}#€]€€€}#aT€/€€ϥ€€ܟS5|€€Z€Z€€€€€6€€=€5a€z€€t€€€€€€€uuk€zw€€€o€J€€€€€€€€€€<+`€x€^a!€€€}]>€m€|)€€€€€dUV€€€€€yM€RW€{ 4C€€j€ 4€€€€],D€€5€€ҹ€€#v€€€€€?€,€€g
<€€€?Pt€n1^€€M€€€E€b€€_€)D+€n€€&€€/€€\"X€N€2€7€3€€v€m氶€€€€Ӏ€€€€p€€gw€ J6\/€2_hL€q€d8€JG€€[€1e€€€€€c€`€€F€€RD€7€f€€€€X€D€a€€€5€+Y€5b€-o€ɮ€p€p€?€.lF8€€€€€€€E€4/g€€€€I€€€Y€€€_€€/9U€<€€~€€€€€€,.T€q€€4o€€<Ch{€[€]€€C€B€€8}l3B얷€€Wg€€€'l[n€€€y€€€*ֹx€€{€€x€€€,€A€€Pp,€̥T€(€€€€-.1€yLl €€T€
€€H€j0€]€€ܖ€Ö*Q€€E€g.\|€€دX\~y]€]\-€>€r€A;€€yӀq€^€€+V €I€€€k[€€1€>€3€€€7€*€€€€€€€=}€€mx?€p€€€€€QES>€Z€€€€>€€€€fW€>X€€ [€1€}5€K€7€€z{p_&9€€Ǝ{€€€U€,b€y€€€€س֯€€ۖ€1m€€€d€ +€u8_€€€€n€עֶ€€€€lP)€s2€Juuy:x€,F)€۱=x€€€€p€€`!€G€€~€{€€€€€(ݫ€€€€ZX€&€€U+#a'(€b€;+ئf€€€S_€ݩ€€1€€€:€€€€€e1€n€3Ɠ€€€€Jɓ€*E€€_€€€€€€€
€kɃA€b€€/€€|€€/€C€A€=€€Z4f%€€€+5€<€
s%q€aÚ@€€:9€v€oᕱo€€€€X€Y€剷€€}€€€W€€€€Q1WoV_o€ך͚€€(!nh%€€^€4€v€ +€*€€€€€xU€c€Z€U#€€U€€€u€-Ե€€Õ?€VȮ€D€€G!Z€€€€€on€fl€a-€{o?PX€r،€+€€F2€DX€€€€€rJt€9€MY$/k€€|*S .?€x!€Z€€€€€€]Oz€s€Uq€
+€€€€€p€Y€€€eo€€1€€€eR{
à [€€!€€n€ <€-w|€€€i€O[ƹ€m€x€€|C€€ټLN€y€A€€_€7€
_g6€Ϳ€€€€€x€G€€~a€€%€€v$€ߩ€€€€F€€;€޼3€^B +€€d0D€P€€G€-b€*n€€)-€€€9€g箳qUk€ȑ^€Mu€€Ѫ♠3€€€€€€€7€€-z€€€5€Tm$€€"€€Þ€QW€€a€s€€€€n€€ (v_>Ԥ€+c€€U€~€€€€€趮€<_€y€€€45€€Ҝ€€€€{€€€€€€€€€€[€€eWJw_z€€[€€Q€Y4€€€€€€€€7(€^€€€>"ݳ€€Ho€€€€€н€or€€^€z _q€€€€H_3:<€t€X€Y:vY€q<€€Q€C޲€€:€€nF€Ǚy€€;€-7@v€€f€GV€€€6/mV€€€x€€€€€)€o€€€Z€€€€€€zPM6€%84߯€H]
€€9v€>€';€BEBFF€v€Ѻl€€€€1€A€€E˸€1€€€€ׇ€€€Is€€b€>€h€Q€€€€"€€M"f1;€~F€)€€#€€3r€c€€g€€€q&€€Qֈ€3€€G€=€€rU€€*€E€€€€€"'/Gj€€a€4€€r€€€€€€€€€€~o€€t€G8€aJD€€€;€€(€€NW€€ԓ€€Y?€B€€Y€€€€9n€€ޚT€)€p€€Y€6d7€k\€€€€N€€G"j€€Wr_€€>zw€€€€6e€€€L€€€^€6€€€€€g€€€€€€€€Yw€y€-7€Y€?!5€ް€€A€A€W€€g€€,\k€CY*ßX€?€5€€ €€wYU€҅jw2á§Â€@€€€€C€5U€€/€€€€he$v€I€€{Oo€Is€['t€7€€(j<1€€ٓY€X|$€Lϋ€€,y€O€3€€a€.€€j€€€9h€3€+€+$[jYvP€€~t€€g€€€m€€€€€€+€Y +€d€€?%4}0<€s€gy€€€€€€€€€€_]%G€€€M€€€lڜ€€€€€€€^€硞o€€€y?€Yw€iyκ=Ò€4€€+€A€€=€A€€3€€€€a€{€€€€€3€c5€€ C€"€€€€€;€W€_֣€€€/
€_)€I€|{€€I€%in€)€&€€P€;9€֤€€{€€M€V€€k€0€B/€€5€€€j]V€3€€f>X~€|€€€€Jevƹ€€X€uE_€`_€€€€ +€0€*€+€6€€i!€EQ'r€;Oe€€€§€TI6€k€€€€€€]N8€€/€{Ä€€€Z€T€€€€€€ֆ€€€€3€m€rM€t1%42€[W)'{€PmoO€€€€N9Ù‹yT€€€€€€€€w€ +d€€€€€€"€€7|3€€xKb>€€€Ǿ€€€€€€€€€€€€€€%€€2j€/{€€:€In{€€€VPT€3<€€€n€€c€S€ʹ͒€e€-€€*0)ß²):5uWdv€b€n€€€€J€SXӔ€Ь8x€C€€€€l€0€9և€€€€€€€€\€€1m€E€€{4€€B€~OU€€N€€K€Bb2€;!€e€€€€€€€€>wWW€€€€€€NO"€>€€h€€€€L€€€ժε€€€c€}€€€€€!€J€€€4"€x€f€€&e€4Ý€/L"€€߮€>€€€o€{€=-2Ñ€Z€UU€̛€v^€€€"€q€-€€aw€€b€Z€z€X€i€€€.U€€€/€m€r1Ì›<€€c/)€€€€€€7€€ԃ€€.€u€#&.€€€Mm23€%|€€}€W€G=|€/⫤€_ |+vl€L€€€€€€€_€€P€j€€€€%Mb_}€€{7|€t€€€€p€i€վ€€%€p€€}`€€/€F3€€7C/W+U]€Sy;€€ ͙€^€wZ9e€€X€o€~o€€v€€€€€€_€€'€Ct€*€=€!€dA€|€W€B€€UW€€€€€€€2ASz€€c€€yI€€~€€K€€X€€~~€Y€!€€€wÖŽCr€€€€Ó€P€€+h€€mr€ǿ*€€n€€€€is€€Q=%gq€O€€ږT€]€-`€€J€x/€6€|j€g +)€€UUg€OFu€ӆK€€€€€€(€€g_Mn€w€€$€€€W€€€€O€€€=~ý_R€€Uh\€qH€€€€*G€S€€;€€c€€E€€€}€€j+€€€*€€؈#uS€c€)€€1Γ€E
€j€:k€|(y€€~€€UJ€€€€4€€€€`€V€€8Jg€͂E#8/o€€€€S€Q€x€€R€€r€*€€€€l€€€S€€o
€€HI€€€~€KJ€€€€M€[€ms}€€QyY€#]€å’€h.-€€`ˊ€J€<€€€!€oN€[ÞA>J€%o v€6€€€Ӻ!#€€(€€€d3ט€€\ $w_c€€€m€m^€*€"€t€€€fÌž*€%€€€ +€S€x€€€€c!_)€r':€€€€€€€€€
V€=QD€V€€€#.H€€V€ +;€€€€€v€d/WU=€Do€€€€€ji€€۽€)B€uU€€)B€€Bl€`€xbF€t€ЗC9M[€€3€€+G€$€\3€0€È\€€€€%g€p/Z€&€€I€w€€{€1O€€|'~€ս€€€n +dYcx€{€?J€€€
€€=€€8€€€#€€€€9b€p€cͥ€k*Ù\€[€^RQ€€&\ Xi€€ k%̬€€€€S€€Z€€€i€2€Õ~wG€UBl~€`0€€|€€d€1Z€€Hf€€m€n0€€€ɉ€7€!€€`€9/€C€€d4X΢€€c,€ƚ
FKL€!6f€!€k4€T_€€l§€o0€b€SP€V€وO€وx@€IA>€U€ o+Ä $€5YL€6 €#€€d€€€€c€11€€)€dBr€A€€€Cl2U€€zC€€ €M€€Z&€€'cc€€l€*c€€2Q€"(€`L€€Ix€€i1€€`A€H€€(-€€X€€h€€E%€)€€€.Ȉ€€+€0€€2€€L€€E€€QgΉ€€c€€€€L€d1Z€€M€€€€شT€{€€€$2€€k€|@Â€Â€Ô q?€€&€|T€€€ÇgH€€X€€d|€dR€c&̓€€€_€"€k€€€Y€S€>(€Ña0$Л €c4€€l€n-&6€#aA€ €€€|ByzlF€€€ Mo€cL`4€lx a1€€ 3j€8s|ɦ€€h€G€€€'3€0€€ތ€@€€b€L€€€(jZ€€f€Y€€
&ʈF5€€?€'€N€€1&€k&€D[ +È”T~*s€€_t€€€@€€ìm€€€7Y-F€Ùg€€(Q~@ C€€€`4€€LLc8€"JAҴ€€€3€€S€٘€u€#R€€o€e$€€€P1€V€€€՘`IE€€OA€fRj€€bc€%€V€€h€€€€€€w,~€-6€-€€€w&€J€(€D$~€!€€E€€@9€؇ж€;€€Zl"€€`€K€€€I2€€€€€x€€Uw€€S
9,€ PXzl€h+C€'€€?€(€jN€O€€V€€€€L€s6Cf\L,ZӨ€h €"€}M€/€€_ԙ€F€O€€C€&yD€@̚€LZI€3~€u€)A€€€V5€€€x€%€l€€€?€% j€ €€x€MR€€ű€€€`€€XNa2Q8€€ڬ€Xd€ €€R€eJ€3CA"!^€€o€€€TM€€(€ˆ$&€€C€(Y€€€€€c€U}f€"€€c(€€<€۔d€€]|ã‹U€ghM[€D€eӨ€c€#€0€ €oh€€(€/€j€€€€€K€Z€ַ€$€j€€€hf€€€nJY€kN€;Z€€9o\€€^€r€Î€)9€K$@G€0€ʱ€k8€€€€L€€€p@(c$d<€Zc$€V€pV€€€€>"O€'€C{€&J5€€a€€h?€0€)€€f€€€P
€S&k €ClR2'€.=V€€€6-€A€€a€@€€U€€€€€€€0sO1BK€҉F€3€p%&€|€ń03€͉q€Ip€؅b€!€€€€$5€̒€€Tz€€€€6&CBQi€eN€ak$>Y€€€P€ k4X€E€,€DÖ¹'€€€w€€YQ€X€/Q<B4&70€&€€;R€€&€]€M€Ø,€3€€C€€€G€ f€o€€€€k€d€v€€€5T€€€H?€f€€k^!tt€n€4€€€02X€€€€€€D@oJ +匟€o2>€vWK€^'€)€j€(€|€)Z-F€€€U€Of€@€€#€ZL€€b,q`[€)€€B€~bLi€wG€4€€$s€9E"€€cK€ͳ€kM匈€€€T€€€€J€3€A€Y€Mc€‚:,p€€݃'p>€€H€\€K€=J€€b€€€a +{
)`€a€4`' €^€€€€€S€€ȡ€Q€G€€б€€挧€€€$€€€Wz€€€€€€n€1ޤ€€€I €€7€(€€€€o(€)€€€€€ €€G*X€z€€€9R;j?S€€錆)€€ߑU€€€€f'€J(€0aPi€€>Z€€€€€€€€W€€€€€€V€7e€H€nI$€€YÄ$p€€xy€V€€TX€€<7€€Ev€€€v&€`€€!jf€€$!?€!o€€PS<,B€€f€ǘb€€S32€€r€'€Yⱪ!€€P}€€€,s€ٔ€>w€€€b;b€ +R?~€€<Ùœ~uvR€€Scݵ€Y€€€7€€€€€E€Dsf€9€\€q€9€<€€€€&|'€s€f[=€€€€J-€ =€€€1[€€̸O€€€€€€oÙ}f€e€ki€€x€€€Miy'0€?91f€€DË…&Sѹ1€€f€€€I€€€O€k€€t€'gۦ€€€€€€߳€€r€€€€
€€ig~2eÒ™9YSΜ€€€b€d€g€Y€€j€g€%%€2i>€€"6€NÊ´$€}6€€€€€.€eN€4[€€€€<v=&€a€.€€€ O&€€1sR€€€u6"€€n)€€€;€R~€NZ(€.U€.€€ +€m€%ζLJ€€€Y€€&MLJiRJ"3Q:">>i>A;€€€>€6€/€`€€€€€€€€x/€€€€N +'€€ձ€)€Rh€€TJ€!€j€o<H€b€:d€E*€€wÌ{@€€
€€€ԇ€IM€K8:&€€€4€€€L€Q€%€€C}€1€p( +€_€4O€յ€<€0€$&FM€3€'As€€€€^€.€€€
N€€€Hk3€9fʤ€€0aB€K€€€bմg€€€€l€€ +€ä€€
€€53€€̘€i|€€fF7}€€tM€€m€S>€€c€ojW€€€6Gь€Wr€>€8i€ն€€sgvL€M1Å›f€q€€dzJ€Ԕ匴€€WT}l€€€€شdk€d€€€߲€Y'%€L€€m5[€-g€K€L 6k€ͺ8)€r€LS€€€YgM€€1ϰ€€s€%3€€̒4€!?Õ–n^€€`€€sfÌ‚I€QgÉš43y€Ჸ€€€€€T(€€€!-Í’jI€4€€Y`&h€€iÌ’L€l€![X€]iz€€1)63ÃB€€€€г€q€€?€jtt +€3.*€€€€€^€?€M͟€^~€+€>€t@€€s€5v€€t€ɽ€w€)€/Lm€€X€€€(€o€€ug €|/L@€€€ €€€€€
€6,*€-]Z€€€ewa€x€€€.V€0É€€ӗ€b€8€]€€€[\€=€€2€€mAĜ€€€€€€€钟€€€=P€€€€€€€€€€m€€€€[€€€€€w`€&q€W€Y€0y€€+ƣ€€€€k€^€h|€k+zm€€V€€€€y€H€L€€Û}€€€&€fn€U豮̵€€/€l€€L€€€L€7€€e€€"€€€€€€€€€€[k6€€GM€€֎€f€€€€€J€€€€€ɛ€>€€€€€j€8=[€|€ǔ€X€€€€..}€c€€V€€V\\]Y€l€⋫€]cnU€€T!€o€€@@€hy€z
€9lÑ¿kCj€€€M€€€€€€€€€h6-{€oZ€€€€sgä“?s€€€¢s€€7€c€>>€€_Xr€€€lᢋ/q,u^R~iEe€e€5€˖_^wÅŠO€€€WcSsK€€€־rUG€€€€;€€€€€W€€z€5€>€^€€\~qYUi€C\€€;6z€€B€€€z€€Sq€w€*S€ >+a€€€K€€€V€€€K€€€zl9Ӕ€.€€€€€€€Ú4v`V€€Js[€€€€€m€€)€€€€[€€n€€€U€l€ink€z€€€€€p*€€ۂ€€nl€G€€€XtS€€€دF€€€€q€WS€€€΂€€€€€U€rs€isk€ €€w#€h€2€MAE€
C€ҋ)e€Ҩn€€u#€€€€€€Xl,%€€W€€€€€Ú€€C€€ _*€€€€€€€€€n€€€€6TY$W€W€5€€M€€Ԃ:€W+€€@"b€S€t€€W€R€}€€€=W+€k€[[€e€€{€W+-€-€$€[€V€€˯tB€4zZ€M€€€0]9€;€€x€r1€v57€€€€mTGw3€€{z;QU€BI€\!€€'@%'(€€€€)€€€€g\€€€€݂€h'%ت€fI'27K€€C€2€€€UԌ€€^oK€9 €+€€€€z€€V€)€€F?C€B€46a€€€sPCU€€m€€:Ki€K€€ݻ +€ݾ€€<".€€(W€A€Tߢ€ڶ€€y€4vHf)€W+n;XiЋ€#€€€€ €€€€€W€6%€Ý€€€€5€\|€€€N>€€€ݶ€€i€2€o€҃B€€€€OPA€T>!;KF4€}€€€pM`€O(jW€6€€€€5ǫ€€€v]€€iG€€95n`& l9}T€ZW/€€€谕€€9€€€€€vv€€?€D€Me€€3€€€€D€€€}@€ݧ(Õ–MBx€tA€€€|€R€€€€€€€€&E€n_€€€ƪ€d€u7aoB€~׀€^€€€€k€€€€^Ų€ €F€€/€€Ó>€€€@€g€ €€€€Ͷߦ€{?ÃZ€Pp€€<d€N€K9ÖŒN€€Z€`B 6.ޚ€8ɖ€€€zF€€€33€ʜ25kT€€€€ķ€v€OxX€€*j€ €€€€€t€€J€€€€€€Ң(€@€ظ€€€€9€@Y€€€€m€+€€€yJQт€€]0€\06€€<=€€)€֞^€w2 +o€€€-]€h€€€€€€.oO€€€5
2Y€z€€=€֖3i€F€€€q€€€z€!€€I€€€nh€€€T€K€€f€LI€€€€6€L€€ڇ6wÂ€ß Â€:€€n€€€€€]€-€€FCkGwkcoOW€€€€€^/€E`QDc€€n_€€€> t€OWOW +€€"€€€x€o<€p)€€€€z€!€€€HLA€㋹jV€€€€€€=L1€mFhNXEiu_ €€I
€[€€€$€€!€€€s€€€€HQ€€2R€€Z€€€€€yt_€05€€€)€l9€8 €€i€P{P€3z€x€Rl€-Q€€€QR€€€l€€€W½E€€€ގ€3ÇŠ)€O*̷€€€{€r€x€€н,€€֤i€€€€€B€Ý€€d 5€€€(i"€@€+PF_€F€€€:€1€j€€]l?€€€7€N€8N|€a€€€€€p€€€€0V€€~€)€[€M€€N€H €€€T*€€/,I€€/€€€€͞}á…³K€€g΄€07wݺ€€€!|{;€Z€€€g€P[%€€€€ +€€_€€1€v*€7^€€€€T€M€(€+€)€<[g`Ë¢
6€€V€€O<€€€6IG€€€€€-I€€€EÓ”E€,{€íªÂ€>u€ĜÜ€€5 +€$€d€R!€€€€m€€€4€€€2€z$Ìš;As€K8€€u€€vt€z`k€€€€|P€>W€p{€€€Q4wt€€hÕ¶api~€L-€€€ҥ756€€€9€m€€€WeB€yZ[€{:{€€€€g€b而€€͡€
h€Ǝn&€֫€Oŀ€}~€8€Y€`XSݩ€€(-€€€€€酵€€€l€RA€€Z€€€€ӗ֋қڡ7E€;€€mkml€€€'€€wUF7t€O€2KD€ejJ€ +Y#ÝšLe€€[€n€p€€€z"€€€€iH€€vRS€)+WQ`=€";€,Y€D€€€€&HIv€v"€€€6Y€%€€WH~\€€€€`g?€€€n€€€ੵ€€€ + +€€Hjj~€€€Z€€€%c\€€ݲ` +zB-pb€€]g€€ €)€é£Â€L€€€^(€€Y€b€>€㱣€׈O€€€€€€L?€zZ€t€m
bN€=M€€€3€€€hí©¯Â€Â€Â€É€O€k>esP`}[€€v߹€€€€€B€WW€b€€€€€d€€6K3€€€€R€ZS>€€LEe]€Rn€€€€g€_z€€U€€€I€€€€<€€€%€€€€I€?{r}y€.€€F€€UI€€€\_U€€€€7€€€ӗrM>€€€X€€€€€€뗟Q_€Tԣ€€$€OO€_€€.J€€€6€€€Q_€€€€fPe€Z€#€€€€€"€€ €€€€-€€€€€€:aB"€€DB€@uu€€mM]k€IU˚€\$€€R4Ĝ€ӔK€€€€ €L€Ǝ€&€?€€J1€3€M€€^€€€!?€E€-€o€,€6K€*€4IN€}L€C5&€(Ч€R€€&€€gR€ȵ€dh€u€Då—¬zj=€8€z€^€€€€€€j€?€~€€€\E}€€€€€p€€€€€€#N=€o€€I€)$€€€~€€k€€€€W€5€€€€J€_mk€€€€H€€vy;hT$,€[€P-r€€€€_€W$€/€€€€€€€€€€A#$€€€@€€g€€r€UB۰€€T:{€€摼p€-€r1!€9($€I.€€€T€€€l€4€€€5€h\d€l€d€€€€
€€rX€J0[€€{€]^H€€Y€㩓꯰͕€€€€K€€B €$$j€''
9€n[|ͧrN4€Jcc€€€qt€€€7iT€Ի€E}€*_€€R€€€a€€?€~5€vԣ€€€€€a€&€€6L€€w
€€R€€~]}}€€€€€€€€O€€D€€z€c€"€t€薎€€_`|€]€€€11/€€Jl%€€[€7€€€J€Dž€w}v}v€€o`€`€€€ؤX€€€E€+€€=€d08€€€€ؑwvC
€€
0 +€€€€7,€€€>Uu€€n€w€€€€n€€8€€`p€€€7€€€,€oH\\sE
€@€
€€t_€ݕ€€oae€٩{L€€nO€€y$€EH€€U€€€€€tstوPt€€€€€€?€<8€19€€0€€€€!€L€m€€G6€>€€Ռ
€€€€€€€€€O€r€ӹyճ€]o +€(€€€I€f€$|OJ€€%€R€€€]€€ȸ<uVU€G€;€€€<€ m€g€q3€€;
€€€€€€jYQ€H€€€€a€€O€c€B€cM€€
€^l|€i^W h€€€TV€€6€€€€6€€XL€y6o弖=€€€s€va€€k€i€€f€)€€Uvv€V€€€Ep€Uh€€qcv"o-e€€€€G€€[=m€€€a;c^€€@)€w€:iթ,€ +€m€€€€9o€Zur€j€^€€€-s€r€€€w€ba=€+€€€€J€€cR€€L€i€€€ +\v€]€€€€C€€€€a\tkGp€Gq1€€1.€c€~€뮂(€~€bH.€\€€
€'k€€p~!€HtÄ·UtL@€T+&#ns€<s0€l +a€JX€€€€Zy€€$€kZ€ī] €M€€6_pËa€€.^€€r€:`pIv€Ϩ|€f}€€€n€z€'€€f€r€}\€€V€€€€€€ڻ€{€€2ê…¤t€€€€9€€6€€€f€€€ᩴCW€€^O€0€r€€€€~1€V€€ç·w(€€€J€w€€€w€€7,€oN€C€€Q7€B€<;g€€€€€€€\g€'}€k8€j1k€€܅€€^€€€€x€€r[€€€€tp€€(€k€€€N€€q€€.¾€€€€€ԩ€2€6Ó€€Bl€€€V<€€€€Z8޽€}sCf€€VV€Ìd€B€€(€c€nU€*€̴€;T€*=€€;€]d€;€W€€€ci€K!€€u11€€}€^€|€q€
.€€€€b€€|ڬ€7ަ€o€xKF€€€€€€€4y€C€@€€R€€#€€€y€-@€€p<€ žF€~€ڂA;€J€£€€b€€g€€M€€)€€€06IWo~ds€€€z€è—€€€]€%z
€€€€V^€€]€L\h^/€€€€€`n€€€|€€€€.€€~l€€e€€€_7€€€€u=€_€€€W€€€=€v݀€*€€€€€U€/_€W9~€!€€E€€€7S€€€T€ڀ€4€€€]€€Z€>€€^€€jZ€€€r€ɵ1€€g€€€€\€€.€€X€€€FW€€W€z€kr€C€9€.X€€€_€€€]€€€^?€5€2€Ov€!6€€Ou€!քo€€T€\6€€€€€€€WY_>€€Z€J€€€€z9q€I€€=[t'€Ρ€€N€€€# +€€Ov€€€^v€5.7€€€
€€v`€_qK€€€€€ €€M]qJ€bڪ(VW€b€€€َ€€s€^€€€G€D€<<€€€S€[€€€R€€€€F€€€€K_€€'O5
€:€€€^€€€€li€€€e> €'Ea€€d#$f€]€€€€€t[€€€€€ݧ֢*€€6t€75,€€€m€]Ò€€€€€!?€,|€ ~€€Ƒ"€€€€€ۙ`€5_~€€Ղb;6=Â€Ò Â€S€€€€_+€H}€~
€€l_~€€R€€_€L +€RnR(€ص€.€rM-6w€€€€€_€l€€ TD€€€€5€€€€nl€€E€eLN€€|tp€€׋Y1€4€
WX}i€Ϭ,€€€€&€€M€€€€€€€K€€:€€A\€S€; €c€n~)W€>€€€,a€€\z%€€€:€€
€€Y€€Å€€€€r€€qϣ€€€€€€mS+€q]€€€€€€€qު€€N€€%€€€€R`€€€€bz€ +e$€wo€e€€€€Ú`"€q€yR€€€€i€Cꀷ€/2€€€Ft€€€€€ba€R^€E]
€€€€€€€€€€€€€C€€€€€t€+€C€€€Y\€€^€zaM€€2op€€U€@€q€€€>0€=€n€N€5€Y€zWI€϶€ € ݞ€ܰ=€€€:€€e6WzQq@€€€€j4E€>€,€H€Ыӆ€€€K_1Z€>{€€}?<€€!€Ao€tз€€зNï©¿"à©£7€€*€q€€€,€Y€o€b€g€€€D€S€7€Л€<|€€q€0b€fO:j<€?€O4€=€€p€pk€€,€B€^+€yIkOiG{c€R€€ZON€(€€1€€€,tMÞ²[.€€€Z€k+€€-€€€€K€<q€%€€€€Xdv€Ņn€N€'€€r(€€€€€@ €€€e€€€tY€€)€V€u€€€,€€H€€€mq€€}€|ԓ€z✩€J^€€€V€€€㴹M€T€~€€W€gϽR€€€P€ +€€€€t€€€€;€€€€€€€)U€€€€€€kI)€€d}e€5L7€[^}€K_}€-€.€€€iÇ€&ß‚)€€j.€€€ylSj€W)€€€-€ɩ€€€
€€,E€(€Z€€y}€oA€Ȏ€€€€v€^€€€€y€€€€€=x€€.€6€€€€€ xu€va€Eq~wz-€~%€,#€€e€>C€kx€g€€€DVOΔ€€€:€ €s€€F€€€€Z€€€ذ€€€€€V€W€€]€Y€€€€€€€€Z`€y€V㗺€޸€pI+€€#]s€€€€ݩ€S€/€jD€€>€A€€Z|€)/€€€€/€€+UO€:>€€z€€€€€w€B€€?€8€€y#€cbVX €Z€€-[€€€€€€9O€$€6a"€€€€m€o€o/!1€.€€€Z eE€€L€&€1€'%rw€€€5€I€a€€€€€`€€€€€h€:0€€T€J€€€€B€
B€EPW.€€tG€€€€9J/€€€€€u€€-5R€X:€€€_€v€f<=€ڬ€€A$u€€~Y€R\k.€€€hÛ·j6€€€€P€Q€€€€€€€€€rM€]€€n€€Ҫ€:{€og €€tßP€=Fg +€€!€]€€€€ A€V€^€/a%-€"]G[M€€€€\5k3€
F€€-€c€€E€€€%Y€"€€€e€PU€E€€eR€זdQ}€%€΅E€€!€N +€k€€݋K€€{€e€+€€€k@€C€Xk€O€€€,3€:g€%€3Z€Ƽ5€e€€€€ڋߗ€€c€͆l€€+Ô Ô†Â€.€€€€€F€`€€K€V€cG7€€€/=\€€Y€€€€€F€=€Q€K€uOo>X7€7M€+@UCe€#€€€€‚€€€€€!€€€%N€Ga€€i#|€;$€€€€€2(€"%~€€*vʗ€€€€€€€€€%€€€€€c€€€n€%p€#jm€€s€€€"€€€k€x€DPnT€D+€r€"s€€€{€€%€€'€;=€,=€M€€€€N€ۆ€!€a€Ù€#€€Q7uT€€`>€€€€^€^^€W€ڋ>€€€L€o€€€ئ€
~€€€Mk€p%€[€o€
€3€€€€€?C€€u€€`!€H€}€3€y€i0€€?c€;}$€s}?3FRm%€€P€ɴs~€{€€€k€€€,€€€€j0€*€€8€ٳ€€^\W;v€€€€€€Wkl€€€O€€{:€€_€€€€=p +€€€X€M-*v€€€€€€#8€P€€EO€”€€€A€>€A€€J€€€(€Ͽ€c€€u€€1_◲€q€&€h=εV€LW€t€€€:€€A€
€€€€€HNql€.u|M€}ij6€€/€€'39€€8w€m€>Q]€rIbs€€W€€pp;՚€pS€|€^&f€d€€",X€F@€V[€Ĕ€€€?€[€€€€J€Q€[r€,eKd
5U€*€€e€€׋€DQ€ +€€€€bAQ1€€̉dP€/€^
€€!€€iL€m€€pD€}€p€€€€€€€€r8H€€`\fw€€€a<h€W€€PaSI8€[€€\€K€€€o€€}€~83F€l€b€*f€E}P€c?€€€,@7g€^€>€I€€€€€Z€.2+€€€€€€€$€ˆh€€-V)|٫ɛ€€5C€€€ ~w€€x*€€€€'€€]€u:W€:€+q€€€€0€€€€€CF\€ĕ;€€E€P€€ј€€ܡME€€€I1€,(€
`€bY]€ڊ€€KdL62€ن€€€€€ +X€? 6€€v€kpE€mw€k€€€ €€€€€€€€€܃€€+$€l€[€&B€€b€"o^€ ]>€€€ra€P€€Y€€ϥO€O4€ؤ€€E€€€€€^€€€€}€€€җo€"€€€€۾m€€€€€8€€o;8€€€€Ri€€€€€ͱ€|i€ŋ€€€W.)[V[[Y!k|> y€€}*4€AG€PQa€€AW€€;u€€€!"€|Vp€€"€Eź€€€B}€pT€€)€€€€ + +k€€€€ o€o€€l€€€€€7€€{€ +€4Mv€Ϛ€€)€€>€€M€€j€€~€€}€ZÜe€€€€-€€] €€€KD|€€k€€€€Zr/€€}€€H€y.€9€€M€€,€€)J-&'rP[^€6€€€3€C€x€€€€€Ԃ€ +໽€b€€€=ȬD2€€%€S4€R€€P9€zTb).€m+)€͟}€€€€€€€><€€€€€;€P€[6€€€t€€€׊L€€p€€w€G€7€€-€€4oD€€€€*^€€€l€€B€l€€b€Kd€H€€€€€€€B뽟€mP€i>€€ +r +€€=€Yj€7/€|ýQ€€€uC€>I€sӢ€*€€€€k€€€r€€€€!k€€n€€4E€K€|€,,€€ €۪€€V€€€€06€€2-€€ɡZ€ohY
€B€k€€€€€€%€;F€€€€Cp€€€€r€€ϩ€l€€7€p€
€T€€€u€;€€m€m€€€d€%b€€€€€€1z€d€E€€LN_€A€^<€ €€^S€;iVW€€€€c<€8€€]€€€€€€€€€€€`L€€R€q\
€€A€€€€E€€B%€€€r€o€FS€€ĺ€€|€€y€nQ€oIQu€9M€€'€€€€W€€>€€ƫÚ€€ا€€G€F腥€€€Zd€€€€ɻ€4".€~]€€2'€€̻iaϘ€€c€€|€w€g€n€€`€€M€L€€C€Q€€€€.n€o€€€€<€€m^€€€M€6D€T€€€€€ҟh€9€suÊœT鰇€€€̕€€€q5'€€€€€jy€*€j€€\€€j8€€.€W€€€E€€€:€=€E9Y€€3€"€€@.€Рk€€€€uO€€qA€h€€€%€}κ€:s€I€€€uQ1€€*€h€ x€€€€h€€€€n€:/-€bq€2eÂ€íª…[k€vU€(U€?€€€€€€R€ix€&_, €€;74t_b€€8b€€€X€€€€€)"V}k€€`€7/vJ€€I€€€l"€6#*€€€O€&k€€xO&€yZ€`€%8€-€3yL€€Db€€2€€B]€e€€/€€€€3k€€€€ά€ZL€€7y€p-n=3€6cH€€€€€€€.€:€j
;:€€€8;8x!€d€C€€€}"€P)T.Rx +€€€,@*D€.€CW€N€X€€)€€€,€3€`€€€€€€B]8?€€€€€:Uu€*1Ρ€€€€ €n€S€€€ +€!€l.€6,_ѧX€€ҵ
ͫi€€€3/a'€€o€1€€
w_€€€€€€E€€h€&T€€[€€a€€2g;€s€€?€€9a_K椙€S€€€8€muÔ;*+z1#8m€€$ϸvb€1€QG3@€o€€U€€ƴҲt€€€€ +€€k€1€Z€z€€€{€N€€€€€€€:a€[*€+ €€~€1€wѫ߈7€)Rw;€Ǩw€Qd*&@€9i€5€€<€*sZ€€ܲj<gA€c€G€€9€€ފMnuq€€ {€4€잷€€Cv€.€€€€€)€€€€Q€€zݒ€"€€€€CÅ€vb:€€€U€€€<€€2€€XB7=j€€q€€€€C€<,P6`\€gi€Wc€>(7mh7€or€;p€z€€€JV€p辺J€€}€0Ù§1€€
€€€€^t€€m€€€€€€&u:€2k€€d€€Z€€D€€€h€€8€l€€(.d€€?€t€:H3€+€€€ €q€€l€S€€€€1у€€×€o7|€€KSy€b€|Å¥u-͹ڛQ4€€€F€(-€€ €pN€€€€Nv€€m€.€€~D€2€€€€:=c€J~d€J€䙋€(4€€€94€€€€@+€&€+€€€Q€€R€€&€€p€€6t€€{€€G@€T€Ρ€€€_'€€€{€H€=€€j€Y€ÞJ=}d€?HwwjNO€€€€€Jb€€J€Թ$>€S€€€*Z€€s5€;og€m€*a€€#€nC.€€€€€ݙ@Ц!€€€€€з€]€0€€€\€e €蘴h€€&€Ѥ€T€€Fs€*€TKD€e€qϡ€€R€€€՘€€€eָ€^$€€и€€ X
€€€*€ĀP€€؅xI€-M€̈́€€OY€Y3€?€€€H€€€€€€)U'€S€€+€€€€€$€€€QM63K€€ǘ€Ã!€]€9^€€NJd€€€€AW€€€€€€€€€Q€Qy"€€€4€6€+FG9>€0]׆ɑjut€€V'€`€`s€€€\€€€€:Icj€D€6€S€€3F€F?X4;€€@€€R€€U:7we€€€06n4€yظP€€€€€€5$?€hy२jn#€N€€€r€@˵€~~€H€]F€€ah€P€IU€€€UU€€)€€İ€€€€p€;.WE€&:€z'e€€a€>€ +€€€€€€͑+"€p€€€€€€R5€T€*€€€€v€HV€-€a'€D;uj€gi€+6€K€o€T€€€+y€€€[0)€ma€€E৙;f +4"}Y€UODsȳ€o€€€P|>€€8~€O€z€€€_
Z€<€€ѓ€€$ϢOw€sXE€€U€z€€NSz€€€X8€€€*€€-€€ i€€v€€€€€€|€€€€nL€€€f2€€€€<$v>Е€c;N1Z €€€/€n€M€€W€)€€
€€€€€€\-V~R€€€x€€wB€5`]d3x8€]#€€€:€€€\€€)€V€|vGPߦ:€k€p^€€€€j|BU
€€€cv|ÏY€Û€€5€€-€€ExZ€q€a\.€€j€H€€€€^€O€€c€-9M€(:€c€€€€n€€€€€€3Õ€€€
r€͕€|€€€RS€u5€3
€ r] €a$G€€€€€€lTL€€a.P€€€c}€€€€€€1€&€$_€€U~q€sX,€€纋€€E€t€K€B€M€"€€€r\€5M€€€€%=Ô‰q€Di1€€J€!\€€ms€#^P/€€€8€ê…h€sÔ•cbb9Ï€~€dv€f€€€Ŭn€€*€€€Þ€m€ƚ먻€`€{€v€'T7+€€h€h€k€[+FN€€,€€}€j€€٨)€€€\H3ƃ€J
Q€€€ j€€a€&ΰ€A"€€€€mĿ€€</߲€€€€€€x5€€h€€ͽ€€€€1.€)€]%%€€€€FTC€D€$yi1€٘K|€*€€FO€w€K0€€Ù7€€o€Y€fhj9€R€€€/€€5É~€€;€€+_€€€€L€Ϝ€€€€6€€€<€€É€4vS€hgL €הm€€€€€€c€€€œ{y€3{M€€<6€€€€`€€]O€€/€€€€€/€]€€/u€€xY€€€€q€€&€€€€€€€nÀ€;h€t€"€€€X€C€€>皚€{6(€€^€'€g€€€€€€€€€c€;€7yM€€wl€x€€|€€ݸ6€Z€e +6w€€B~v,i€€[+\€1€J€u'€|}S/c€€=€€€€€€d€+€€u€Pd€€l€VI€@€rLo5a€€€2^ÜŒt~iB€s$€_€€€€=F€€/€ۗm€€€t~€Ed€e<€€€€혻€€_€{€€€ї€U€T>€S6ާ€7€r€€N€Y€€€€_€€8€~%6€X€;Q€_€€Þ€u€€ +'0ì²t€J׼€;€€€€€`€€€kG€[QK€c€X€#€Jo€€€€ceGj€€€H]FXɌ€€5€T{€J€{)ҕ€€€€|4`~€ޡD€P)yl>`€I€8€€e€€€ +€y-€€€\€€x€€(€M€€€r%T]T€€€€,€( +€P'€$D€€"€€€zQw€g€€he€€€€Õ€u€a3€€€:€€X€5×¹ +€݋€M€€P€y€€;€c€,€N.sKB*€^€€u€€€E€€€-€L,€
!N€€d€€€ €€J€€X€/€€~.€€9ϩ€n€€ˎ€€Г€€
]&zq€€Hp]h€€{P €v€:`€€€€€P€€€€€€ɯr€M€.€-€F!€€U€€c€L{€_€€)€€,SJm€0q€$R€p€€̾8X€€,N(€€j€+€DEm8€T€:l7€JWÌ‹t-€€|@€€/€€!€}€€€€2J_ €/w.s`€€€u€X€e€€€€€pq€€N€€bD€€€0€u€€€#>#Lq}€ژ€c€2€€€€w"€S8€€_DC€_€€KO€€€6€\€G€€0b>€€k€€€€€€!X€O€R€u?€~€Ko€;€0æ½¾6>€k€€Ѿ6~€h_€}=€*€€ >€€H€€€؅€^€'€Z€€€k€ަMN`ZpV58€'€7€€t€€&€đ€d€€€eC€LF_f€扚€€€€€€€€Q€(€q€€€€}€€€::€€€ۄ.2€5€L€ €Z€/xӟ€€u]€€~˜y1€€€;Wvn€x[a€Lyf€€€Z€€k€V€X€=x€Ex^€€^€u^€N|uX€€Pb€€|€€€C+€,^€€j€€7€&€P€€€Fe€€vjѹ€T€Z€-€xQ€€€€€€B]€€e€€cX€̵n8w€%€€z€€€€€€€€€:U/N€€eÂ€î ª\e€kD€€€€€vo€O€W€]€€€€€7€€h{€.'€€€€€i#5€7€€€€6z€]€r*p€0€€€€€€€€€€€y€€`iT€€.-€w€;€€€€€o€9€€€1€€g@€U¹€\9€. +.l€)€€A>lU€܇€€€#\A€€<€G€ }Ԅ€€7€€€i2$€€EK\A.i€€€D€E€"€€"€€€€\€€;a8Q€€€€{:€~€€€'-€€€3€€9€€€m€€€`dX€uw€h€€w€j€€}+w€€x'€v€k/€t€x€€€tN€€ +€€€€€€€i€-*J+€€€€€bi€bQT€€€5€
€"€Y€€€'€€:L4€€€€€€ €€€€€s€€€€€˪k`€g4€8€lZX€€b€€&rv€€6€€€€6€€~€€=€o<€€{€€€€€h$
€n€€?€v€€€€
B€€€io€€€€0@€*bd€:€€€}€€€V,€9€€€€€sdMF€€€€€o1b€€€€€7€8Oѵ^€ofq€€€<HO€€€€nj€8c€€>ã¥Â€^sMi€€€K€€g€~l)€њ€V€^\€<€€t€€€€5€€"8€K+€€2\/ +spider.webMPW_SpiderWEB_21Mar93.sitSISITDSIT!€€P€1?F€%\/ weave.webq%\/WebMakefile.unix}%\/webtail+€2!9€2Setg +€€!€<
\ No newline at end of file diff --git a/web/spiderweb/ms-dos/whereis b/web/spiderweb/ms-dos/whereis new file mode 100644 index 0000000000..137bc53d0d --- /dev/null +++ b/web/spiderweb/ms-dos/whereis @@ -0,0 +1,325 @@ +From @pucc.PRINCETON.EDU:HHBODE@DOSUNI1.BITNET Wed Dec 4 10:27:13 1991 +Received: from Princeton.EDU (Princeton.EDU.) by fs.Princeton.EDU (4.0/1.105) + id AA15150; Wed, 4 Dec 91 10:27:12 EST +Received: from pucc.Princeton.EDU by Princeton.EDU (5.65b/2.84/princeton) + id AA22962; Wed, 4 Dec 91 10:27:00 -0500 +Message-Id: <9112041527.AA22962@Princeton.EDU> +Received: from PUCC.PRINCETON.EDU by pucc.PRINCETON.EDU (IBM VM SMTP V2R1) + with BSMTP id 7652; Wed, 04 Dec 91 10:26:37 EST +Received: from DOSUNI1.BITNET by PUCC.PRINCETON.EDU (Mailer R2.08 R208007) with + BSMTP id 4355; Wed, 04 Dec 91 10:26:36 EST +Received: from DOSUNI1 (HHBODE) by DOSUNI1.BITNET (Mailer R2.08) with BSMTP id + 0546; Wed, 04 Dec 91 16:25:55 MEZ +Date: Wed, 04 Dec 91 16:24:12 MEZ +From: Hans-Hermann Bode <HHBODE@DOSUNI1.BITNET> +Subject: PC implementation of Spidery WEB +To: Norman Ramsey <nr@Princeton.EDU> +Status: RO + +Hello, + +I like to let you know about a PC version of your Spidery WEB system that I +implemented. In fact, it is an ANSI-C version also, as appropriate changes +are provided and the PC-related stuff is conditional. The implementation is +available as an archive file spiderpc.zip by anonymous ftp from +dione.rz.uni-osnabrueck.de (in the directory /pub/msdos/tex/web) or from +rusinfo.rus.uni-stuttgart.de (in the directory /soft/tex/web/spiderweb); it +contains the original files (none of it was edited directly, but a few had +to be renamed) and changefiles and makefiles for the PC version. For your +information I append the file readme.pc from spiderpc.zip. + +Hans-Hermann Bode +Arbeitsgruppe Systemforschung, Universit\"at Osnabr\"uck +Tel.: (49)-541-9692545 +e-mail: HHBODE@DOSUNI1.BITNET + +------------------------------------------------README.PC-from-SPIDERPC.ZIP--- + -*-Text-*- +This is the PC implementation of Norman Ramsey's Spidery WEB system, +compiled and provided with changefiles and makefiles for PC-/MS-DOS by +Hans-Hermann Bode <HHBODE@DOSUNI1.BITNET>. The changes are appropriate for +ANSI-C compilers as well as for Turbo C++, where the latter are made +conditional (they will become effective only if the symbol __TURBOC__ is +defined, which automatically is the case when compiled with Turbo C++), so +users of other systems with ANSI-C compilers might be interested also. + +Note that---though the Spider programs itself now should be suitable for +ANSI-C compilers---there is no Spidery ANSI-C WEB yet, i.e., a weave +processor capable to typeset ANSI-C programs is missing (the provided +ceeweave is intended for traditional C only---the tangle processor, on the +other hand, causes no problem, so the make procedure is not affected by +this). You could use the C++ version (ccweave) instead, but this will not +recognize traditional comments (the /*...*/ form). A quick solution might be +to take the C++ Spider source (./cc/cc.spi, see below) and to change the +comment rule appropriately. Possibly, this will be the first exercise for +you in generating a new Spidery WEB. + +To install the system unpack the archive and reproduce the following +directory structure: + +. +./ada +./ada/make +./ada/ada.spi +./ada/stacks.web +./ada/new.spi +./ada/old.spi +./ada/pcmake.sh * +./ada/pcmake.bat * +./ada/adatangl.exe + +./ada/adaweave.exe + +./ada/adaweb.tex + +./awk +./awk/awk.spi +./awk/make +./awk/tangle.c +./awk/nawk.spi +./awk/pcmake.sh * +./awk/pcmake.bat * +./awk/awktangl.exe + +./awk/awkweave.exe + +./awk/awkweb.tex + +./awk/awktangl.c + +./c +./c/local.gui +./c/make +./c/c.spi +./c/tangle.c +./c/pcmake.sh * +./c/pcmake.bat * +./c/ceetangl.exe + +./c/ceeweave.exe + +./c/cweb.tex + +./c/ceetangl.c + +./cc +./cc/make +./cc/cc.spi +./cc/pcmake.sh * +./cc/pcmake.bat * +./cc/cctangle.exe + +./cc/ccweave.exe + +./cc/ccweb.tex + +./dijkstra +./dijkstra/binary.web +./dijkstra/make +./dijkstra/d.spi +./dijkstra/sp.web +./dijkstra/readme +./dijkstra/pcmake.sh * +./dijkstra/pcmake.bat * +./dijkstra/dtangle.exe + +./dijkstra/dweave.exe + +./dijkstra/dijkstra.tex + +./larch +./larch/make +./larch/l.spi +./larch/lists.web +./larch/pcmake.sh * +./larch/pcmake.bat * +./larch/ltangle.exe + +./larch/lweave.exe + +./larch/larchweb.tex + +./penelope +./penelope/make +./penelope/spiderma +./penelope/a.spi +./penelope/nesting.spi +./penelope/stacks.web +./penelope/proc-a.spi +./penelope/scan_ann.awk +./penelope/spimkfil.pc * +./penelope/pcmake.sh * +./penelope/pcmake.bat * +./ssl +./ssl/make +./ssl/s.spi +./ssl/pcmake.sh * +./ssl/pcmake.bat * +./ssl/stangle.exe + +./ssl/sweave.exe + +./ssl/sslweb.tex + +./doc +./doc/spiderma.aux +./doc/spiderwe.toc +./doc/makefile +./doc/cacm.aux +./doc/cacm.tex +./doc/abstract.tex +./doc/spiderma.tex +./doc/overview.aux +./doc/overview.tex +./doc/spiderwe.tex +./doc/descript +./master +./master/cycle.awk +./master/nodups.awk +./master/transche.awk +./master/pathopen.h_0 +./master/multitan.ch +./master/common.web +./master/cycle.web +./master/webhead +./master/spider.awk +./master/webtail +./master/common.h_0 +./master/newdefs.awk +./master/transche.lis +./master/pretty.awk +./master/pathopen.web +./master/make.pre +./master/webmakef +./master/common.c_0 +./master/pathopen.c_0 +./master/makefile +./master/spider.web +./master/junk.lis +./master/weave.web +./master/tangle.web +./master/makefile.pc * +./master/pathopen.ch * +./master/common.ch * +./master/common.hch * +./master/common.h o +./master/tangle.ch * +./master/weave.ch * +./master/pathopen.h + +./master/pathopen.c + +./master/common.c + +./master/common.obj + +./master/pathopen.obj + +./gawk210 +./gawk210/gawk.exe +./gawk210/gawk.1 +./gawk210/gawk.dvi +./gawk210/gawk.tex +./gawk210/texinfo.tex +./gawk210/problems +./gawk210/readme +./gawk210/copying +./readme +./copyrigh +./bugs +./webkerne.tex +./makefile +./readme.pc * + +The files marked with `*' are specific and essential for the PC +implementation, those marked with `+' are the results of pcmake runs (see +below) and are reproducible. The file marked with `o' will not be generated +by pcmake but might be reproduced from masterfile ./master/common.h_0 and +changefile ./master/common.hch by means of a tool like WMERGE or TIE (or by +hand). All files with names ending in `_0' are renamed from the original +distribution, because they are replaced by new ones. The file +./awk/nawk.spi, a Spider source for the new Awk language, is contributed by +Erich Neuwirth. The directory ./gawk210 contains the GNU implementation of +the Awk programming language, Version 2.10; the interpreter, gawk.exe, is +used in the pcmake process. All other files come from the original +distribution of Spidery WEB. + +For more information on the Spider system see the file ./readme and the +documentation in the directory ./doc. For the copyright policy on Spidery +WEB consider the file ./copyrigh. For the same subject on GAWK pay attention +to the file ./gawk210/copying. Unfortunately, I can't tell you where to get +the source files of the PC implementation of GAWK 2.10, since I got the +system myself exactly as it is in ./gawk210 (look in ./gawk210/readme for +contact persons, if required). + +Using Spidery WEB on a PC +------------------------- + +For your convenience, precompiled executables are provided with this +distribution. So, all you have to do is the following: + + - Copy the file ./webkernel.tex to a directory where TeX looks for input +files. + + - Pick up one or more of the directories ./ada, ./awk, ./c, ./cc, +./dijkstra, ./larch, and ./ssl that correspond to the languages you like to +use (cc is actually c++ in the original distribution). Copy the TeX files +(*web.tex) to your TeX-inputs directory, too, and copy the exe files +(*tangle.exe and *weave.exe) to your binaries directory, i.e., a directory +that is in the DOS PATH. + + - That's all! + +Note that there are no executables in the ./penelope directory. This is due +to the fact that GAWK hung up while processing ./penelope/proc-a.spi. I +didn't fix this problem up to now. + +Setting up new Spiders on a PC +------------------------------ + +If you want to build new Spidery WEBs or like to change existing ones, +you'll need the following resources: + + - An Awk interpreter. As GAWK, Version 2.10, is included in this archive, +you don't have to worry about. Notice that GAWK, Version 2.11, will not +work. Other MS-DOS Awk interpreters have not been tested, but probably won't +work also. + + - A C compiler. The executables and object files supplied herein were +compiled with and the changefiles as well as ./master/makefile.pc are +intended for Turbo C++, Version 1.01. Other MS-DOS C compilers may also +work, but you might run into delicate problems with Microsoft C, Version +6.00. + + - A make utility (if you don't prefer to do the job by hand, which would +be a hard one). The file ./master/makefile.pc is intended for Turbo Make, +Version 3.0. + + - A lot of memory. The most storage-consuming process is the interpreting +of the Spider source (*.spi) by GAWK. This will need about 550 to 575 KByte +of memory available on your system, so remove all memory-resident programs +that aren't really necessary. + +The file ./master/makefile.pc provides a full automatic creation of a +Spidery WEB for a certain language from a Spider source file (don't use the +other makefiles in this distribution, they are not intended for PC-/MS-DOS). +For flexibility, several macros have to be defined from the command line; +read the comment at the beginning of the makefile for more information. +Incidentally, a symbol CMD may be defined, in which case the +makefile---besides the interpreter and compiler mentioned above---will use +standard DOS file utilities only; default is to use Unix-like utilities like +cp, sort, and rm. + +Each of the language-specific directories contains a script file, pcmake, +that calls ./master/makefile.pc appropriate for the major Spider source of +the language in question (sometimes, alternative sources are provided; +again, don't use the other make scripts, they won't call the right +makefile). Actually, two versions of pcmake reside in each of these +directories: pcmake.bat is a batch file for use with command.com, pcmake.sh +is a shell script for use with a bourne shell like ms_sh. Because both +command processors will run the corresponding script automatically, simply +type `pcmake' if you use either of these. + +It is assumed that bourne-shell users have the Unix-like file utilities +mentioned above available, thus pcmake.sh will run the makefile without +defining CMD, while pcmake.bat defines it. Besides, in both cases the make +utility will be called under the name `tmake'. If one of these facts doesn't +fit your needs, you have to edit pcmake.sh or pcmake.bat first. + +The make procedure implies a call to both the tangle processors of the Awk +and the C language (awktangle.exe and ceetangle.exe). Hence you must install +those in your binaries directory before doing anything else. If for some +reason you can't use the binaries provided, you have to recompile +./c/ceetangle.c, ./awk/awktangle.c, ./master/common.c, and +./master/pathopen.c (don't forget to define the symbol MSDOS from the +command line) and link the resulting ceetangle.obj and awktangle.obj with +the resulting object files of the ./master sources, respectively. + +When you ever change ./master/pathopen.web or ./master/pathopen.ch, the make +process will generate a new pathopen.h in the current directory. You should +move this file to the ./master directory, so it will not be produced once +more in subsequent runs until it is outdated again. + +By taking all these suggestions into account, after editing one of the +Spider sources you should delete the exe files from the directory in +question and, from that directory, just say `pcmake'. If everything works +alright, after a while you will get new executables *tangle.exe and +*weave.exe and a new macro package *web.tex besides some intermediate files. +You can remove the latter by saying `pcmake clean' (this will not affect the +exe and tex files). If you ceate a Spidery WEB for a new language, you +should take one of the pcmake files as a model to proceed with a similar +procedure. + -H2B- + diff --git a/web/spiderweb/os2/os2.changes b/web/spiderweb/os2/os2.changes new file mode 100644 index 0000000000..0d34a86b0b --- /dev/null +++ b/web/spiderweb/os2/os2.changes @@ -0,0 +1,688 @@ +From bdubbs@cs.tamu.edu Mon Feb 15 18:25:17 1993 +Received: from flash.bellcore.com by mailee.bellcore.com (5.61/1.34) + id AA24579; Mon, 15 Feb 93 18:25:13 -0500 +Received: from NEURON.TAMU.EDU by flash.bellcore.com (5.61/1.34) + id AA06361; Mon, 15 Feb 93 18:25:09 -0500 +Received: by neuron.cs.tamu.edu (AA01812); Mon, 15 Feb 93 17:24:16 CST +Date: Mon, 15 Feb 93 17:24:16 CST +From: bdubbs@cs.tamu.edu (Bruce Dubbs) +Message-Id: <9302152324.AA01812@neuron.cs.tamu.edu> +To: norman@bellcore.com +Subject: Re: Spider Web port to OS/2 +Cc: bart@cs.tamu.edu +Status: RO + +Attached are the final changes I made to the Spider WEB system for +porting to OS/2. Also is the readme.os2 and makefile.emx that I +included in the package. The file, spider.zip, is now at +ftp-os2.nmsu.edu in the /pub/uploads directory, but it should be moved +to the /pub/os2/2.0/programming directory in a week or two. + +I made the bug fixes in common.ch because I did not want to change +your distribution code until you made the changes public. I also made +a slight change to weave.web (weave.ch) because ceeweave was giving +an error at a single @ inside a /* ... */ comment. + + -- Bruce Dubbs + +---readme.os2---------------------------------------------------------- +This is the OS/2 2.0 port of Norman Ramsey's Spider WEB. + +Briefly, WEB is a system that allows the creation of computer source +code and typeset documentation from a single source file. The file is +processed by tangle for input to the target compiler and the same +source is processed be weave for input to TeX for typeset +documentation. + +This port includes the entire source for Ramsey's system that allows +the creation of custom tangle and weave processors for arbitrary +computer languages. Included in the main directory of this port is a +set of OS/2 specific files: + +README.OS2 -- This file +ceeweave.exe -- C Weave executable +ceetangle.exe -- C Tangle executable +awkweave.exe -- AWK Weave executable +awktangle.exe -- AWK Tangle executable +cweb.tex -- include file for Woven C tex files +awkweb.tex -- include file for Woven AWK tex files +makefile.emx -- make for C and AWK executatables and dvi + documentation +common.ch -- change file for common.web +weave.ch -- change file for weave.web +emxlibc.dll -- emx C dynamic link library + +The only change I have made to the original files is to rename +common.c to common.c.old in order to force the makefile to create a +new common.c from the combination of common.web and common.ch. + +INSTALLATION: + +Copy the executables above to a directoru on your PATH. +Copy cweb.tex, awkweb.tex, and webkernel.tex to the directory that TeX +normally looks for inputs. +Copy the emxlibc.dll file to a directory on your LIBPATH. + +>From this point, you should be able to run the appropriate version of +tangle and weave from any location. + +That it. + +NOTES: + +1. I have assumed the files here are on an HPFS directory. This means +that the capability for long filenames is assumed. + +2. The TeX include file webkernel.tex appears to be too long for +tex386, but internally tex386 processes the \input command properly +and will find webkernel.tex properly if it is in the current directory +or the proper TEXINPUT directory. However, tex386 will not recognize +a file on the command line linger tahn the 8.3 format. + +MAKING IT YOURSELF: + +The makefile "makefile.emx" will create the executables and dvi files +of the sources and documentation. The primary commands are: + + make -f makefile.emx exe (default - makes executables) + make -f makefile.emx docs (makes dvi files of documentation) + make -f makefile.emx dvi (makes dvi files from Spider sources) + make -f makefile.emx all (all of the above) + make -f makefile.emx clean (removes all non-essential files) + +It takes about 13 minutes to to a `make all' on my 386/33 + 387 + 16Mb RAM. + +The makefile assumes a lot about utilities that are available. I used +the emx 0.8f gcc compiler, gawk, sort, rm, cat, and sort. It also +uses tex386 from the emTeX package using both plain and LaTeX styles. +All of these are available from ftp-os2.nms.edu. + +If you want to develop one of the other Spider WEB languages, take a +look at the makefile closely. You may even want to develop a Spider +Web for a new language. + + -- Bruce Dubbs + bdubbs@neuron.tamu.edu or + bdubsb@hal.kelly.af.mil (after August 1993) + +REFERENCES: +[1] Wayne Sewell, Weaving a Program: Literate Programming in WEB. +Van Nostrand Reinhold, New York, 1988 + +[2] Donald Knuth, Literate Programming. Center for the Study of +Language and Information, Leland Stanford Junior University, CA, 1992. +--------common.ch------------------------------------------------ +% Change file to common.web for Spider Web generation for OS2 +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +% This file is part of Spidery WEB + +% This program by Norman Ramsey is based on programs Silvio Levy +% and D. E. Knuth. Silvio Levy wrote most of the code. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Dec 1987 + +% Change file by Bruce Dubbs, Texas A&M University, bdubbs@neuron.tamu.edu + + +@x Module 7 Sun Feb 14 01:12:22 1993 +@ The \.{WEAVE} and \.{TANGLE} processors convert between ASCII code and +the user's external character set by means of arrays |xord| and |xchr| +that are analogous to PASCAL's |ord| and |chr| functions. + +@<Definitions...@>= +ASCII xord[last_text_char]; /* specifies conversion of input characters */ +outer_char xchr[@'200]; /* specifies conversion of output characters */ +@y Module 7 Sun Feb 14 01:12:22 1993 +@ The \.{WEAVE} and \.{TANGLE} processors convert between ASCII code and +the user's external character set by means of arrays |xord| and |xchr| +that are analogous to PASCAL's |ord| and |chr| functions. + +We have to change the size of xord to |last_text_char|+1 to cover the +entire 128 byte ASCII array. + +@<Definitions...@>= +ASCII xord[last_text_char+1]; /* specifies conversion of input characters */ +outer_char xchr[@'200]; /* specifies conversion of output characters */ +@z Module 7 Sun Feb 14 01:12:22 1993 + +@x Module 8 Sun Feb 14 01:16:14 1993 +@ Every system supporting \cee\ must be able to read and write the 95 +visible characters of standard ASCII above (although not necessarily using the +ASCII codes to represent them). Conversely, these characters, plus +the newline, are sufficient to write any \cee\ program. Other +characters are desirable mainly in strings, and they can be referred +to by means of escape sequences like \.{'\t'}. + +The basic implementation of \.{WEB}, then, only has to assign an +|xord| to these 95 characters (newlines are swallowed by the reading +routines). The easiest way to do this is to assign the characters to +their positions in |xchr| and then invert the correspondence: + +@<Functions...@>= +common_init() +{ + strcpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "); + @<System-dependent parts of character set@>; + @<Invert |xchr| to get |xord|@>; + @<Initialize pointers@>; + setting_up=1; + @<Scan arguments and open output files@>; + setting_up=0; +} +@y Module 8 Sun Feb 14 01:16:14 1993 +@ Every system supporting \cee\ must be able to read and write the 95 +visible characters of standard ASCII above (although not necessarily using the +ASCII codes to represent them). Conversely, these characters, plus +the newline, are sufficient to write any \cee\ program. Other +characters are desirable mainly in strings, and they can be referred +to by means of escape sequences like \.{'\t'}. + +The basic implementation of \.{WEB}, then, only has to assign an +|xord| to these 95 characters (newlines are swallowed by the reading +routines). The easiest way to do this is to assign the characters to +their positions in |xchr| and then invert the correspondence: + +We make a change here so the string copy does not add a null to the |xchr| +array. + +@<Functions...@>= +common_init() +{ + strncpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ",128); + @<System-dependent parts of character set@>; + @<Invert |xchr| to get |xord|@>; + @<Initialize pointers@>; + setting_up=1; + @<Scan arguments and open output files@>; + setting_up=0; +} +@z Module 8 Sun Feb 14 01:16:14 1993 + +@x Module 28 Sun Feb 14 01:17:40 1993 +@ When a \.{@@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 \.{"..."}; +\.{WEB} will look for include files in standard directories using +the |pathopen| module. +That is set up at the beginning using the {\tt -I} arguments +and the {\tt WEBPATH} environment variable. +@<Add environment variable |"WEBPATH"| to search path@>= + pathaddpath(getenv("WEBPATH"),':'); +@y Module 28 Sun Feb 14 01:17:40 1993 +@ When a \.{@@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 \.{"..."}; +\.{WEB} will look for include files in standard directories using +the |pathopen| module. +That is set up at the beginning using the {\tt -I} arguments +and the {\tt WEBPATH} environment variable. + +We change the path delimeter to a semi-colon for OS/2. + +@<Add environment variable |"WEBPATH"| to search path@>= + pathaddpath(getenv("WEBPATH"),';'); +@z Module 28 Sun Feb 14 01:17:40 1993 + +@x Module 70 Sun Feb 14 01:19:06 1993 +@ @<Set up null...@>= +#ifdef MSDOS +strcpy(change_file_name,"NUL"); +#else +strcpy(change_file_name,"/dev/null"); +#endif +@y Module 70 Sun Feb 14 01:19:06 1993 +@ OS/2 uses {\tt /dev/nul} instead of {\tt /dev/null}. + +@<Set up null...@>= +strcpy(change_file_name,"/dev/nul"); +@z Module 70 Sun Feb 14 01:19:06 1993 +-----------weave.ch--------------------------------------------- +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +% This file is part of Spidery WEB +% This program by Norman Ramsey is based on programs Silvio Levy +% and D. E. Knuth. Silvio Levy wrote most of the code. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Dec 1987 + +% Change made to overcome a small error. There is a comment that +% only use a single at-sign. We change it here to at-at. + +@x +@ Control codes in \.{WEB}, 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_module| should be the largest of +all. Some of these numeric control codes take the place of ASCII +control codes that will not otherwise appear in the output of the +scanning routines. +@^ASCII code@> + +@d ignore = 0 /* control code of no interest to \.{CWEAVE} */ +@d verbatim = @'2 /* extended ASCII alpha will not appear */ + /* extended ASCII beta will not appear */ +@d begin_comment = @'10 /* ASCII tab mark will not appear */ +@d octal = @'14 /* ASCII carriage return will not appear */ +@d hex = @'15 /* ASCII form feed will not appear */ +@d switch_math_flag = @'175 /* this code will be intercepted without confusion */ +@d underline = @'176 /* this code will be intercepted without confusion */ +@d param = @'177 /* ASCII delete will not appear */ +/* identifier =200 or octal @'310 */ +@#/* following three must be conseccutive for indexing to work */ +@d xref_roman = (identifier+roman) /* control code for `\.{@@\^}' */ +@d xref_wildcard = (identifier+wildcard) /* control code for `\.{@@:}' */ +@d xref_typewriter = (identifier+typewriter) /* control code for `\.{@@.}' */ +@d TeX_string = @'356 /* control code for `\.{@@t}' */ +@d ascii_constant = @'357 /* control code for `\.{@@`}' */ +@d join = @'360 /* control code for `\.{@@\&}' */ +@d thin_space = @'361 /* control code for `\.{@@,}' */ +@d math_break = @'362 /* control code for `\.{@@\char'174}' */ +@d line_force = @'363 /* control code for `\.{@@/}' */ +@d line_break = @'364 /* control code for `\.{@@-}' */ +@d big_line_break = @'365 /* control code for `\.{@@\#}' */ +@d no_line_break = @'366 /* control code for `\.{@@+}' */ +@d pseudo_semi = @'367 /* control code for `\.{@@;}' */ +@d vertical_bar = @'370 /* The `\v' used to mark Ada text */ +@d trace = @'371 /* control code for `\.{@@0}', `\.{@@1}' and `\.{@@2}' */ +@d format = @'373 /* control code for `\.{@@f}' */ +@d definition = @'374 /* control code for `\.{@@d}' */ +@d begin_unnamed = @'375 /* control code for `\.{@@u}' */ +@d module_name = @'376 /* control code for `\.{@@<}' */ +@d new_module = @'377 /* control code for `\.{@@\ }' and `\.{@@*}' */ +@y +@ Control codes in \.{WEB}, 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_module| should be the largest of +all. Some of these numeric control codes take the place of ASCII +control codes that will not otherwise appear in the output of the +scanning routines. +@^ASCII code@> + +@d ignore = 0 /* control code of no interest to \.{CWEAVE} */ +@d verbatim = @'2 /* extended ASCII alpha will not appear */ + /* extended ASCII beta will not appear */ +@d begin_comment = @'10 /* ASCII tab mark will not appear */ +@d octal = @'14 /* ASCII carriage return will not appear */ +@d hex = @'15 /* ASCII form feed will not appear */ +@d switch_math_flag = @'175 /* this code will be intercepted without confusion */ +@d underline = @'176 /* this code will be intercepted without confusion */ +@d param = @'177 /* ASCII delete will not appear */ + +% This is where the change is + +/* identifier =200 or octal @@'310 */ + +@#/* following three must be conseccutive for indexing to work */ +@d xref_roman = (identifier+roman) /* control code for `\.{@@\^}' */ +@d xref_wildcard = (identifier+wildcard) /* control code for `\.{@@:}' */ +@d xref_typewriter = (identifier+typewriter) /* control code for `\.{@@.}' */ +@d TeX_string = @'356 /* control code for `\.{@@t}' */ +@d ascii_constant = @'357 /* control code for `\.{@@`}' */ +@d join = @'360 /* control code for `\.{@@\&}' */ +@d thin_space = @'361 /* control code for `\.{@@,}' */ +@d math_break = @'362 /* control code for `\.{@@\char'174}' */ +@d line_force = @'363 /* control code for `\.{@@/}' */ +@d line_break = @'364 /* control code for `\.{@@-}' */ +@d big_line_break = @'365 /* control code for `\.{@@\#}' */ +@d no_line_break = @'366 /* control code for `\.{@@+}' */ +@d pseudo_semi = @'367 /* control code for `\.{@@;}' */ +@d vertical_bar = @'370 /* The `\v' used to mark Ada text */ +@d trace = @'371 /* control code for `\.{@@0}', `\.{@@1}' and `\.{@@2}' */ +@d format = @'373 /* control code for `\.{@@f}' */ +@d definition = @'374 /* control code for `\.{@@d}' */ +@d begin_unnamed = @'375 /* control code for `\.{@@u}' */ +@d module_name = @'376 /* control code for `\.{@@<}' */ +@d new_module = @'377 /* control code for `\.{@@\ }' and `\.{@@*}' */ +@z +----------------makefile.emx-------------------------------------- +# Makefile for awkweb and ceeweb of OS/2 2.0 with emx/gcc +# Run the file from a directory containing the master\ and awk\ +# subdirectories. Edit this file to make the ROOT variable the +# same as your main spider directory. + +# That is, the directory structure should look like: +# spider\ +# spider\master\ +# spider\awk\ +# spider\c\ + + +# make -f makefile.emx [argument] + +CC = gcc -Zomf -Zmt -O +O = .obj +A = .lib + +LIBS = +CFLAGS = + +# Basic directory definitions + +ROOT = \spider + +C = $(ROOT)\c +AWK = $(ROOT)\awk +MASTER = $(ROOT)\master +DOC = $(ROOT)\doc +OS2 = $(ROOT) + +# Executables used + +CTANGLE = $(ROOT)\ceetangle.exe +CWEAVE = $(ROOT)\ceeweave.exe +AWKTANGLE = $(ROOT)\awktangle.exe +AWKWEAVE = $(ROOT)\awkweave.exe +TEX = tex386 +LATEX = $(TEX) `&lplain` + +# Files to make +# Note that we need ceetangle to make a new ceetangle if we do not +# have the C version of tangle.c--its recursive. + +# Also, if we lose spider.awk, it can be remade from spider.web but +# we need awktangle to do it. + + +CEE_EXE = $(CTANGLE) $(CWEAVE) +AWK_EXE = $(AWKTANGLE) $(AWKWEAVE) + +CEE_DVI = $(OS2)\ceeweave.dvi $(OS2)\ctangle.dvi +A_DVI = $(OS2)\awkweave.dvi $(OS2)\atangle.dvi +AWK_DVI = $(OS2)\spider.dvi $(OS2)\cycle.dvi + +COMMON_DVI = $(OS2)\common.dvi +PATHOPEN_DVI = $(OS2)\pathopen.dvi + +CACM = $(OS2)\cacm.dvi +S_WEBMAN = $(OS2)\s_webman.dvi +S_MAN = $(OS2)\s_man.dvi +OVERVIEW = $(OS2)\overview.dvi + + +EXE = $(CEE_EXE) $(AWK_EXE) +DVI = $(COMMON_DVI) $(PATHOPEN_DVI) $(AWK_DVI) $(A_DVI) $(CEE_DVI) + +DOCS = $(CACM) $(S_WEBMAN) $(S_MAN) $(OVERVIEW) + +# What we want to make +# The default is the AWK and C versions of tangle and weave + +exe: $(EXE) + +dvi: $(DVI) + +docs: $(DOCS) + +all: $(EXE) $(DVI) $(DOCS) + +# This is how we make ceeweave and ceetangle + +$(CTANGLE): $(C)\tangle$(O) $(MASTER)\common$(O) $(MASTER)\pathopen$(O) + $(CC) $(CFLAGS) -o $(CTANGLE) $(C)\tangle$(O) $(MASTER)\common$(O) \ + $(MASTER)\pathopen$(O) + +$(C)\tangle$(O): $(C)\tangle.c + cd $(C) + $(CC) $(CFLAGS) -c tangle.c + cd $(OS2) + +$(C)\tangle.c: $(MASTER)\common.h $(C)\outtoks.web $(MASTER)\tangle.web + copy $(MASTER)\tangle.web $(C) + copy $(MASTER)\common.h $(C) + cd $(C) + $(CTANGLE) tangle.web + cd $(OS2) + +$(CWEAVE): $(C)\weave$(O) $(MASTER)\common$(O) $(MASTER)\pathopen$(O) + $(CC) $(CFLAGS) -o $(CWEAVE) $(C)\weave$(O) $(MASTER)\common$(O) \ + $(MASTER)\pathopen$(O) + +$(C)\weave$(O): $(C)\weave.c + cd $(C) + $(CC) $(CFLAGS) -c weave.c + cd $(OS2) + +$(C)\weave.c: $(MASTER)\weave.web $(MASTER)\common.h $(C)\grammar.web + copy $(MASTER)\common.h $(C) + copy $(MASTER)\weave.web $(C) + cd $(C) + $(CTANGLE) weave $(OS2)\weave.ch + rm common.h weave.web + cd $(OS2) + +$(C)\grammar.web $(C)\outtoks.web $(OS2)\cweb.tex: \ + $(MASTER)\cycle.awk $(MASTER)\spider.awk $(C)\c.spider + cd $(C) + gawk -f $(MASTER)\spider.awk c.spider + cat $(MASTER)\transcheck.list trans_keys.unsorted | \ + gawk -f $(MASTER)\transcheck.awk + gawk -f $(MASTER)\cycle.awk < cycle.test + cat *.unsorted | sort | gawk -f $(MASTER)\nodups.awk + copy cweb.tex $(OS2) + cd $(OS2) + +# This is how we make awkweave and awktangle + +$(AWKTANGLE): $(AWK)\tangle$(O) $(MASTER)\common$(O) $(MASTER)\pathopen$(O) + cd $(AWK) + $(CC) $(CFLAGS) -o $(AWKTANGLE) $(AWK)\tangle$(O) $(MASTER)\common$(O)\ + $(MASTER)\pathopen$(O) + cd $(OS2) + +$(AWK)\tangle$(O): $(C)\tangle.c + cd $(AWK) + $(CC) $(CFLAGS) -c tangle.c + cd $(OS2) + +$(AWK)\tangle.c: $(MASTER)\common.h $(AWK)\outtoks.web $(MASTER)\tangle.web + copy $(MASTER)\tangle.web $(AWK) + copy $(MASTER)\common.h $(AWK) + cd $(AWK) + $(CTANGLE) tangle.web + rm $(AWK)\tangle.web $(AWK)\common.h + cd $(OS2) + +$(AWKWEAVE): $(AWK)\weave$(O) $(MASTER)\common$(O) $(MASTER)\pathopen$(O) + $(CC) $(CFLAGS) -o $(AWKWEAVE) $(AWK)\weave$(O) $(MASTER)\common$(O) \ + $(MASTER)\pathopen$(O) + +$(AWK)\weave$(O): $(AWK)\weave.c + cd $(AWK) + $(CC) $(CFLAGS) -c weave.c + cd $(OS2) + +$(AWK)\weave.c: $(MASTER)\weave.web $(MASTER)\common.h $(AWK)\grammar.web + copy $(MASTER)\weave.web $(AWK) + copy $(MASTER)\common.h $(AWK) + cd $(AWK) + $(CTANGLE) weave $(OS2)\weave.ch + cd $(OS2) + +$(AWK)\grammar.web $(AWK)\outtoks.web $(OS2)\awkweb.tex: \ + $(MASTER)\cycle.awk $(MASTER)\spider.awk $(AWK)\awk.spider + cd $(AWK) + gawk -f $(MASTER)\spider.awk awk.spider + cat $(MASTER)\transcheck.list trans_keys.unsorted | \ + gawk -f $(MASTER)\transcheck.awk + gawk -f $(MASTER)\cycle.awk < cycle.test + cat *.unsorted | sort | gawk -f $(MASTER)\nodups.awk + copy awkweb.tex $(OS2) + cd $(OS2) + +$(MASTER)\spider.awk: $(MASTER)\spider.web + cd $(MASTER) + $(AWKTANGLE) $(MASTER)\spider.web + cd $(OS2) + + +# This is how we make the files needed for all executables + +$(MASTER)\pathopen$(O): $(MASTER)\pathopen.c + cd $(MASTER) + $(CC) $(CFLAGS) -c pathopen.c + cd $(OS2) + +$(MASTER)\pathopen.c $(MASTER)\pathopen.h: $(MASTER)\pathopen.web + cd $(MASTER) + $(CTANGLE) pathopen.web + cd $(OS2) + +# Note the OS2 change file here + +$(MASTER)\common.c: $(MASTER)\common.web $(OS2)\common.ch + cd $(MASTER) + $(CTANGLE) common.web $(OS2)\common.ch + cd $(OS2) + +$(MASTER)\common$(O): $(MASTER)\common.c + cd $(MASTER) + $(CC) $(CFLAGS) -c common.c + cd $(OS2) + +$(OS2)\common.dvi: $(MASTER)\common.tex $(OS2)\cweb.tex + copy $(MASTER)\common.tex $(OS2) + -$(TEX) common.tex + rm $(OS2)\common.tex + +$(MASTER)\common.tex: $(MASTER)\common.web $(MASTER)\pathopen.h $(CWEAVE) + cd $(MASTER) + $(CWEAVE) common.web + cd $(OS2) + +$(OS2)\pathopen.dvi: $(MASTER)\pathopen.tex $(OS2)\cweb.tex + copy $(MASTER)\pathopen.tex $(OS2) + -$(TEX) pathopen.tex + rm $(OS2)\pathopen.tex + +$(MASTER)\pathopen.tex: $(MASTER)\pathopen.web $(CWEAVE) + cd $(MASTER) + $(CWEAVE) pathopen.web + cd $(OS2) + +$(OS2)\cycle.dvi: $(MASTER)\cycle.tex $(OS2)\awkweb.tex + copy $(MASTER)\cycle.tex $(OS2) + -$(TEX) cycle.tex + rm $(OS2)\cycle.tex + +$(MASTER)\cycle.tex: $(MASTER)\cycle.web $(AWKWEAVE) + cd $(MASTER) + $(AWKWEAVE) cycle.web + cd $(OS2) + +$(OS2)\spider.dvi: $(MASTER)\spider.tex $(OS2)\awkweb.tex + copy $(MASTER)\spider.tex $(OS2) + -$(TEX) spider.tex + rm $(OS2)\spider.tex + +$(MASTER)\spider.tex: $(MASTER)\spider.web $(AWkWEAVE) + cd $(MASTER) + $(AWKWEAVE) spider.web + cd $(OS2) + +$(OS2)\atangle.dvi: $(AWK)\atangle.tex $(OS2)\cweb.tex + copy $(AWK)\atangle.tex $(OS2) + -$(TEX) atangle.tex + rm $(OS2)\atangle.tex + +$(AWK)\atangle.tex: $(MASTER)\tangle.web $(AWK)\outtoks.web + cd $(AWK) + copy $(MASTER)\common.h $(AWK) + copy $(MASTER)\tangle.web $(AWK) + $(CWEAVE) tangle.web + rename tangle.tex atangle.tex + cd $(OS2) + +$(OS2)\awkweave.dvi: $(AWK)\awkweave.tex $(OS2)\cweb.tex + copy $(AWK)\awkweave.tex $(OS2) + -$(TEX) awkweave.tex + rm $(OS2)\awkweave.tex + +$(AWK)\awkweave.tex: $(MASTER)\weave.web $(AWK)\grammar.web $(OS2)\weave.ch + cd $(AWK) + copy $(MASTER)\common.h $(AWK) + copy $(MASTER)\weave.web $(AWK) + $(CWEAVE) weave.web $(OS2)\weave.ch + rename weave.tex awkweave.tex + cd $(OS2) + +$(OS2)\ceeweave.dvi: $(C)\ceeweave.tex $(OS2)\cweb.tex + copy $(C)\ceeweave.tex $(OS2) + -$(TEX) ceeweave.tex + rm $(OS2)\ceeweave.tex + +$(C)\ceeweave.tex: $(MASTER)\weave.web $(C)\grammar.web $(OS2)\weave.ch + cd $(C) + copy $(MASTER)\common.h $(C) + copy $(MASTER)\weave.web $(C) + $(CWEAVE) weave.web $(OS2)\weave.ch + rename weave.tex ceeweave.tex + cd $(OS2) + +# I wanted to call this ceetangle.dvi, but tex386 only understands +# the 8.3 filenames right now so ceetangle was one character too long. + +$(OS2)\ctangle.dvi: $(C)\ctangle.tex $(OS2)\cweb.tex + copy $(C)\ctangle.tex $(OS2) + -$(TEX) ctangle.tex + rm $(OS2)\ctangle.tex + +$(C)\ctangle.tex: $(MASTER)\tangle.web $(C)\outtoks.web + cd $(C) + copy $(MASTER)\common.h $(C) + copy $(MASTER)\tangle.web $(C) + $(CWEAVE) tangle.web + rename tangle.tex ctangle.tex + cd $(OS2) + +# This cleanup applies to the root directoru, master\, c\, and awk\. + +clean: + cd $(AWK) + -rm -f tangle.* weave.* common.* + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog *.obj + -rm -f *.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + cd $(C) + -rm -f tangle.* weave.* common.* + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog *.obj + -rm -f *.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + cd $(MASTER) + -rm -f *.tex *.obj common.c + cd $(OS2) + -rm -f *.dvi *.log *.toc + +$(CACM): $(DOC)\cacm.tex + copy $(DOC)\cacm.* $(OS2) + -$(LATEX) cacm + -rm -f cacm.tex cacm.aux cacm.log + +$(S_WEBMAN): $(DOC)\spiderwebman.tex + copy $(DOC)\spiderwebman.tex $(OS2)\s_webman.tex + -$(TEX) s_webman.tex + -rm -f *.log *.aux s_webman.tex + +$(S_MAN): $(DOC)\spiderman.tex + copy $(DOC)\spiderman.tex $(OS2)\s_man.tex + -$(LATEX) s_man.tex + -$(LATEX) s_man.tex + -rm -f *.log *.aux s_man.tex + +$(OVERVIEW): $(DOC)\overview.tex + copy $(DOC)\overview.tex $(OS2) + -$(LATEX) overview.tex + -$(LATEX) overview.tex + -rm -f *.log *.aux overview.tex + + + + + + diff --git a/web/spiderweb/patches/001 b/web/spiderweb/patches/001 new file mode 100644 index 0000000000..02a21aedd8 --- /dev/null +++ b/web/spiderweb/patches/001 @@ -0,0 +1,32 @@ +*** WebMakefile~ Thu Apr 6 19:53:39 1989 +--- WebMakefile Sat Apr 8 12:32:06 1989 +*************** +*** 134,139 **** +--- 134,140 ---- + boot: + cd ../master; rm -f *.o; for i in $(COMMONC); do \ + cc $(CFLAGS) -c $$i; \ ++ mv *.o $(OBDIR) ; \ + done; cd ../c + cc $(CFLAGS) -c $(TANGLESRC).c; \ + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o +*** spider.web~ Thu Apr 6 13:57:13 1989 +--- spider.web Sat Apr 8 12:49:58 1989 +*************** +*** 1133,1139 **** + if (tempfile==ttokfile) { ## output to \.{TANGLE} + #<If |t| is |"string"|, |"constant"|, or |"identifier"|, + just |continue|#> ## already defined in \.{TANGLE} +! temp = temp + #'37 - highesttoken ## hackety hack! + } + printf "@d %s = %s\n", tokenname[t], temp > tempfile + } +--- 1133,1140 ---- + if (tempfile==ttokfile) { ## output to \.{TANGLE} + #<If |t| is |"string"|, |"constant"|, or |"identifier"|, + just |continue|#> ## already defined in \.{TANGLE} +! temp = temp + #'37 + 3 - highesttoken ## hackety hack! +! ## +3 because three highest are already defined! + } + printf "@d %s = %s\n", tokenname[t], temp > tempfile + } diff --git a/web/spiderweb/patches/002 b/web/spiderweb/patches/002 new file mode 100644 index 0000000000..c120280709 --- /dev/null +++ b/web/spiderweb/patches/002 @@ -0,0 +1,95 @@ +*** README.old Sat Apr 8 12:55:24 1989 +--- README Mon Apr 10 12:16:25 1989 +*************** +*** 33,38 **** +--- 33,44 ---- + + 6) Go into WEBROOT and type `make boot' + ++ Once this is successful you will have executable versions of tangle for ++ C and Awk, which is the minumum needed to make other things. After you've ++ done this, you can afford to `make clean', which will remove the .c and ++ .awk source you used to bootstrap yourself. You can always make them over ++ again using the executable versions (`make source'). ++ + 7) Move webkernel.tex into a place where TeX can find it + + +*** Makefile.old Mon Apr 10 12:10:11 1989 +--- Makefile Mon Apr 10 12:14:16 1989 +*************** +*** 2,11 **** + # Not to be sold, but may be used freely for any purpose + # For more information, see file COPYRIGHT in the parent directory + +! # This is a SUN OS 4 Makefile. Sorry. + + MAKE=make $(MFLAGS) + DIRECTORIES=ada awk c dijkstra larch penelope ssl doc master + clean: + @for i in $(DIRECTORIES); do \ + cd $$i; \ +--- 2,16 ---- + # Not to be sold, but may be used freely for any purpose + # For more information, see file COPYRIGHT in the parent directory + +! # This is a SUN OS 4 Makefile. Sorry. Makefiles in subdirectories +! # should work under any reasonable Make. + + MAKE=make $(MFLAGS) + DIRECTORIES=ada awk c dijkstra larch penelope ssl doc master ++ ++ # Removes excess junk from the world, except it doesn't remove ++ # common object files from ./master ++ # This destroys the sources, so don't make clean until you've made boot. + clean: + @for i in $(DIRECTORIES); do \ + cd $$i; \ +*************** +*** 16,34 **** + rm -f *~ + @echo "All done." + + source: + cd c ; $(MAKE) source ; cd .. + cd awk ; $(MAKE) source ; cd .. + + distribution: + # $(MAKE) clean + # $(MAKE) source +! tar cvhf spiderweb.tar README COPYRIGHT BUGS webkernel.tex Makefile $(DIRECTORIES) + + boot: + cd c; $(MAKE) boot; cd .. + cd awk; $(MAKE) boot; cd .. + + all: + @for i in $(DIRECTORIES); do \ + cd $$i; \ +--- 21,46 ---- + rm -f *~ + @echo "All done." + ++ # This creates the minimum sources in preparation for `make distribution' + source: + cd c ; $(MAKE) source ; cd .. + cd awk ; $(MAKE) source ; cd .. + ++ # Put everything into a tar file. Must `make source' first, and should clean + distribution: + # $(MAKE) clean ++ cd master ; make superclean ; cd .. # remove common .o from master + # $(MAKE) source +! tar cvhf spiderweb.tar README COPYRIGHT BUGS webkernel.tex \ +! Makefile $(DIRECTORIES) + ++ # Used to bring up the system when first installing it. Requires sources, ++ # either from the distribution tarfile or from `make source' + boot: + cd c; $(MAKE) boot; cd .. + cd awk; $(MAKE) boot; cd .. + ++ # Make all known webs. For lunatics only. + all: + @for i in $(DIRECTORIES); do \ + cd $$i; \ diff --git a/web/spiderweb/patches/003 b/web/spiderweb/patches/003 new file mode 100644 index 0000000000..e5d5931076 --- /dev/null +++ b/web/spiderweb/patches/003 @@ -0,0 +1,179 @@ +*** doc/cacm.tex.old Thu Apr 6 14:01:25 1989 +--- doc/cacm.tex Mon Apr 10 14:47:13 1989 +*************** +*** 182,188 **** + \put(125,30){\line(-1,-1){10}} + \put(115,20){\vector(-1,0){25}} + +! \put(104,21.5){\makebox(0,0)[b]{\scriptsize\sl CWEAVE}} + + \put(60,15){\framebox(30,10){xtangle.c}} + \put(60,-25){\framebox(30,10){xweave.c}} +--- 182,188 ---- + \put(125,30){\line(-1,-1){10}} + \put(115,20){\vector(-1,0){25}} + +! \put(104,21.5){\makebox(0,0)[b]{\scriptsize\sl CTANGLE}} + + \put(60,15){\framebox(30,10){xtangle.c}} + \put(60,-25){\framebox(30,10){xweave.c}} +*** Makefile.old Mon Apr 10 11:14:16 1989 +--- Makefile Tue Apr 11 11:51:42 1989 +*************** +*** 29,35 **** + # Put everything into a tar file. Must `make source' first, and should clean + distribution: + # $(MAKE) clean +- cd master ; make superclean ; cd .. # remove common .o from master + # $(MAKE) source + tar cvhf spiderweb.tar README COPYRIGHT BUGS webkernel.tex \ + Makefile $(DIRECTORIES) +--- 29,34 ---- +*** master/Makefile.old Thu Apr 6 19:37:11 1989 +--- master/Makefile Tue Apr 11 11:55:29 1989 +*************** +*** 2,12 **** + # Not to be sold, but may be used freely for any purpose + # For more information, see file COPYRIGHT in the parent directory + + clean: + -rm -f *.tex *.dvi *.log *.wlog *~ *.toc + + superclean: +! -rm -f *.c *.o + -rm -f *.tex *.dvi *.log *~ *.toc +- -rm -f sun3/*.o vax/*.o + +--- 2,18 ---- + # Not to be sold, but may be used freely for any purpose + # For more information, see file COPYRIGHT in the parent directory + ++ OBJECTDIRS=sun3 vax ++ + clean: + -rm -f *.tex *.dvi *.log *.wlog *~ *.toc ++ @-for i in $(OBJECTDIRS); do \ ++ rm -f $$i/*.o; \ ++ done ++ -rm -f *.o + + superclean: +! -rm -f sun3/*.o vax/*.o *.o +! -rm -f *.c + -rm -f *.tex *.dvi *.log *~ *.toc + +*** master/spider.web.old Tue Apr 11 13:19:58 1989 +--- master/spider.web Tue Apr 11 14:02:06 1989 +*************** +*** 1939,1945 **** + if (n%5==0) + print "@ @<Test for all of the productions@>=" \ + > grammarfile ## avoids overflowing \.{WEAVE} of \.{WEAVE} +! #<Remove \vert\ from |inputline[n]| and put results in |this_string|#> + #<Make |this_string| no more than 60 characters wide#> + printf "if (%s) {\n\t/* %d: {\\tt %s} */\n%s",\ + prodtest[n],n,this_string,prodtrans[n] > grammarfile +--- 1939,1945 ---- + if (n%5==0) + print "@ @<Test for all of the productions@>=" \ + > grammarfile ## avoids overflowing \.{WEAVE} of \.{WEAVE} +! #<Change \vert,\_, and {\tt \##} in |inputline[n]|; put results in |this_string|#> + #<Make |this_string| no more than 60 characters wide#> + printf "if (%s) {\n\t/* %d: {\\tt %s} */\n%s",\ + prodtest[n],n,this_string,prodtrans[n] > grammarfile +*************** +*** 1991,2005 **** + # It's desirable to put the production in a comment, but we have to + get rid of the confusing \vert, or \.{WEAVE} will think it introduces + code. +! #<Remove \vert\ from |inputline[n]| and put results in |this_string|#>= +! this_string = inputline[n] + tempi = index(this_string,"|") +! while (tempi != 0) { +! tempa = substr(this_string,1,tempi-1) +! tempb = substr(this_string,tempi+1) +! this_string = tempa "\\vert " tempb +! tempi = index(this_string,"|") +! } + + + # We have to keep these productions from making an input line too long. +--- 1991,2025 ---- + # It's desirable to put the production in a comment, but we have to + get rid of the confusing \vert, or \.{WEAVE} will think it introduces + code. +! We also have to escape underscores and sharp signs, otherwise \TeX\ will +! think we want math mode. +! #<Change \vert,\_, and {\tt \##} in |inputline[n]|; put results in |this_string|#>= +! this_string = inputline[n] +! tempi = index(this_string,"|") +! while (tempi != 0) { +! tempa = substr(this_string,1,tempi-1) +! tempb = substr(this_string,tempi+1) +! this_string = tempa "\\vert " tempb + tempi = index(this_string,"|") +! } +! templ = ""; tempr = this_string +! tempi = index(tempr,"_") +! while (tempi != 0) { +! tempa = substr(tempr,1,tempi-1) +! tempr = substr(tempr,tempi+1) +! templ = templ tempa "\\_" +! tempi = index(tempr,"_") +! } +! this_string = templ tempr +! templ = ""; tempr = this_string +! tempi = index(tempr,"##") +! while (tempi != 0) { +! tempa = substr(tempr,1,tempi-1) +! tempr = substr(tempr,tempi+1) +! templ = templ tempa "\\##" +! tempi = index(tempr,"##") +! } +! this_string = templ tempr + + + # We have to keep these productions from making an input line too long. +*** doc/spiderwebman.tex.old Thu Apr 6 14:01:32 1989 +--- doc/spiderwebman.tex Tue Apr 11 14:24:39 1989 +*************** +*** 579,599 **** + can define two kinds of macros to make the programs shorter and more + readable. + +! \yskip\hang`\.{@d} \\{identifier} \PASCAL\ text' defines a {\sl + simple\/} macro, where the identifier will be replaced by the \PASCAL\ text + when \.{TANGLE} produces its output. + +! \yskip\hang`\.{@d} \\{identifier}\.{(\\{ actual identifiers})} \PASCAL\ text' defines a + {\sl parametric\/} macro, where the identifier will be replaced by the \PASCAL\ + text and where occurrences of the \\{identifiers} in that \PASCAL\ text will be + replaced by arguments. + +! C programmers will recognize the C macro processor. +! The implementation relies on the C preprocessor to expand the macros. +! The author of \.{Spider} \.{WEB} intends to correct this unfortunate +! historical accident at the earliest opportunity, by restoring +! \.{WEB}'s built-in macro processor. +! + + + +--- 579,595 ---- + can define two kinds of macros to make the programs shorter and more + readable. + +! \yskip\hang`\.{@d} \\{identifier} = \PASCAL\ text' defines a {\sl + simple\/} macro, where the identifier will be replaced by the \PASCAL\ text + when \.{TANGLE} produces its output. + +! \yskip\hang`\.{@d} \\{identifier}\.{(\\{ actual identifiers})} = \PASCAL\ text' defines a + {\sl parametric\/} macro, where the identifier will be replaced by the \PASCAL\ + text and where occurrences of the \\{identifiers} in that \PASCAL\ text will be + replaced by arguments. + +! For C programmers, this is similar to the C macro processor. +! \endnewstuff + + + diff --git a/web/spiderweb/patches/004 b/web/spiderweb/patches/004 new file mode 100644 index 0000000000..72dee88b34 --- /dev/null +++ b/web/spiderweb/patches/004 @@ -0,0 +1,70 @@ +*** master/weave.web.old Fri Apr 14 12:31:34 1989 +--- master/weave.web Fri Apr 14 12:33:28 1989 +*************** +*** 353,359 **** + + @d ignore = 0 /* control code of no interest to \.{CWEAVE} */ + @d verbatim = @'2 /* extended ASCII alpha will not appear */ +! @d tangle_force_line = @'3 /* extended ASCII beta will not appear */ + @d begin_comment = @'10 /* ASCII tab mark will not appear */ + @d octal = @'14 /* ASCII carriage return will not appear */ + @d hex = @'15 /* ASCII form feed will not appear */ +--- 353,359 ---- + + @d ignore = 0 /* control code of no interest to \.{CWEAVE} */ + @d verbatim = @'2 /* extended ASCII alpha will not appear */ +! /* extended ASCII beta will not appear */ + @d begin_comment = @'10 /* ASCII tab mark will not appear */ + @d octal = @'14 /* ASCII carriage return will not appear */ + @d hex = @'15 /* ASCII form feed will not appear */ +*************** +*** 395,401 **** + ccode['-']=line_break; + ccode['#']=big_line_break; + ccode['=']=verbatim; +- ccode['\\']=tangle_force_line; + ccode['d']=ccode['D']=definition; + ccode['f']=ccode['F']=format; + ccode['c']=ccode['C']=begin_unnamed; +--- 395,400 ---- +*************** +*** 2026,2032 **** + break; + case xref_roman: case xref_wildcard: case xref_typewriter: + break; +- case tangle_force_line: app_str("\\]"); app_scrap(SP_ignore_scrap,yes_math); break; + case thin_space: app_str("\\,"); app_scrap(SP_ignore_scrap,yes_math); break; + case math_break: + small_app(opt); app_str("0"); app_scrap(SP_ignore_scrap,yes_math); break; +--- 2025,2030 ---- +*** doc/spiderwebman.tex.old Fri Apr 14 12:32:11 1989 +--- doc/spiderwebman.tex Fri Apr 14 12:39:57 1989 +*************** +*** 952,958 **** + \@= [\PAS] The ``control text'' that follows, up to the next `\.{@>}', will + be passed verbatim to the \PASCAL\ program. + +! \@\\ [\PAS] Force end-of-line here in the \PASCAL\ program file. + + \@! [\PAS,T] The module number in an index entry will be underlined if `\.{@!}' + immediately precedes the identifier or control text being indexed. +--- 952,958 ---- + \@= [\PAS] The ``control text'' that follows, up to the next `\.{@>}', will + be passed verbatim to the \PASCAL\ program. + +! %%% \@\\ [\PAS] Force end-of-line here in the \PASCAL\ program file. + + \@! [\PAS,T] The module number in an index entry will be underlined if `\.{@!}' + immediately precedes the identifier or control text being indexed. +*************** +*** 982,987 **** +--- 982,990 ---- + \@? + [\PAS,T] This cancels an implicit (or explicit) `\.{@!}', so that the next + index entry will not be underlined. ++ ++ \newstuff This is not implemented in the current version of Spidery \.{WEB}. ++ \endnewstuff + + \@, [\PAS] This control code inserts a thin space in \.{WEAVE}'s output; it is + ignored by \.{TANGLE}. diff --git a/web/spiderweb/patches/005 b/web/spiderweb/patches/005 new file mode 100644 index 0000000000..52f9a47999 --- /dev/null +++ b/web/spiderweb/patches/005 @@ -0,0 +1,74 @@ +*** master/spider.web~ Tue Apr 11 14:02:06 1989 +--- master/spider.web Mon Jul 3 12:46:05 1989 +*************** +*** 772,778 **** + } else if (length($2)>1) { + #<Handle multicharacter tokens#> + } else { +! temp = sprintf "'%s'", $2 + tokenname[$2] = temp + tokenlength[$2]=1 + } +--- 772,778 ---- + } else if (length($2)>1) { + #<Handle multicharacter tokens#> + } else { +! temp = sprintf("'%s'", $2) + tokenname[$2] = temp + tokenlength[$2]=1 + } +*************** +*** 791,797 **** + tokennumbers[$2]=tokennumber + tokennumber-- + ## figure out how to recognize the token +! temp = sprintf "strncmp(\"%s\",loc-1,%d)==0", $2, length($2) + tokentest[$2]=temp + tokenlength[$2]=length($2) + +--- 791,797 ---- + tokennumbers[$2]=tokennumber + tokennumber-- + ## figure out how to recognize the token +! temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, length($2)) + tokentest[$2]=temp + tokenlength[$2]=length($2) + +*************** +*** 1738,1744 **** + $i = substr($i,2) ## peel off the \## + #<Make sure |1 <= $i < arrowpos|#> + targetcategory[prodnum]="Unnamed category" +! temp = sprintf "(pp+%d)->cat", $i-1 + unnamed_cat[prodnum]=temp + } else if ($i ~ #=/[a-z][a-z_]*/#>) { ## a category + targetcategory[prodnum]=$i +--- 1738,1744 ---- + $i = substr($i,2) ## peel off the \## + #<Make sure |1 <= $i < arrowpos|#> + targetcategory[prodnum]="Unnamed category" +! temp = sprintf("(pp+%d)->cat", $i-1) + unnamed_cat[prodnum]=temp + } else if ($i ~ #=/[a-z][a-z_]*/#>) { ## a category + targetcategory[prodnum]=$i +*** webkernel.tex.old Mon Jun 26 12:32:33 1989 +--- webkernel.tex Mon Jun 26 12:35:38 1989 +*************** +*** 218,224 **** + \global\output{\normaloutput\page\lheader\rheader\lfooter\rfooter}} + \setpage + \vbox to \vsize{} % the first \topmark won't be null +! \eject + \write\cont{\string\catcode`\string\@=11}% a hack to make contents + % take stuff in \.{---} + +--- 218,226 ---- + \global\output{\normaloutput\page\lheader\rheader\lfooter\rfooter}} + \setpage + \vbox to \vsize{} % the first \topmark won't be null +! % Delete as per bug report from kademan@stat.wisc.edu +! % Causes headings on first page to be missing +! % \eject + \write\cont{\string\catcode`\string\@=11}% a hack to make contents + % take stuff in \.{---} + diff --git a/web/spiderweb/patches/006 b/web/spiderweb/patches/006 new file mode 100644 index 0000000000..361103571a --- /dev/null +++ b/web/spiderweb/patches/006 @@ -0,0 +1,92 @@ +*** master/spider.web.old Mon Jul 3 12:46:05 1989 +--- master/spider.web Thu Jul 20 19:00:04 1989 +*************** +*** 1532,1537 **** +--- 1532,1541 ---- + each scrap is true, the whole production will fire. + If we're called upon to make a scrap underlined or reserved, we'll add + to |trans[pos]|. ++ ++ If a category is negated we add an extra clause to make ++ sure nothing matches the zero category, since {\tt WEAVE} assumes ++ no production ever matches a scrap with category zero. + #<Process a single category#>= + field[pos]=$i ## save this field to compare RHS + #<Set |negation|, and remove leading |"!"| from |$i| if necessary#> +*************** +*** 1540,1548 **** + cat = $i + categories[cat]=1 ## remember |cat| is a category + if (negation==0) { +! test[pos]=sprintf("(pp+%d)->cat==SP_%s",pos-1,cat) + } else { +! test[pos]=sprintf("(pp+%d)->cat!=SP_%s",pos-1,cat) + } + #<Update the record of the rightmost occurrence of category |cat|#> + #<Advance |pos|, making the new |trans[pos]| empty#> +--- 1544,1553 ---- + cat = $i + categories[cat]=1 ## remember |cat| is a category + if (negation==0) { +! test[pos]=sprintf("(pp+%d)->cat==SP_%s",pos-1,cat) + } else { +! test[pos]=sprintf("((pp+%d)->cat!=SP_%s && (pp+%d)->cat != 0)",\ +! pos-1,cat,pos-1) + } + #<Update the record of the rightmost occurrence of category |cat|#> + #<Advance |pos|, making the new |trans[pos]| empty#> +*************** +*** 1551,1556 **** +--- 1556,1565 ---- + categories are separated by vertical bars. + We have to make the test for these things a disjunction, but + processing is more or less like the processing for a single category. ++ ++ If a list of alternatives is negated we add an extra clause to make ++ sure nothing matches the zero category, since {\tt WEAVE} assumes ++ no production ever matches a scrap with category zero. + #<Process a list of alternative categories#>= + field[pos]=$i ## save this field to compare RHS + #<Set |negation|, and remove leading |"!"| from |$i| if necessary#> +*************** +*** 1557,1563 **** + if (negation==0) { + test[pos]="(" ## open for a list of good alternatives + } else { +! test[pos]="!(" ## open for a list of bad alternatives + } + #<Strip stars from |$i| (if any) and add appropriate + translations to |trans[pos]|#> +--- 1566,1573 ---- + if (negation==0) { + test[pos]="(" ## open for a list of good alternatives + } else { +! temp=sprintf("(pp+%d)->cat==0",pos-1) +! test[pos]="!(" temp "||" ## open for a list of bad alternatives + } + #<Strip stars from |$i| (if any) and add appropriate + translations to |trans[pos]|#> +*************** +*** 1635,1644 **** + #<Forget this production#> + } + +! # Wild cards are easy to process + #<Process a category wild card#>= + field[pos]=$i ## save this field to compare RHS +! test[pos]="(1)" ## anything matches + highwildcard=pos ## we don't really need this? + #<Advance |pos|, making the new |trans[pos]| empty#> + +--- 1645,1655 ---- + #<Forget this production#> + } + +! # Wild cards are easy to process, but we do have to remember that +! not even a wild card matches a scrap of category zero. + #<Process a category wild card#>= + field[pos]=$i ## save this field to compare RHS +! test[pos]=sprintf("(pp+%d)->cat!=0",pos-1) ## anything nonzero matches + highwildcard=pos ## we don't really need this? + #<Advance |pos|, making the new |trans[pos]| empty#> + diff --git a/web/spiderweb/patches/007 b/web/spiderweb/patches/007 new file mode 100644 index 0000000000..0dc52bbdad --- /dev/null +++ b/web/spiderweb/patches/007 @@ -0,0 +1,188 @@ +*** master/spider.web.old Wed Aug 23 14:08:45 1989 +--- master/spider.web Wed Aug 23 14:03:12 1989 +*************** +*** 314,322 **** + + # If the macro facility worked right, + we would use the following patterns to recognize items as they occur: +! #d cat_pattern = #=/[a-z][a-z_]*/#> +! #d trans_pattern = #=/<(([0-9]|[a-z][a-z_]*|"([^"]*\\")*[^"]*"|\*)-)*#>#& +! #=([0-9]|[a-z][a-z_]*|"([^"]*\\")*[^"]*"|\*)>/#> + + # Here's where we swallow a translation and spit out the \.{WEAVE} code + to handle that translation. +--- 314,322 ---- + + # If the macro facility worked right, + we would use the following patterns to recognize items as they occur: +! #d cat_pattern = #=/[a-zA-Z][a-zA-Z_]*/#> +! #d trans_pattern = #=/<(([0-9]|[a-zA-Z][a-zA-Z_]*|"([^"]*\\")*[^"]*"|\*)-)*#>#& +! #=([0-9]|[a-zA-Z][a-zA-Z_]*|"([^"]*\\")*[^"]*"|\*)>/#> + + # Here's where we swallow a translation and spit out the \.{WEAVE} code + to handle that translation. +*************** +*** 341,347 **** + if (alternate ~ #=/^[0-9]$/#>) { ## digit + temp = sprintf("\tapp_str(\"%s\");\n",alternate) + outstring=outstring temp +! } else if (alternate ~ #=/^[a-z_]+$/#>) { ## key word + translation_keywords[alternate]=1 ## remember + temp = sprintf("\t%s(%s);\n",append_keyword,alternate) + ##Call |app| or |small_app| depending whether we're reducing or creating scraps +--- 341,347 ---- + if (alternate ~ #=/^[0-9]$/#>) { ## digit + temp = sprintf("\tapp_str(\"%s\");\n",alternate) + outstring=outstring temp +! } else if (alternate ~ #=/^[a-zA-Z_]+$/#>) { ## key word + translation_keywords[alternate]=1 ## remember + temp = sprintf("\t%s(%s);\n",append_keyword,alternate) + ##Call |app| or |small_app| depending whether we're reducing or creating scraps +*************** +*** 394,400 **** + if (alternate ~ #=/^[0-9]$/#>) { ## digit + print "Digit not allowed in restricted translation", wherestring + exitcode = -1 +! } else if (alternate ~ #=/^[a-z_]+$/#>) { ## key word + print "Key word not allowed in restricted translation", wherestring + exitcode = -1 + } else if (alternate ~ #=/^\"([^"]*\\\")*[^"]*\"$/#>) { ## string +--- 394,400 ---- + if (alternate ~ #=/^[0-9]$/#>) { ## digit + print "Digit not allowed in restricted translation", wherestring + exitcode = -1 +! } else if (alternate ~ #=/^[a-zA-Z_]+$/#>) { ## key word + print "Key word not allowed in restricted translation", wherestring + exitcode = -1 + } else if (alternate ~ #=/^\"([^"]*\\\")*[^"]*\"$/#>) { ## string +*************** +*** 576,582 **** + #<Process newline token description#> + } else if ($2=="pseudo_semi") { + #<Process |pseudo_semi| token description#> +! } else if ($2 ~ #=/[a-zA-Z0-9]+/#>) { + ## we recognize no other names + print "Error: unknown token species:", $2 + #<Punt this command#> +--- 576,582 ---- + #<Process newline token description#> + } else if ($2=="pseudo_semi") { + #<Process |pseudo_semi| token description#> +! } else if ($2 ~ #=/[a-zA-ZA-Z0-9]+/#>) { + ## we recognize no other names + print "Error: unknown token species:", $2 + #<Punt this command#> +*************** +*** 1200,1206 **** + that an item of ilk |fish_like| will get category |fish|. + + #<If no category is specified, invent a default if you can#>= +! if ($2 ~ #=/^[a-z_]+_like$/#> && $0 !~ #=/ category /#>) { + ## give default category + this_category = substr($2,1,length($2)-5) + categories[this_category]=1 +--- 1200,1206 ---- + that an item of ilk |fish_like| will get category |fish|. + + #<If no category is specified, invent a default if you can#>= +! if ($2 ~ #=/^[a-zA-Z_]+_like$/#> && $0 !~ #=/ category /#>) { + ## give default category + this_category = substr($2,1,length($2)-5) + categories[this_category]=1 +*************** +*** 1490,1498 **** + for (i=1; i<=NF; i++) { + if ($i ~ #=/<.*>/#>) { ## should be |trans_pattern| + #<Process a translation in |$i|#> +! } else if ($i ~ #=/^!?[a-z_]+(\*\*?)?$/#>) { ## |cat_pattern| + #<Process a single category#> +! } else if ($i ~ #=/^!?\(([a-z_]+\|)*[a-z_]+\)(\*\*?)?$/#>){ + #<Process a list of alternative categories#> + } else if ($i == "?") { + #<Process a category wild card#> +--- 1490,1498 ---- + for (i=1; i<=NF; i++) { + if ($i ~ #=/<.*>/#>) { ## should be |trans_pattern| + #<Process a translation in |$i|#> +! } else if ($i ~ #=/^!?[a-zA-Z_]+(\*\*?)?$/#>) { ## |cat_pattern| + #<Process a single category#> +! } else if ($i ~ #=/^!?\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/#>){ + #<Process a list of alternative categories#> + } else if ($i == "?") { + #<Process a category wild card#> +*************** +*** 1632,1642 **** + + #<Strip stars from |$i| (if any) and add appropriate + translations to |trans[pos]|#>= +! if ($i ~ #=/^([a-z_]+|\(([a-z_]+\|)*[a-z_]+\))\*\*$/#>) { ## it's double-starred + temp = sprintf("\tmake_underlined(pp+%d);\n",pos-1) + trans[pos] = trans[pos] temp + $i = substr($i,1,length($i)-2) +! } else if ($i ~ #=/^([a-z_]+|\(([a-z_]+\|)*[a-z_]+\))\*$/#>) { ## it's starred + temp = sprintf("\tmake_underlined(pp+%d);\n",pos-1) + trans[pos] = trans[pos] temp + $i = substr($i,1,length($i)-1) +--- 1632,1642 ---- + + #<Strip stars from |$i| (if any) and add appropriate + translations to |trans[pos]|#>= +! if ($i ~ #=/^([a-zA-Z_]+|\(([a-zA-Z_]+\|)*[a-zA-Z_]+\))\*\*$/#>) { ## it's double-starred + temp = sprintf("\tmake_underlined(pp+%d);\n",pos-1) + trans[pos] = trans[pos] temp + $i = substr($i,1,length($i)-2) +! } else if ($i ~ #=/^([a-zA-Z_]+|\(([a-zA-Z_]+\|)*[a-zA-Z_]+\))\*$/#>) { ## it's starred + temp = sprintf("\tmake_underlined(pp+%d);\n",pos-1) + trans[pos] = trans[pos] temp + $i = substr($i,1,length($i)-1) +*************** +*** 1751,1757 **** + targetcategory[prodnum]="Unnamed category" + temp = sprintf("(pp+%d)->cat", $i-1) + unnamed_cat[prodnum]=temp +! } else if ($i ~ #=/[a-z][a-z_]*/#>) { ## a category + targetcategory[prodnum]=$i + categories[$i]=1 ## remember this is a category + } else { +--- 1751,1757 ---- + targetcategory[prodnum]="Unnamed category" + temp = sprintf("(pp+%d)->cat", $i-1) + unnamed_cat[prodnum]=temp +! } else if ($i ~ #=/[a-zA-Z][a-zA-Z_]*/#>) { ## a category + targetcategory[prodnum]=$i + categories[$i]=1 ## remember this is a category + } else { +*************** +*** 1827,1833 **** + temp = field[pos] + tempa = substr(temp,1,1) + if (tempa != "!") { +! if (temp ~ #=/^\(([a-z_]+\|)*[a-z_]+\)(\*\*?)?$/#>) { + ## list of alternatives + #<Remove trailing stars from |temp|#> + temp = substr(temp,2,length(temp)-2) +--- 1827,1833 ---- + temp = field[pos] + tempa = substr(temp,1,1) + if (tempa != "!") { +! if (temp ~ #=/^\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/#>) { + ## list of alternatives + #<Remove trailing stars from |temp|#> + temp = substr(temp,2,length(temp)-2) +*************** +*** 1836,1842 **** + alternate = tok[j] + reduced[alternate]=1 + } +! } else if (temp ~ #=/^[a-z_]+(\*\*?)?$/#>) { + #<Remove trailing stars from |temp|#> + reduced[temp]=1 + } else if (temp != "?") { +--- 1836,1842 ---- + alternate = tok[j] + reduced[alternate]=1 + } +! } else if (temp ~ #=/^[a-zA-Z_]+(\*\*?)?$/#>) { + #<Remove trailing stars from |temp|#> + reduced[temp]=1 + } else if (temp != "?") { diff --git a/web/spiderweb/patches/008 b/web/spiderweb/patches/008 new file mode 100644 index 0000000000..d0e0615e3a --- /dev/null +++ b/web/spiderweb/patches/008 @@ -0,0 +1,29 @@ +*** c/c.spider.old Wed Nov 29 22:48:59 1989 +--- c/c.spider Wed Nov 29 21:55:48 1989 +*************** +*** 18,28 **** + + token + category unorbinop + token - category unorbinop +! token * category unorbinop translation <"{*}"> + token / category dot + token < category less translation <> + token > category greater translation <> + token = category equals translation <"\\leftarrow"> tangleto <"="-space> + token . category dot + token ~ category unop translation <"\\TI"> + token & category unorbinop translation <"\\amp"> +--- 18,30 ---- + + token + category unorbinop + token - category unorbinop +! token * category unorbinop translation <"{*}"> tangleto <space-"*"> +! # avoid inadvertant /* + token / category dot + token < category less translation <> + token > category greater translation <> + token = category equals translation <"\\leftarrow"> tangleto <"="-space> ++ # avoid inadvertant =- + token . category dot + token ~ category unop translation <"\\TI"> + token & category unorbinop translation <"\\amp"> diff --git a/web/spiderweb/patches/009 b/web/spiderweb/patches/009 new file mode 100644 index 0000000000..ce36467111 --- /dev/null +++ b/web/spiderweb/patches/009 @@ -0,0 +1,44 @@ +*** master/WebMakefile.old Mon Jan 22 13:26:49 1990 +--- master/WebMakefile Mon Jan 22 13:32:40 1990 +*************** +*** 70,76 **** + $(MASTER)/common.c: $(MASTER)/common.web # no change file + $(CTANGLE) $(MASTER)/common + +! $(OBDIR)/common.o: $(MASTER)/common.c + $(CC) $(CFLAGS) -c $(MASTER)/common.c + mv common.o $(OBDIR) + +--- 70,76 ---- + $(MASTER)/common.c: $(MASTER)/common.web # no change file + $(CTANGLE) $(MASTER)/common + +! $(OBDIR)/common.o: $(MASTER)/common.c $(OBDIR) + $(CC) $(CFLAGS) -c $(MASTER)/common.c + mv common.o $(OBDIR) + +*************** +*** 79,88 **** + $(CTANGLE) $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +! $(OBDIR)/pathopen.o: $(MASTER)/pathopen.c + $(CC) $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(OBDIR) + + + ## Now we make the tangle and weave source locally + +--- 79,90 ---- + $(CTANGLE) $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +! $(OBDIR)/pathopen.o: $(MASTER)/pathopen.c $(OBDIR) + $(CC) $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(OBDIR) + ++ $(OBDIR): ++ if /bin/test ! -d $(OBDIR) ; then mkdir $(OBDIR) ; fi + + ## Now we make the tangle and weave source locally + diff --git a/web/spiderweb/patches/010 b/web/spiderweb/patches/010 new file mode 100644 index 0000000000..fca8083e4c --- /dev/null +++ b/web/spiderweb/patches/010 @@ -0,0 +1,36 @@ +*** master/weave.web.old Thu Feb 8 12:55:12 1990 +--- master/weave.web Thu Feb 8 12:55:50 1990 +*************** +*** 254,260 **** + (mod_xref_switch==file_flag && q->num < file_flag)) { + printf("\n! You can't use <"); print_id(p); + printf("> both as a file and as a named module"); mark_harmless; +! @.{You can't use <section name> both as a file...@> + + } + } +--- 254,260 ---- + (mod_xref_switch==file_flag && q->num < file_flag)) { + printf("\n! You can't use <"); print_id(p); + printf("> both as a file and as a named module"); mark_harmless; +! @.You can't use <section name> both as a file...@> + + } + } +*************** +*** 968,974 **** + if ((cur_xref->num)/def_flag != level) { + printf("\n! You can't use <"); print_id(p); + printf("> both as a file and as a named module"); mark_harmless; +! @.{You can't use <section name> both as a file...@> + } + cur_xref=cur_xref->xlink; + } +--- 968,974 ---- + if ((cur_xref->num)/def_flag != level) { + printf("\n! You can't use <"); print_id(p); + printf("> both as a file and as a named module"); mark_harmless; +! @.You can't use <section name> both as a file...@> + } + cur_xref=cur_xref->xlink; + } diff --git a/web/spiderweb/src/68k/68k.spider b/web/spiderweb/src/68k/68k.spider new file mode 100644 index 0000000000..b3f7a8943a --- /dev/null +++ b/web/spiderweb/src/68k/68k.spider @@ -0,0 +1,569 @@ +# 68k.spider +# Copyright (C) 1991,1992 by Izumi Watanabe, FUJI PHOTO FILM co., ltd. +# email address nabe@miya.fujifilm.co.jp +# This source is trial to generate an assembler-WEB. +# +# For Assembler weave, I use simple idea; +# label, opecode and operands are in a TeX's \hbox. + +language asm-68K extension 68k +at_sign @ + +comment begin <";"> end newline +line begin <";"-space-"line"> end <""> + +default translation <*> mathness yes + +token identifier category sym mathness yes +token number category math mathness yes +token newline category ignore_scrap mathness no translation <> +token pseudo_semi category ignore_scrap mathness maybe translation <> + +module definition stmt use pure_stmt + +macros begin +\def\opsize{6em} +\def\opbox#1{\hbox to\opsize{#1\hfill}} % Use in code +\def\popbox#1{#1\quad} % Use in comments +\def\OPbox#1{{\let\&=\. \opbox{#1}}} +#\def\REGbox#1{\let\&=\. \hbox{#1}} +\def\REGbox#1{#1} +\def\Lbox{\hbox to 1em{}} +\def\C#1{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % redefine: comments + \XX\hfil\penalty-1\hfilneg\quad + $\commentbegin\,${\let\opbox=\popbox #1}$\,\commentend$\XX} +macros end + +default translation <*> mathness yes +token . category dot +token + category unorbinop tangleto <space-"+"> +token - category unorbinop tangleto <space-dash> +token * category binop +token / category binop +token , category camma translation <",\\;"> +token ( category open tangleto <space-"("> +token [ category open tangleto <space-"["> +token { translation <"\\{"> category open tangleto <space-"{"> +token ) category close +token ] category close +token } translation <"\\}"> category close +token : category colon tangleto <":"-space> +token # category unop translation <"\\#"> tangleto <space-"#"> +#token ` category unop translation <"'"> mathness yes +#token ; category semi +token < category open tangleto <space-"<"> +token > category close +#token = category binop +#token ! category unop translation <"\\lnot"> +#token & category binop translation <"\\land"> +#token || category binop translation <"\\lor"> +#token | category unop +#token != name not_eq translation <"\\I"> category binop +#token <= name lt_eq translation <"\\L"> category binop +#token >= name gt_eq translation <"\\G"> category binop +#token == name eq_eq translation <"\\S"> category binop +#token >> translation <"\\rangle"> category close +#token << translation <"\\langle"> category open + + +#macros begin +#\def\LRA{\Longrightarrow} +#\def\IFF{\Longleftrightarrow} +#\def\FF{\Longleftarrow} +#\def\DEF{\buildrel\triangle\over=} +#\def\CE{\mathrel{{:}{=}}} +#\def\CC{\mathrel{{:}{:}}} +#\let\RA\rightarrow +#\let\openbraces=\{ +#\let\closebraces=\} +#\def\{{\ifmmode\openbraces\else$\openbraces$\fi} +#\def\}{\ifmmode\closebraces\else$\closebraces$\fi} +#macros end + + + + + +## definition of reserved +############################################## +## Pseudo Instructions ## +## (should be changed for your assembler) ## +############################################## + +ilk equ_like category equ mathness yes +ilk dw_like category dw mathness yes +reserved equ ilk equ_like +reserved set ilk equ_like +reserved EQU ilk equ_like +reserved SET ilk equ_like +reserved dc ilk dw_like +reserved db ilk dw_like +reserved dw ilk dw_like +reserved ds ilk dw_like +reserved dd ilk dw_like +reserved float ilk dw_like +reserved dfloat ilk dw_like +reserved DC ilk dw_like +reserved DB ilk dw_like +reserved DW ilk dw_like +reserved DS ilk dw_like +reserved DD ilk dw_like +reserved FLOAT ilk dw_like +reserved DFLOAT ilk dw_like + +ilk pseudo_like category pseudo mathness yes +reserved name ilk pseudo_like +reserved include ilk pseudo_like +reserved end ilk pseudo_like +reserved org ilk pseudo_like +reserved aorg ilk pseudo_like +reserved bnd ilk pseudo_like +reserved sect ilk pseudo_like +reserved NAME ilk pseudo_like +reserved INCLUDE ilk pseudo_like +reserved END ilk pseudo_like +reserved ORG ilk pseudo_like +reserved AORG ilk pseudo_like +reserved BND ilk pseudo_like +reserved SECT ilk pseudo_like + +ilk glo_like category glo mathness yes +reserved global ilk glo_like +reserved GLOBAL ilk glo_like + +ilk ext_like category ext mathness yes +reserved extnal ilk ext_like +reserved EXTNAL ilk ext_like + +default translation <*-"\\"-space> tangleto <*-space> +ilk if_like category if +ilk else_like category else +ilk endif_like category endif +reserved if ilk if_like +reserved ifdef ilk if_like +reserved ifndef ilk if_like +reserved else ilk else_like +reserved endif ilk endif_like +reserved IF ilk if_like +reserved IFDEF ilk if_like +reserved IFNDEF ilk if_like +reserved ELSE ilk else_like +reserved ENDIF ilk endif_like + +######################## +## All 68000 postfix ## +######################## +default mathness maybe +ilk post_b_like category post translation <*> tangleto <*-space> +ilk post_w_like category post translation <*> tangleto <*-space> +ilk post_l_like category post translation <*> tangleto <*-space> +ilk post_x_like category post translation <*> tangleto <*-space> +reserved b ilk post_b_like +reserved B ilk post_b_like +reserved w ilk post_w_like +reserved W ilk post_w_like +reserved l ilk post_l_like +reserved L ilk post_l_like +reserved x ilk post_x_like +reserved X ilk post_x_like + +########################## +## All 68000 registers ## +########################## +ilk reg_like category reg mathness yes +reserved a0 ilk reg_like +reserved a1 ilk reg_like +reserved a2 ilk reg_like +reserved a3 ilk reg_like +reserved a4 ilk reg_like +reserved a5 ilk reg_like +reserved a6 ilk reg_like +reserved a7 ilk reg_like +reserved d0 ilk reg_like +reserved d1 ilk reg_like +reserved d2 ilk reg_like +reserved d3 ilk reg_like +reserved d4 ilk reg_like +reserved d5 ilk reg_like +reserved d6 ilk reg_like +reserved d7 ilk reg_like +reserved pc ilk reg_like +reserved sr ilk reg_like +reserved ccr ilk reg_like +reserved ssp ilk reg_like +reserved usp ilk reg_like +reserved A0 ilk reg_like +reserved A1 ilk reg_like +reserved A2 ilk reg_like +reserved A3 ilk reg_like +reserved A4 ilk reg_like +reserved A5 ilk reg_like +reserved A6 ilk reg_like +reserved A7 ilk reg_like +reserved D0 ilk reg_like +reserved D1 ilk reg_like +reserved D2 ilk reg_like +reserved D3 ilk reg_like +reserved D4 ilk reg_like +reserved D5 ilk reg_like +reserved D6 ilk reg_like +reserved D7 ilk reg_like +reserved PC ilk reg_like +reserved SR ilk reg_like +reserved CCR ilk reg_like +reserved SSP ilk reg_like +reserved USP ilk reg_like + +############################## +## All 68000 Instructions ## +############################## +default translation <*> mathness yes +ilk opcode_like category opcode tangleto <space-*-space> mathness yes +reserved ABCD ilk opcode_like +reserved ADD ilk opcode_like +reserved ADDA ilk opcode_like +reserved ADDI ilk opcode_like +reserved ADDQ ilk opcode_like +reserved ADDX ilk opcode_like +reserved AND ilk opcode_like +reserved ANDI ilk opcode_like +reserved ASL ilk opcode_like +reserved ASR ilk opcode_like +reserved BCC ilk opcode_like +reserved BCS ilk opcode_like +reserved BEQ ilk opcode_like +reserved BGE ilk opcode_like +reserved BGT ilk opcode_like +reserved BHI ilk opcode_like +reserved BLE ilk opcode_like +reserved BLS ilk opcode_like +reserved BLT ilk opcode_like +reserved BMI ilk opcode_like +reserved BNE ilk opcode_like +reserved BPL ilk opcode_like +reserved BVC ilk opcode_like +reserved BVS ilk opcode_like +reserved BCHG ilk opcode_like +reserved BCLR ilk opcode_like +reserved BKPT ilk opcode_like +reserved BRA ilk opcode_like +reserved BSET ilk opcode_like +reserved BSR ilk opcode_like +reserved BTST ilk opcode_like +reserved CHK ilk opcode_like +reserved CLR ilk opcode_like +reserved CMP ilk opcode_like +reserved CMPA ilk opcode_like +reserved CMPI ilk opcode_like +reserved CMPM ilk opcode_like +reserved DBCC ilk opcode_like +reserved DBCS ilk opcode_like +reserved DBEQ ilk opcode_like +reserved DBF ilk opcode_like +reserved DBGE ilk opcode_like +reserved DBGE ilk opcode_like +reserved DBGT ilk opcode_like +reserved DBHI ilk opcode_like +reserved DBLE ilk opcode_like +reserved DBLS ilk opcode_like +reserved DBLT ilk opcode_like +reserved DBMI ilk opcode_like +reserved DBMI ilk opcode_like +reserved DBNE ilk opcode_like +reserved DBPL ilk opcode_like +reserved DBT ilk opcode_like +reserved DBVC ilk opcode_like +reserved DBVS ilk opcode_like +reserved DIVS ilk opcode_like +reserved DIVU ilk opcode_like +reserved EOR ilk opcode_like +reserved EORI ilk opcode_like +reserved EXG ilk opcode_like +reserved EXT ilk opcode_like +reserved ILLEGAL ilk opcode_like +reserved JMP ilk opcode_like +reserved JSR ilk opcode_like +reserved LEA ilk opcode_like +reserved LINK ilk opcode_like +reserved LSL ilk opcode_like +reserved LSR ilk opcode_like +reserved MOVE ilk opcode_like +reserved MOVEA ilk opcode_like +reserved MOVEC ilk opcode_like +reserved MOVEM ilk opcode_like +reserved MOVEP ilk opcode_like +reserved MOVEQ ilk opcode_like +reserved MOVES ilk opcode_like +reserved MULS ilk opcode_like +reserved MULU ilk opcode_like +reserved NBCD ilk opcode_like +reserved NEG ilk opcode_like +reserved NEGX ilk opcode_like +reserved NOP ilk opcode_like +reserved NOT ilk opcode_like +reserved OR ilk opcode_like +reserved ORI ilk opcode_like +reserved PEA ilk opcode_like +reserved RESET ilk opcode_like +reserved ROL ilk opcode_like +reserved ROR ilk opcode_like +reserved ROXL ilk opcode_like +reserved ROXR ilk opcode_like +reserved RTD ilk opcode_like +reserved RTE ilk opcode_like +reserved RTR ilk opcode_like +reserved RTS ilk opcode_like +reserved SBCD ilk opcode_like +reserved SCC ilk opcode_like +reserved SCS ilk opcode_like +reserved SEQ ilk opcode_like +reserved SF ilk opcode_like +reserved SGE ilk opcode_like +reserved SGT ilk opcode_like +reserved SHI ilk opcode_like +reserved SLE ilk opcode_like +reserved SLS ilk opcode_like +reserved SLT ilk opcode_like +reserved SMI ilk opcode_like +reserved SNE ilk opcode_like +reserved SPL ilk opcode_like +reserved ST ilk opcode_like +reserved SVC ilk opcode_like +reserved SVS ilk opcode_like +reserved STOP ilk opcode_like +reserved SUB ilk opcode_like +reserved SUBA ilk opcode_like +reserved SUBI ilk opcode_like +reserved SUBQ ilk opcode_like +reserved SUBX ilk opcode_like +reserved SWAP ilk opcode_like +reserved TAS ilk opcode_like +reserved TRAP ilk opcode_like +reserved TRAPV ilk opcode_like +reserved TST ilk opcode_like +reserved UNLK ilk opcode_like +reserved abcd ilk opcode_like +reserved add ilk opcode_like +reserved adda ilk opcode_like +reserved addi ilk opcode_like +reserved addq ilk opcode_like +reserved addx ilk opcode_like +reserved and ilk opcode_like +reserved andi ilk opcode_like +reserved asl ilk opcode_like +reserved asr ilk opcode_like +reserved bcc ilk opcode_like +reserved bcs ilk opcode_like +reserved beq ilk opcode_like +reserved bge ilk opcode_like +reserved bgt ilk opcode_like +reserved bhi ilk opcode_like +reserved ble ilk opcode_like +reserved bls ilk opcode_like +reserved blt ilk opcode_like +reserved bmi ilk opcode_like +reserved bne ilk opcode_like +reserved bpl ilk opcode_like +reserved bvc ilk opcode_like +reserved bvs ilk opcode_like +reserved bchg ilk opcode_like +reserved bclr ilk opcode_like +reserved bkpt ilk opcode_like +reserved bra ilk opcode_like +reserved bset ilk opcode_like +reserved bsr ilk opcode_like +reserved btst ilk opcode_like +reserved chk ilk opcode_like +reserved clr ilk opcode_like +reserved cmp ilk opcode_like +reserved cmpa ilk opcode_like +reserved cmpi ilk opcode_like +reserved cmpm ilk opcode_like +reserved dbcc ilk opcode_like +reserved dbcs ilk opcode_like +reserved dbeq ilk opcode_like +reserved dbf ilk opcode_like +reserved dbge ilk opcode_like +reserved dbge ilk opcode_like +reserved dbgt ilk opcode_like +reserved dbhi ilk opcode_like +reserved dble ilk opcode_like +reserved dbls ilk opcode_like +reserved dblt ilk opcode_like +reserved dbmi ilk opcode_like +reserved dbmi ilk opcode_like +reserved dbne ilk opcode_like +reserved dbpl ilk opcode_like +reserved dbt ilk opcode_like +reserved dbvc ilk opcode_like +reserved dbvs ilk opcode_like +reserved divs ilk opcode_like +reserved divu ilk opcode_like +reserved eor ilk opcode_like +reserved eori ilk opcode_like +reserved exg ilk opcode_like +reserved ext ilk opcode_like +reserved illegal ilk opcode_like +reserved jmp ilk opcode_like +reserved jsr ilk opcode_like +reserved lea ilk opcode_like +reserved link ilk opcode_like +reserved lsl ilk opcode_like +reserved lsr ilk opcode_like +reserved move ilk opcode_like +reserved movea ilk opcode_like +reserved movec ilk opcode_like +reserved movem ilk opcode_like +reserved movep ilk opcode_like +reserved moveq ilk opcode_like +reserved moves ilk opcode_like +reserved muls ilk opcode_like +reserved mulu ilk opcode_like +reserved nbcd ilk opcode_like +reserved neg ilk opcode_like +reserved negx ilk opcode_like +reserved nop ilk opcode_like +reserved not ilk opcode_like +reserved or ilk opcode_like +reserved ori ilk opcode_like +reserved pea ilk opcode_like +reserved reset ilk opcode_like +reserved rol ilk opcode_like +reserved ror ilk opcode_like +reserved roxl ilk opcode_like +reserved roxr ilk opcode_like +reserved rtd ilk opcode_like +reserved rte ilk opcode_like +reserved rtr ilk opcode_like +reserved rts ilk opcode_like +reserved sbcd ilk opcode_like +reserved scc ilk opcode_like +reserved scs ilk opcode_like +reserved seq ilk opcode_like +reserved sf ilk opcode_like +reserved sge ilk opcode_like +reserved sgt ilk opcode_like +reserved shi ilk opcode_like +reserved sle ilk opcode_like +reserved sls ilk opcode_like +reserved slt ilk opcode_like +reserved smi ilk opcode_like +reserved sne ilk opcode_like +reserved spl ilk opcode_like +reserved st ilk opcode_like +reserved svc ilk opcode_like +reserved svs ilk opcode_like +reserved stop ilk opcode_like +reserved sub ilk opcode_like +reserved suba ilk opcode_like +reserved subi ilk opcode_like +reserved subq ilk opcode_like +reserved subx ilk opcode_like +reserved swap ilk opcode_like +reserved tas ilk opcode_like +reserved trap ilk opcode_like +reserved trapv ilk opcode_like +reserved tst ilk opcode_like +reserved unlk ilk opcode_like + +################################ +## Production roles for weave ## +################################ + +# For register +# +#[ <"\\REGbox{"> reg <"}"> ] --> math +<"\\REGbox{"> reg dot post <"}"> --> math +[ <"\\REGbox{"> reg <"}"> ] open --> math open +[ <"\\REGbox{"> reg <"}"> ] close --> math close +[ <"\\REGbox{"> reg <"}"> ] binop --> math binop +[ <"\\REGbox{"> reg <"}"> ] camma --> math camma +[ <"\\REGbox{"> reg <"}"> ] unorbinop --> math unorbinop +[ <"\\REGbox{"> reg <"}"> ] ignore_scrap --> math ignore_scrap + +<"\\REGbox{"> reg <"}"> (math|sym) --> math + +# For math +# +(sym|math) (binop|unorbinop|camma) (sym|math) --> math +(unop|unorbinop) (sym|math) --> math +(sym|math) (unop|unorbinop) --> math +open (sym|math) close --> math +(sym|math) <space> (sym|math) --> math + +#open close --> math +#math semi <force> --> unop +#math <force> lbrace --> lbrace +#lbrace math close --> math +#lbrace math close <force> --> unop + +# There are rules for if-pseudo-instructions +# +<force> if (sym|math) --> ifmath +ifmath math ignore_scrap --> ifmath +ifmath <indent> stmt ignore_scrap --> ifstmt +ifstmt stmt --> ifstmt +ifstmt <outdent-force> else if --> if +ifstmt <outdent-force> endif --> stmt + +ifmath <force> else --> ifels +ifstmt <outdent-force> else ignore_scrap --> ifels +ifels <indent> stmt --> ifelstmt +ifelstmt stmt --> ifelstmt +ifelstmt <outdent-force> endif --> stmt +ifels <force> endif --> stmt + +# For instructions +# +#-- pseudo instructions +(dw|pseudo) <"\\"-space> --> inst +<force> sym* <"\\"-space> (equ|dw) <"\\"-space> (sym|math) ignore_scrap --> stmt +#<force> dw <"\\"-space> (sym|math) ignore_scrap --> stmt +#-- CPU instructions +<"\\OPbox{"> opcode dot post <"}"-space> --> inst +<"\\OPbox{"> opcode <"}"-space> --> inst + +#-- ext instructions +# +<force> ext <"\\"-space> sym* --> extsym +extsym camma <break_space> sym* --> extsym +extsym ignore_scrap --> stmt + +<force> glo <"\\"-space> sym --> glosym +glosym camma <break_space> sym --> glosym +glosym ignore_scrap --> stmt + +#sym* camma sym* --> symlist +#symlist camma sym* --> symlist +#<indent-force> (ext|glo) <"\\"-space> symlist <outdent> ignore_scrap --> stmt + +#-- instructions +# +[ inst (sym|math) ] ignore_scrap --> pure_stmt ignore_scrap +[ inst ] ignore_scrap --> pure_stmt ignore_scrap +#[ inst math (unop|unorbinop) ] ignore_scrap --> pure_stmt ignore_scrap + +# reducing label +# +<"\\hbox{"> sym* colon <"}"> --> label +<big_force> label <force> label --> sub_label +<big_force> sub_label <force> label --> sub_label + +# Statements +# +sub_label <force-"\\Lbox"-space> pure_stmt --> stmt +<big_force> label <force-"\\Lbox"-space> pure_stmt --> stmt +<force-"\\Lbox"-space> pure_stmt --> stmt +#stmt <force-"\\Lbox"-space> pure_stmt --> stmt + +stmt stmt --> stmt + +#labeled_stmt <force> pure_stmt --> stmt +#stmt labeled_stmt --> stmt +#<force> pure_stmt labeled_stmt --> stmt + +? ignore_scrap --> #1 + +# end of file + + diff --git a/web/spiderweb/src/68k/make b/web/spiderweb/src/68k/make new file mode 100644 index 0000000000..d5de3d22b3 --- /dev/null +++ b/web/spiderweb/src/68k/make @@ -0,0 +1,3 @@ +#!/bin/sh +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=68ktangle THEWEAVE=68kweave SPIDER=68k.spider "$@" diff --git a/web/spiderweb/src/BUGS b/web/spiderweb/src/BUGS new file mode 100644 index 0000000000..5045ea5576 --- /dev/null +++ b/web/spiderweb/src/BUGS @@ -0,0 +1,84 @@ + 8 Apr 89 Forgot to move object files to $(OBDIR) when making `boot' + 8 Apr 89 TANGLE token numbers were too low by 3. This caused a + duplicate case in switch when there were too many tokens, + because some token was getting decimal 10 (#'13). The + fix was to add 3 to the appropriate place in spider.web + +===> Bundled 8 Apr 89; all bugs into patches/001 + +10 Apr 89 Confusion about Makefile targets; updated Makefile & README + +===> Bundled 10 Apr 89; all bugs into patches/002 + +10 Apr 89 Bad figure in cacm.tex +11 Apr 89 Make clean and distribution removed important source + from master directory. +11 Apr 89 WEAVE itself doesn't WEAVE properly because of foul + comments in grammar.web. Changed spider.web to escape + _ and # as well as |. +11 Apr 89 spiderwebman.tex had a missing \endnewstuff. While + putting it in I found some inaccuracies about macros. + The whole spiderwebman is pretty grim, and should be + rewritten, or at least checked for accuracy. + +===> Bundled 11 Apr 89; all bugs into patches/003 + +14 Apr 89 Removed @\ from WEAVE; it was already gone from TANGLE + and is obsolete in Spidery WEB. + Marked documentation to show @? isn't supported. + + +===> Bundled 18 Apr 89; all bugs into patches/004 + +26 Jun 89 Removed \eject from webkernel.tex line 221 (before first page) + It was causing the headings on page 1 to come out missing. + 3 Jul 89 Added parentheses to 3 offending sprintf calls in spider.web + +===> Bundled 3 Jul 89; all bugs into patches/005 + +20 Jul 89 WEAVE was erroneously matching scraps with category zero. + This was tickled in ceeweave by the name @<Oink |#include|s@>. + Grabbing the scrap with category zero caused WEAVE to drop + the text associated with the whole sequence. I don't know + why it didn't go off the trolley entirely. + Fix was to put in a zero check for negations (single and + lists) and wild cards. + +===> Bundled 8 Aug 89; all bugs into patches/006 + +23 Aug 89 Spider wouldn't accept capital letters in category and field + names. + +===> Bundled 14 Sep 89; all bugs into patches/007 + +29 Nov 89 Ceetangle rewrote `a = b / *p' as `a= b/*p', a phony comment. + Fixed by `token * tangleto <space-"*">' (changing / mucks up + #include files) + +29 Nov 89 Updated README file to mention . in front of path, clear + up some misconceptions, and fix my telephone number. + Added Wayne Sewell's book to bibliographies. + +===> Bundled 29 Nov 89; all bugs into patches/008 + +22 Jan 90 WebMakefile bombed if $(OBDIR) directory didn't exist. +23 Jan 90 Got a letter from David Ness, indicating some changes for + MS-DOS version (also some bug fixes to spider.web). + I integrated his changes by introducing longs where + appropriate and adding a couple of `#ifdef MSDOS' lines. + +===> Bundled 02 Feb 90; all bugs into patches/009 + +13 Feb 90 David Ness reports some \& should be \amp in macro definitions +16 Apr 90 larch spider specification had old-style comment defns +16 Apr 90 \write\cont{\string\catcode`\string\@=11} misplaced + in webkernel.tex +16 Apr 90 Give ** operator a translation in ada.spider +11 Sep 90 Various bug fixes in webkernel.tex (from G. Alexander) + + +===> Bundled 26 Sep 90; no patches for most bugs, some in patches/010 + +19 Feb 91 Sequence @i wasn't in the manual. + +===> Bundled 19 Feb 91; no patches.
\ No newline at end of file diff --git a/web/spiderweb/src/COPYRIGHT b/web/spiderweb/src/COPYRIGHT new file mode 100644 index 0000000000..193fdea8b4 --- /dev/null +++ b/web/spiderweb/src/COPYRIGHT @@ -0,0 +1,11 @@ +Spider and Spidery WEB are copyright 1989-1992 by Norman Ramsey, +Odyssey Research Associates (ORA Corp), 301A Dates Drive, Ithaca, New +York 14850. + +You may use and distribute Spider and Spidery WEB for any purpose, for +free. You may modify Spider and Spidery WEB and create derived works, +provided you retain the copyright notice, but the result may not be +called Spider or Spidery WEB without written permission from ORA Corp. +You may not sell Spider or Spidery WEB themselves, but you may do +anything you like with programs created with Spider and Spidery WEB. + diff --git a/web/spiderweb/src/Makefile b/web/spiderweb/src/Makefile new file mode 100644 index 0000000000..0b1510b6af --- /dev/null +++ b/web/spiderweb/src/Makefile @@ -0,0 +1,44 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory + +# This is a SUN OS 4 Makefile. Sorry. Makefiles in subdirectories +# should work under any reasonable Make. + +MAKE=make $(MFLAGS) +DIRECTORIES=68k ada awk c c++ dijkstra kelem larch nawk \ + penelope postscript reduce sml ssl turing turing+ + +# Removes excess junk from the world, except it doesn't remove +# common object files from ./master +# This destroys the sources, so don't make clean until you've made boot. +clean: + @for i in $(DIRECTORIES); do \ + cd $$i; \ + echo making $$i clean...; \ + $(MAKE) clean ; \ + cd ..; \ + done + rm -f *~ + @echo "All done." + +# This creates the minimum sources in preparation for `make distribution' +source: + cd c ; $(MAKE) source ; cd .. + cd awk ; $(MAKE) source ; cd .. + +# Used to bring up the system when first installing it. Requires sources, +# either from the distribution tarfile or from `make source' +boot: + cd c; $(MAKE) boot; cd .. + cd awk; $(MAKE) boot; cd .. + +# Make all known webs. For lunatics only. +all: + @for i in $(DIRECTORIES); do \ + cd $$i; \ + $(MAKE) web ; \ + cd ..; \ + done + @echo "All done." + diff --git a/web/spiderweb/src/README b/web/spiderweb/src/README new file mode 100644 index 0000000000..d7750508f9 --- /dev/null +++ b/web/spiderweb/src/README @@ -0,0 +1,104 @@ +This file says how to install Spidery WEB. If you want more information +about what it is, look in the doc subdirectory, especially doc/DESCRIPTION. +Spidery WEB is not in the public domain, but you are welcome to use it for +any purpose. For more details, see the file COPYRIGHT. + + +How to install Spidery WEB: + +1) Pick a directory to install the WEB source in. Call it WEBROOT. + +2) untar the distribution in WEBROOT (cd WEBROOT; tar xvf spiderweb.tar) + +3) change to the master subdirectory and edit WebMakefile. + -- Set WEBROOT to the WEBROOT directory + -- Set DEST to the name of a directory to hold the executables + -- Set MACROS to the name of directory to hold TeX macros + Example: + WEBROOT=/usr/src/local/spiderweb + DEST=/usr/local + MACROS=/usr/lib/tex/macros + + Make sure there are no spaces following the names. + +4) If your installation doesn't have a cputype program, make one (a shell + script is fine) following the instructions in WebMakefile. Put it + somewhere on your path. + +5) As defaults, the names of C tangle and weave are ceetangle and ceeweave + (to avoid confusion with Silvio Levy's ctangle and cweave). Awk tangle + is called awktangle. If you want to change these names, you must change + them in WEBROOT/master/WebMakefile, and also on WEBROOT/c/make and + WEBROOT/awk/make + +6) Make sure . is at the front of your path. For example, csh users could + type `set path = (. $path)' or sh users type `path=.:$path'. (I haven't + checked these since . is at the front of my path by default.) If you + don't like this security hole, you will have to change `make' to `./make' + at the appropriate places (found by you). + + With your path set, go into WEBROOT and type `make boot' + + Once this is successful you will have executable versions of tangle for + C and Awk, which is the minumum needed to make other things. After you've + done this, you can afford to `make clean', which will remove the .c and + .awk source you used to bootstrap yourself. You can always make them over + again using the executable versions (`make source'). + + In case it isn't clear, once you `make boot' you will never need to do + it again. + +7) Move webkernel.tex into a place where TeX can find it. Until you do + this you won't be able to TeX WEAVE output (or doc/spiderwebman.tex). + + + +Spidery WEB comes with the following languages: + +Directory Description + +68k 68000 assembly language, courtesy Izumi Watanabe +ada Ada +awk old-style AWK, a string processing language +c Kernighan and Ritchie C +c++ C++, courtesy of Ed Kademan +dijkstra Edsger Dijkstra's language of guarded commands (flaky) +kelem Algol-like C, courtesy Steve Kelem +larch The Larch Shared Language, used for specifying + equational theories. +nawk new-style AWK +penelope Ada, extended with formal comments for verification +postscript PostScript, courtesy David Love +reduce A Pascal-like lisp, courtesy Marcel Roelofs +sml A couple of attempts at Standard ML +ssl The language of the Cornell Synthesizer Generator +turing,turing+ Two versions of the Turing language, courtesty Kostas N. Oikonomou + + +Each of these directories has a file called 'make'. The settings in +that file determine the name that the executable versions of WEAVE and +TANGLE have for that particular language. The names of the Spider +files are also given. See ../doc/spiderman.tex for details on using +Spider. Izumi Watanabe's Japanese translation is in ../doc/spdjman.tex. + +To make weave or tangle, change to the directory for the chosen language, +and type `make weave' or `make tangle'. `make web' will make both weave +and tangle. + +The `latex' subdirectory contains change files and other information +to support use of WEB with latex. They may not be up to date with the +current version of web. + +Spidery WEB is available by anonymous ftp from the literate- +programming archive at niord.shsu.edu. Spidery WEB is no longer +supported; it has been replaced by `noweb', which is available by +anonymous ftp from csservices.princeton.edu:pub/noweb.shar.Z. ORA +Corp makes some effort to keep Spidery WEB working, and bug reports, +fixes, and new language descriptions can be sent to +spider-bugs@oracorp.com. + +Norman Ramsey +ORA Corporation +301A Harris B. Dates Drive +Ithaca, New York 14850 +Internet: spider-bugs@oracorp.com diff --git a/web/spiderweb/src/README.DOS b/web/spiderweb/src/README.DOS new file mode 100644 index 0000000000..596e6c5081 --- /dev/null +++ b/web/spiderweb/src/README.DOS @@ -0,0 +1,56 @@ +How to bring up Spider on MS-DOS (adapted from instructions kindly +provided by David Ness). Assumes Microsoft C 5.1 and MS overlay +linker V 3.65. + +1. Get \MASTER\PATHOPEN.* COMMON.* + +2. Get TANGLE.C from C.ZIP + +3. Compile with 'CL /AH TANGLE.C COMMON.C PATHOPEN.C'. (If your + compiler does not define the symbol MSDOS automatically, you should + use 'CL /DMSDOS' or whatever the appropriate incantation is.) This will + produce lots of warnings because the code has labels after '#endif'. + This produces your official C tangle, so perhaps + 'REN TANGLE.EXE CTANGLE.EXE' is in order. + +4. Get TANGLE.C from AWK.ZIP, and + 'CL /AH TANGLE.C COMMON.OBJ PATHOPEN.OBJ' followed by + 'REN TANGLE.EXE ATANGLE.EXE' should give you an Awk tangle. + +5. Not that the copies of C TANGLE and Awk TANGLE have been produced + from the bootstrap TANGLE.C, not from TANGLE.WEB. Our next task + is to produce good TANGLEs from the WEB. This will require SPIDER, + and SPIDER REQUIRES Awk. + +6. First we can regenerate PATHOPEN.C and PATHOPEN.H from PATHOPEN.WEB + with 'CTANGLE PATHOPEN'. This is done just for consistency. + +7. Now begin by creating SPIDER.AWK from SPIDER.WEB: 'ATANGLE SPIDER'. + +8. Run Awk on SPIDER, giving it C.SPI: 'AWK -F SPIDER.AWK C.SPI'. + This produces OUTTOKS.WEB needed for TANGLE.WEB and GRAMMAR.WEB and + SCRAPS.WEB needed for WEAVE. + +9. However, there is one problem. As is, the function `translate()' + generates a code segment too big to handle. By wild good luck, if + the appropriate calls to the `reduce()' function are replaced with + calls on `squash()', then it just fits. (SPIDER doesn't generate + calls on `squash()', although `squash()' is still defined in + WEAVE.) + + DNN.WEB will generate an Awk script that does this reduction. + For MKS Awk this is done with + ATANGLE DNN.WEB + AWK -F DNN GRAMMAR.WEB + COPY OUT.TMP GRAMMAR.WEB + +10.Then 'CTANGLE WEAVE' to produce WEAVE.C + +11.And finally 'CL /AH WEAVE.C COMMON.OBJ PATHOPEN.OBJ' + and 'REN WEAVE.EXE CWEAVE.EXE'. + +12.We can generate AWEAVE (for Awk) by starting again at step 8 and + substituting `A' for `C' where appropriate. + + + diff --git a/web/spiderweb/src/ada/ada.spider b/web/spiderweb/src/ada/ada.spider new file mode 100644 index 0000000000..6a76f95436 --- /dev/null +++ b/web/spiderweb/src/ada/ada.spider @@ -0,0 +1,278 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory + +# Modified by Sylvester Fernandez + +language Ada extension ada + +at_sign @ + +module definition stmt use stmt + +comment begin <dash-dash> end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin <dash-dash-"line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness maybe +token number category math mathness yes +token newline category ignore_scrap translation <> mathness maybe +token pseudo_semi translation <> category semi mathness maybe + +macros begin +\let\R\relax +macros end + +# Delimiters +token & category binop translation <"\\amp"> +token ( category open +token ) category close +token * category binop +token + category unorbinop +token , category binop translation <",\\,"-opt-3> +token - category unorbinop +token . category binop +token / category binop +token : category binop +token ; category semi translation <";"-space-opt-2> +token < category binop +token = category binop +token > category binop +token | category binop translation <"\\mid"> + +# Compound delimiters + +token => category arrow translation <"\\AR"> +token .. category binop translation <"\\.{..}\\>"> +token ** category binop translation <"\\mathbin{**}"> +token := category binop translation <"\\mathbin{:=}"> +token /= translation <"\\I"> category binop +token >= translation <"\\G"> category binop +token <= translation <"\\L"> category binop +token << translation <"\\LL"> category openlabel +token >> translation <"\\GG"> category closelabel +token <> translation <"\\LG"> category math + +# Hacks no ', and this becomes a binary op +token ' category binop mathness no + +token # category math translation <"\\#"> + + + + +default mathness maybe translation <*> + +reserved abort ilk math_like +reserved abs ilk unop_like +reserved accept ilk proc_like +reserved access ilk math_like +reserved all ilk math_like +reserved and ilk and_like +reserved array ilk math_like +reserved at ilk at_like +reserved begin ilk begin_like +reserved body ilk math_like +reserved case ilk case_like +reserved constant ilk math_like +reserved declare ilk decl_like +reserved delay ilk math_like +reserved delta ilk math_like +reserved digits ilk math_like +reserved do ilk do_like +reserved else ilk else_like +reserved elsif ilk elsif_like +reserved end ilk end_like +reserved entry ilk proc_like +reserved exception ilk ex_like +reserved exit ilk math_like +reserved for ilk math_like +reserved function ilk proc_like +reserved generic ilk gen_like +reserved goto ilk math_like +reserved if ilk if_like +reserved in ilk unorbinop_like +reserved is ilk is_like +reserved limited ilk math_like +reserved loop ilk loop_like +reserved mod ilk binop_like +reserved new ilk unop_like +reserved not ilk unop_like +reserved null ilk math_like +reserved of ilk math_like +reserved or ilk or_like +reserved others ilk math_like +reserved out ilk math_like +reserved package ilk proc_like +reserved pragma ilk math_like +reserved private ilk private_like +reserved procedure ilk proc_like +reserved raise ilk math_like +reserved range ilk math_like +reserved record ilk record_like +reserved rem ilk binop_like +reserved renames ilk math_like +reserved return ilk math_like +reserved reverse ilk math_like +reserved select ilk select_like +reserved separate ilk separate_like +reserved subtype ilk math_like +reserved task ilk proc_like +reserved terminate ilk math_like +reserved then ilk then_like +reserved type ilk math_like +reserved use ilk math_like +reserved when ilk when_like +reserved while ilk math_like +reserved with ilk with_like +reserved xor ilk binop_like + +ilk and_like translation <*> category and +ilk at_like translation <*> category at +ilk begin_like translation <*-indent> category beginning +ilk binop_like translation <"\\"-space-*-"\\"-space> category binop +ilk case_like translation <*> category case +ilk decl_like translation <*-indent> category declaration +ilk do_like translation <*> category do +ilk else_like translation <*> category else +ilk elsif_like translation <*> category elsif +ilk end_like translation <*> category close +ilk ex_like translation <*> category exception +ilk gen_like translation <*-indent> category generic +ilk if_like translation <*> category if +ilk is_like translation <*> category is +ilk loop_like translation <*> category loop +ilk math_like translation <*> category math +ilk or_like translation <*> category or +ilk private_like translation <*> category private +ilk proc_like translation <force-*> category proc +ilk record_like translation <*> category record +ilk select_like translation <*> category select +ilk separate_like translation <*> category separate +ilk then_like translation <*> category then +ilk unop_like translation <*-"\\"-space> category unop +ilk unorbinop_like translation <"\\"-space-*-"\\"-space> category resunorbinop +ilk when_like translation <*> category when +ilk with_like translation <*> category with + + +# \MC means ``math close'' and sets \MS to ``math set'' +macros begin +\def\MC{\ifmmode\global\let\MS$\else\global\let\MS\relax\fi\relax\MS} +\def\LG{\mathord{<}\mathord{>}} +\let\IG=\ignorespaces +macros end + + + +beginning <outdent-force> continuation <outdent-force> ending --> stmt +beginning <outdent-force> ending --> stmt +# beginning <force> (stmt|ignore_scrap) --> beginning +beginning <force> stmt --> beginning + +case <"\\"-space> math <"\\"-space> is <indent-force> --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation <force> stmt --> continuation +continuation <outdent-force> continuation --> continuation + + +declaration <outdent-force> beginning <outdent-force> continuation <outdent-force> ending --> stmt +declaration <outdent-force> beginning <outdent-force> ending --> stmt +declaration <outdent-force> ending --> stmt +declaration <force> (declaration|stmt) --> declaration + +else <indent-force> --> continuation +elsif <"\\"-space> math <"\\"-space> then <indent-force> --> continuation + +exception <indent-force> --> continuation + +generic <outdent-force> declaration --> declaration +generic <force> stmt --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen <indent-force> stmt --> beginning +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> else --> ifthen +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> close <"\\"-space> if --> math +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> elsif --> if + + +is --> math + +loop <indent-force> --> beginning + +math [ <"\\"-space> and <"\\"-space> then <"\\"-space> ] --> math binop +math [ <"\\"-space> and <"\\"-space> ] --> math binop + +math (binop|unorbinop) math --> math +math <"\\"-space> resunorbinop <"\\"-space> math --> math +(unorbinop|unop) math --> math +resunorbinop <"\\"-space> math --> math +# This doesn't apply in Ada: math unop --> math + +math arrow --> math +math <"\\"-space> at --> math +math binop <"\\"-space> exception --> math +math <"\\"-space> is --> math +math <"\\"-space> loop --> loop +math <"\\"-space> math --> math +math [ <"\\"-space> or <"\\"-space> else <"\\"-space> ] --> math binop +math [ <"\\"-space> or <"\\"-space> ] --> math binop +math <"\\"-space> private --> math +math <"\\"-space> separate --> math +math <indent-force> stmt <outdent-force> --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + +<force-backup> openlabel math closelabel <force> --> math + +or <indent-force> --> continuation + +private <indent-force> --> beginning + +proc <"\\"-space> math <"\\"-space> is <"\\"-space> unop --> math +proc <"\\"-space> math <"\\"-space> is <"\\"-space> separate --> math +proc <"\\"-space> math <"\\"-space> is <indent-force> --> declaration +proc <"\\"-space> math <"\\"-space> do <indent-force> --> beginning +proc <"\\"-space> math terminator <force> --> declaration + +#record <"\\"-space> at <"\\"-space> math terminator <indent-force> --> beginning +record <indent-force> --> beginning + +select <indent-force> --> beginning + +semi --> terminator + +separate math --> stmt + +stmt <force> declaration --> declaration + +stmt <force> stmt --> stmt + +stmt <outdent-force> ending --> stmt + +when <"\\"-space> math arrow <indent-force> --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt <outdent-force> ending --> ending +whengroup stmt <outdent-force> continuation --> continuation +whengroup stmt <outdent-force> whengroup --> whengroup + +with <"\\"-space> math --> math +with <"\\"-space> proc <"\\"-space> math --> math + +? ignore_scrap --> #1 + +macros begin +\let\AR=\Longrightarrow +macros end diff --git a/web/spiderweb/src/ada/make b/web/spiderweb/src/ada/make new file mode 100644 index 0000000000..cbb39a896a --- /dev/null +++ b/web/spiderweb/src/ada/make @@ -0,0 +1,3 @@ +#!/bin/csh -f +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=adatangle THEWEAVE=adaweave SPIDER=ada.spider $* diff --git a/web/spiderweb/src/ada/new.spider b/web/spiderweb/src/ada/new.spider new file mode 100644 index 0000000000..31f142b23e --- /dev/null +++ b/web/spiderweb/src/ada/new.spider @@ -0,0 +1,315 @@ +From ngcr@planet8.planet8.sp.unisys.com Thu Jan 10 16:23:26 1991 +Received: from cs.Princeton.EDU (cs.Princeton.EDU) by fs.Princeton.EDU (4.0/1.105) + id AA12318; Thu, 10 Jan 91 16:23:23 EST +Received: from fs.Princeton.EDU by cs.Princeton.EDU (5.57/1.105) + id AA09028; Thu, 10 Jan 91 16:23:19 EST +Received: from Princeton.EDU (Princeton.EDU.) by fs.Princeton.EDU (4.0/1.105) + id AA12315; Thu, 10 Jan 91 16:23:15 EST +Received: from [129.218.60.4] by Princeton.EDU (5.61++/2.62/princeton) + id AA16288; Thu, 10 Jan 91 16:23:09 -0500 +Received: by email.sp.unisys.com (5.57/Ultrix3.0-C) + id AA15274; Thu, 10 Jan 91 15:22:05 -0600 +Received: from pablo.sp.unisys.com. by planet8.planet8.sp.unisys.com. (4.0/SMI-4.0) + id AA12500; Thu, 10 Jan 91 15:22:39 CST +Date: Thu, 10 Jan 91 15:22:39 CST +From: ngcr<@fs>@Princeton.EDU (Sylvester Fernandez) +Message-Id: <9101102122.AA12500@planet8.planet8.sp.unisys.com.> +To: nr@Princeton.EDU +Subject: Re: Ada Web +Status: R + + +All the bugs I found were in the grammar. Here is the modified +version we are using now: + +----------- +ada.spider +----------- +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory + +# Modified by Sylvester Fernandez + +language Ada extension ada + +at_sign @ + +module definition stmt use stmt + +comment begin <dash-dash> end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin <dash-dash-"line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness maybe +token number category math mathness yes +token newline category ignore_scrap translation <> mathness maybe +token pseudo_semi translation <> category semi mathness maybe + +macros begin +\let\R\relax +macros end + +# Delimiters +token & category binop translation <"\\amp"> +token ( category open +token ) category close +token * category binop +token + category unorbinop +token , category binop translation <",\\,"-opt-3> +token - category unorbinop +token . category binop +token / category binop +token : category binop +token ; category semi translation <";"-space-opt-2> +token < category binop +token = category binop +token > category binop +token | category binop translation <"\\mid"> + +# Compound delimiters + +token => category arrow translation <"\\AR"> +token .. category binop translation <"\\.{..}\\>"> +token ** category binop translation <"\\mathbin{**}"> +token := category binop translation <"\\mathbin{:=}"> +token /= translation <"\\I"> category binop +token >= translation <"\\G"> category binop +token <= translation <"\\L"> category binop +token << translation <"\\LL"> category openlabel +token >> translation <"\\GG"> category closelabel +token <> translation <"\\LG"> category math + +# Hacks no ', and this becomes a binary op +token ' category binop mathness no + +token # category math translation <"\\#"> + + + + +default mathness maybe translation <*> + +reserved abort ilk math_like +reserved abs ilk unop_like +reserved accept ilk proc_like +reserved access ilk math_like +reserved all ilk math_like +reserved and ilk and_like +reserved array ilk math_like +reserved at ilk at_like +reserved begin ilk begin_like +reserved body ilk math_like +reserved case ilk case_like +reserved constant ilk math_like +reserved declare ilk decl_like +reserved delay ilk math_like +reserved delta ilk math_like +reserved digits ilk math_like +reserved do ilk do_like +reserved else ilk else_like +reserved elsif ilk elsif_like +reserved end ilk end_like +reserved entry ilk proc_like +reserved exception ilk ex_like +reserved exit ilk math_like +reserved for ilk math_like +reserved function ilk proc_like +reserved generic ilk gen_like +reserved goto ilk math_like +reserved if ilk if_like +reserved in ilk unorbinop_like +reserved is ilk is_like +reserved limited ilk math_like +reserved loop ilk loop_like +reserved mod ilk binop_like +reserved new ilk unop_like +reserved not ilk unop_like +reserved null ilk math_like +reserved of ilk math_like +reserved or ilk or_like +reserved others ilk math_like +reserved out ilk math_like +reserved package ilk proc_like +reserved pragma ilk math_like +reserved private ilk private_like +reserved procedure ilk proc_like +reserved raise ilk math_like +reserved range ilk math_like +reserved record ilk record_like +reserved rem ilk binop_like +reserved renames ilk math_like +reserved return ilk math_like +reserved reverse ilk math_like +reserved select ilk select_like +reserved separate ilk separate_like +reserved subtype ilk math_like +reserved task ilk proc_like +reserved terminate ilk math_like +reserved then ilk then_like +reserved type ilk math_like +reserved use ilk math_like +reserved when ilk when_like +reserved while ilk math_like +reserved with ilk with_like +reserved xor ilk binop_like + +ilk and_like translation <*> category and +ilk at_like translation <*> category at +ilk begin_like translation <*-indent> category beginning +ilk binop_like translation <"\\"-space-*-"\\"-space> category binop +ilk case_like translation <*> category case +ilk decl_like translation <*-indent> category declaration +ilk do_like translation <*> category do +ilk else_like translation <*> category else +ilk elsif_like translation <*> category elsif +ilk end_like translation <*> category close +ilk ex_like translation <*> category exception +ilk gen_like translation <*-indent> category generic +ilk if_like translation <*> category if +ilk is_like translation <*> category is +ilk loop_like translation <*> category loop +ilk math_like translation <*> category math +ilk or_like translation <*> category or +ilk private_like translation <*> category private +ilk proc_like translation <force-*> category proc +ilk record_like translation <*> category record +ilk select_like translation <*> category select +ilk separate_like translation <*> category separate +ilk then_like translation <*> category then +ilk unop_like translation <*-"\\"-space> category unop +ilk unorbinop_like translation <"\\"-space-*-"\\"-space> category resunorbinop +ilk when_like translation <*> category when +ilk with_like translation <*> category with + + +# \MC means ``math close'' and sets \MS to ``math set'' +macros begin +\def\MC{\ifmmode\global\let\MS$\else\global\let\MS\relax\fi\relax\MS} +\def\LG{\mathord{<}\mathord{>}} +\let\IG=\ignorespaces +macros end + + + +beginning <outdent-force> continuation <outdent-force> ending --> stmt +beginning <outdent-force> ending --> stmt +# beginning <force> (stmt|ignore_scrap) --> beginning +beginning <force> stmt --> beginning + +case <"\\"-space> math <"\\"-space> is <indent-force> --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation <force> stmt --> continuation +continuation <outdent-force> continuation --> continuation + + +declaration <outdent-force> beginning <outdent-force> continuation <outdent-force> ending --> stmt +declaration <outdent-force> beginning <outdent-force> ending --> stmt +declaration <outdent-force> ending --> stmt +declaration <force> (declaration|stmt) --> declaration + +else <indent-force> --> continuation +elsif <"\\"-space> math <"\\"-space> then <indent-force> --> continuation + +exception <indent-force> --> continuation + +generic <outdent-force> declaration --> declaration +generic <force> stmt --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen <indent-force> stmt --> beginning +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> else --> ifthen +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> close <"\\"-space> if --> math +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> elsif --> if + + +is --> math + +loop <indent-force> --> beginning + +math [ <"\\"-space> and <"\\"-space> then <"\\"-space> ] --> math binop +math [ <"\\"-space> and <"\\"-space> ] --> math binop + +math (binop|unorbinop) math --> math +math <"\\"-space> resunorbinop <"\\"-space> math --> math +(unorbinop|unop) math --> math +resunorbinop <"\\"-space> math --> math +# This doesn't apply in Ada: math unop --> math + +math arrow --> math +math <"\\"-space> at --> math +math binop <"\\"-space> exception --> math +math <"\\"-space> is --> math +math <"\\"-space> loop --> loop +math <"\\"-space> math --> math +math [ <"\\"-space> or <"\\"-space> else <"\\"-space> ] --> math binop +math [ <"\\"-space> or <"\\"-space> ] --> math binop +math <"\\"-space> private --> math +math <"\\"-space> separate --> math +math <indent-force> stmt <outdent-force> --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + +<force-backup> openlabel math closelabel <force> --> math + +or <indent-force> --> continuation + +private <indent-force> --> beginning + +proc <"\\"-space> math <"\\"-space> is <"\\"-space> unop --> math +proc <"\\"-space> math <"\\"-space> is <"\\"-space> separate --> math +proc <"\\"-space> math <"\\"-space> is <indent-force> --> declaration +proc <"\\"-space> math <"\\"-space> do <indent-force> --> beginning +proc <"\\"-space> math terminator <force> --> declaration + +#record <"\\"-space> at <"\\"-space> math terminator <indent-force> --> beginning +record <indent-force> --> beginning + +select <indent-force> --> beginning + +semi --> terminator + +separate math --> stmt + +stmt <force> declaration --> declaration + +stmt <force> stmt --> stmt + +stmt <outdent-force> ending --> stmt + +when <"\\"-space> math arrow <indent-force> --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt <outdent-force> ending --> ending +whengroup stmt <outdent-force> continuation --> continuation +whengroup stmt <outdent-force> whengroup --> whengroup + +with <"\\"-space> math --> math +with <"\\"-space> proc <"\\"-space> math --> math + +? ignore_scrap --> #1 + +macros begin +\let\AR=\Longrightarrow +macros end +------------------ +End of ada.spider +------------------ + +I'll let you know about the change you suggested. Until the problem +has been fixed, I have asked users here not use bases larger than ten +when specifying numeric constants. + + Sylvester Fernandez + diff --git a/web/spiderweb/src/ada/old.spider b/web/spiderweb/src/ada/old.spider new file mode 100644 index 0000000000..ce2b566a7d --- /dev/null +++ b/web/spiderweb/src/ada/old.spider @@ -0,0 +1,261 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language Ada extension ada + +at_sign @ + +module definition stmt use math + +comment begin <dash-dash> end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin <dash-dash-"line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness maybe +token number category math mathness yes +token newline category ignore_scrap translation <> mathness maybe +token pseudo_semi translation <> category semi mathness maybe + +macros begin +\let\R\relax +macros end + +# Delimiters +token & category binop translation <"\\amp"> +token ( category open +token ) category close +token * category binop +token + category unorbinop +token , category binop translation <",\\,"-opt-3> +token - category unorbinop +token . category binop +token / category binop +token : category binop +token ; category semi translation <";"-space-opt-2> +token < category binop +token = category binop +token > category binop +token | category binop translation <"\\mid"> + +# Compound delimiters + +token => category arrow translation <"\\AR"> +token .. category binop translation <"\\.{..}"> +token ** category binop translation <"\\mathbin{**}"> +token := category binop translation <"\\mathbin{:=}"> +token /= translation <"\\I"> category binop +token >= translation <"\\G"> category binop +token <= translation <"\\L"> category binop +token << translation <"\\LL"> category openlabel +token >> translation <"\\GG"> category closelabel +token <> translation <"\\LG"> category math + +# Hacks no ', and this becomes a binary op +token ' category binop mathness no + +token # category math translation <"\\#"> + + + + +default mathness maybe translation <*> + +reserved abort ilk math_like +reserved abs ilk unop_like +reserved accept ilk proc_like +reserved access ilk math_like +reserved all ilk math_like +reserved and ilk and_like +reserved array ilk math_like +reserved at ilk at_like +reserved begin ilk begin_like +reserved body ilk math_like +reserved case ilk case_like +reserved constant ilk math_like +reserved declare ilk decl_like +reserved delay ilk math_like +reserved delta ilk math_like +reserved digits ilk math_like +reserved do ilk is_like +reserved else ilk else_like +reserved elsif ilk elsif_like +reserved end ilk end_like +reserved entry ilk proc_like +reserved exception ilk ex_like +reserved exit ilk math_like +reserved for ilk math_like +reserved function ilk proc_like +reserved generic ilk gen_like +reserved goto ilk math_like +reserved if ilk if_like +reserved in ilk unorbinop_like +reserved is ilk is_like +reserved limited ilk math_like +reserved loop ilk loop_like +reserved mod ilk binop_like +reserved new ilk separate_like +reserved not ilk unop_like +reserved null ilk math_like +reserved of ilk math_like +reserved or ilk or_like +reserved others ilk math_like +reserved out ilk math_like +reserved package ilk proc_like +reserved pragma ilk math_like +reserved private ilk private_like +reserved procedure ilk proc_like +reserved raise ilk math_like +reserved range ilk math_like +reserved record ilk record_like +reserved rem ilk binop_like +reserved renames ilk math_like +reserved return ilk math_like +reserved reverse ilk math_like +reserved select ilk begin_like +reserved separate ilk separate_like +reserved subtype ilk math_like +reserved task ilk proc_like +reserved terminate ilk math_like +reserved then ilk then_like +reserved type ilk math_like +reserved use ilk math_like +reserved when ilk when_like +reserved while ilk math_like +reserved with ilk with_like +reserved xor ilk binop_like + +ilk and_like translation <*> category and +ilk at_like translation <*> category at +ilk begin_like translation <*-indent> category beginning +ilk binop_like translation <"\\"-space-*-"\\"-space> category binop +ilk case_like translation <*> category case +ilk decl_like translation <*-indent> category declaration +ilk else_like translation <*> category else +ilk elsif_like translation <*> category elsif +ilk end_like translation <*> category close +ilk ex_like translation <*> category exception +ilk gen_like translation <*-indent> category generic +ilk if_like translation <*> category if +ilk is_like translation <*> category is +ilk loop_like translation <*> category loop +ilk math_like translation <*> category math +ilk or_like translation <*> category or +ilk private_like translation <*> category private +ilk proc_like translation <*> category proc +ilk record_like translation <*> category record +ilk separate_like translation <*> category separate +ilk then_like translation <*> category then +ilk unop_like translation <*-"\\"-space> category unop +ilk unorbinop_like translation <"\\"-space-*-"\\"-space> category resunorbinop +ilk when_like translation <*> category when +ilk with_like translation <*> category with + + +# \MC means ``math close'' and sets \MS to ``math set'' +macros begin +\def\MC{\ifmmode\global\let\MS$\else\global\let\MS\relax\fi\relax\MS} +\def\LG{\mathord{<}\mathord{>}} +\let\IG=\ignorespaces +macros end + + + +beginning <outdent-force> continuation <outdent-force> ending --> stmt +beginning <outdent-force> ending --> stmt +# beginning <force> (stmt|ignore_scrap) --> beginning +beginning <force> stmt --> beginning + +case <"\\"-space> math <"\\"-space> is <indent-force> --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation <force> stmt --> continuation +continuation <outdent-force> continuation --> continuation + + +declaration <outdent-force> beginning <outdent-force> continuation <outdent-force> ending --> stmt +declaration <outdent-force> beginning <outdent-force> ending --> stmt +declaration <outdent-force> ending --> stmt +declaration <force> stmt --> declaration + +else <indent-force> --> continuation +elsif <"\\"-space> math <"\\"-space> then <indent-force> --> continuation + +exception <indent-force> --> continuation + +generic <outdent-force> declaration --> declaration +generic <force> stmt --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen <indent-force> stmt --> beginning +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> else --> ifthen +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> close <"\\"-space> if --> math +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> elsif --> if + + +is --> math + +loop <indent-force> --> beginning + +math [ <"\\"-space> and <"\\"-space> then <"\\"-space> ] --> math binop +math [ <"\\"-space> and <"\\"-space> ] --> math binop + +math (binop|unorbinop) math --> math +math <"\\"-space> resunorbinop <"\\"-space> math --> math +(unorbinop|unop) math --> math +resunorbinop <"\\"-space> math --> math +# This doesn't apply in Ada: math unop --> math + +math arrow --> math +math binop <"\\"-space> exception --> math +math <"\\"-space> is --> math +math <"\\"-space> loop --> loop +math <"\\"-space> math --> math +math [ <"\\"-space> or <"\\"-space> else <"\\"-space> ] --> math binop +math [ <"\\"-space> or <"\\"-space> ] --> math binop +math <"\\"-space> private --> math +math <"\\"-space> separate --> math +math <indent-force> stmt <outdent-force> --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + +<force-backup> openlabel math closelabel <force> --> math + +or <indent-force> --> continuation + +private <indent-force> --> beginning + +proc <"\\"-space> math <"\\"-space> is <"\\"-space> separate --> math +proc <"\\"-space> math <"\\"-space> is <indent-force> --> declaration +proc <"\\"-space> math terminator --> stmt + +record <"\\"-space> at <"\\"-space> math terminator <indent-force> --> beginning +record <indent-force> --> beginning + +semi --> terminator + +stmt <force> stmt --> stmt + +when <"\\"-space> math arrow <indent-force> --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt <outdent-force> ending --> ending +whengroup stmt <outdent-force> whengroup --> whengroup + +with <"\\"-space> math --> math +with <"\\"-space> proc <"\\"-space> math --> math + +? ignore_scrap --> #1 + +macros begin +\let\AR=\Longrightarrow +macros end diff --git a/web/spiderweb/src/ada/stacks.web b/web/spiderweb/src/ada/stacks.web new file mode 100644 index 0000000000..8e05ee0f31 --- /dev/null +++ b/web/spiderweb/src/ada/stacks.web @@ -0,0 +1,443 @@ +\message{OK, entering \string\batchmode...} +\batchmode +\overfullrule0pt +\input enumerate +\def\VC#1#2{{\enumerate\item #1\endenumerate\par}{$>\!\!>$\ #2\par}} +%\parindent=0pt\parskip=0.5\baselineskip +\let\maps\rightarrow +\def\title{A Generic Stack Package} + +@*Stacks. +The idea is to implement, and to prove part of, a simple stack package. +We write a Larch trait for the stacks, +we use terms of that trait to specify our package. + In the package body we write down an explicit +representation invariant |invar| and an explicit abstraction function +|abstraction|, and we use them to prove the package \`a la Hoare. +The package specification refers only to the abstract trait, +and our software will automatically perform the translation required +to introduce explicit invariants and abstraction functions in the +package body. + +@*Theory of stacks. +We use the following theory: +%\input stacktrait.pretty + + +@*Specification. +We now use the |Stack_theory| trait to specify a package. +The phrase +|with trait Stack_theory| +makes the |Stack_theory| trait visible and +the phrase +|based on stack| +makes the sort |stack| from |Stack_theory| the abstract sort |stack'ABSTRACT|. +We also use the |element| sort to represent the private type |element|. +% ACK! What proof obligations does this give? + +In the package {\it specification}, all terms of type |stack| are +specified with terms of type |Stacks_theory.stack|. +In the package {\it body}, we will specify terms of type |stack| with +terms of a sort corresponding to the private type of stack (in this +instance, a record type). +We will provide an abstraction function from terms of the record trait +to terms of the stack trait, and an invariant function from terms of +the record trait to |boolean|. +@c@0 +generic + type element is private; + length: natural := 100; +package stacks is + + type stack is private; +@/ + overflow, underflow: exception; +@# + function empty_stack return stack; + + +@# + function pushit(s:stack; e:element) return stack; + + + + +@# + function popit(s:stack) return stack; + + + + +@# + function topit(s:stack) return element; + + + + +@# + function isEmpty(s:stack) return boolean; + + + + +private + subtype stack_range is natural range 0.. length - 1; + type stack_array is array(stack_range) of element; + type stack is + record + l: natural; -- length + a: stack_array; --stack + end record; + +end stacks; +@*Implementation. +We break the implementation into pieces so we can discuss them one at +a time. + +Within the hidden part of the package, |stack| will stand for the +concrete type (or sort), |stack'CONCRETE|. +Outside, in the specification, |stack| will stand for the abstract +type (or sort), |stack'ABSTRACT|. +We use types in actual Ada code, and sorts in annotations and virtual +functions. + +@c +generic + type element is private; + length: natural := 100; +package body stacks is +@<Abstraction and invariants@>@; +@<Implementation of |empty_stack|@>@; +@<Implementation of |pushit|@>@; +@<Implementation of |popit|@>@; +@<Implementation of |topit|@>@; +@<Implementation of |isEmpty|@>@; +end stacks; +@ Here we make explicit the representation invariant |invar| and the +abstraction function |abstraction|. +These are virtual functions, and templates for them will be generated +automatically from the package specification. +These functions will appear in the annotations for the operations of +the package, which will also have been translated from the package +specification. + +The invariant requires only that the length be within sensible bounds. +(I have ignored the problem of definedness throughout the example.) +The abstraction function works by peeling off the top element, and +pushing it onto the abstraction of what's left. +This works all the way down to |s.l=0|, for which the abstraction is +|new_stack|. + +The templates for |invar| and |abstraction| are generated +automatically. + +@<Abstraction...@>= + + + + + + + + + + + + + + + + + +@ To implement |empty_stack| we return a stack of length zero. + +@<Implementation of |empty_stack|@>= +function empty_stack return stack + + + + + +is + empty: stack; +begin + empty.l := 0; + return empty; +end empty_stack; + +@*Proof of |empty_stack|. +Here and elsewhere we will use the notation |@@return| to denote the return +value. +Predicate transformation of the postcondition leaves the following verification +condition: +\VC{|true|}{|invar(empty) and abstraction(empty)=new_stack|} + +We split and get +\VC{|true|}{|invar(empty)|} +and, expanding +\VC{|true|}{|0<=empty.l and empty.l <= length|} +and substituting for |empty.l| (on what basis?) +\VC{|true|}{|0<=0 and 0 <= length|} +from which +\VC{|true|}{|true|} +because of the property |0<=n| for any natural number |n|. + +The second verification condition is +\VC{|true|}{|abstraction(empty)=new_stack|} +We expand |abstraction|, spawning the new VC +\VC{|true|}{|invar(empty)|} +for which we can refer to the earlier proof. +We are left with +\VC{|true|}{|if empty.l=0 then new_stack else + push(abstraction(empty[l=>l-1]),empty.a(empty.l)); + end if = new_stack;|} +Which rewrites to +\VC{|true|}{|new_stack=new_stack|} + + +@ Here we have to check for overflow, but there are really no surprises. +@<Implementation of |pushit|@>= +function pushit(s:stack; e:element) return stack + + + + + + +is + t: stack; +begin + if s.l=length then raise overflow; end if; + t.l := s.l+1; + t.a := s.a; + t.a(t.l) := e; + return t; +end empty_stack; + +@*Predicate transformation of |pushit|. +Here we have ignored the possibility of abnormal termination. + +I've written intermediate conditions in between the statements to +which they apply. +The predicate transformation rules I've used are completely +informal. + + +@c +function pushit(s:stack; e:element) return stack + + + + + + + +is + t: stack; +begin + + + + if s.l=length then raise overflow; end if; + + + t.l := s.l+1; + + + t.a := s.a; + + + t.a(t.l) := e; + + + return t; + + +end empty_stack; + +@*Proof of |pushit|. +We're going to make heavy use of a (nonexistent) theory of records. +Record states are as in Anna; +informally they behave just as you would think. + +We first rewrite the term involving |t| into a simpler and more useful +form: +$$\vbox{\noindent +|t[l=>s.l+1;a=>s.a;a(l)=>e]| rewrites to +|s[l=>l+1;a(l)=>e]|. +}$$ + + +After this simplification we have this verification condition: +\VC{| +invar(s)|\item +|not (size(abstraction(s)) = length)|} +{| +s.l /= length and +invar(s[l=>l+1;a(l)=>e]) and +abstraction(s[l=>l+1;a(l)=>e])=push(abstraction(s),e) +|} +We'll tackle one conjunct at a time. + +@ {\it First conjunct.} +We begin by proving a lemma about |size|: +\VC{|invar(s)|} +{|size(abstraction(s))|$\simeq$|s.l|} +The proof is by type induction on the predefined type |natural|. +We omit it here. + +Once we have the |size| lemma we rewrite the VC for the first conjunct as: +\VC{| +invar(s)|\item +|not (s.l = length)|} +{|s.l /= length|} +The proof is by the laws (not stated) for |=| and |/=|. + +@ {\it Second Conjunct.} +Again we apply the |size| lemma. +\VC{| +invar(s)|\item +|not (s.l = length)|} +{| +invar(s[l=>l+1;a(l)=>e])|} +Expanding the definition of |invar| in the hypothesis and the conclusion yields +\VC{| +0<=s.l and s.l <= length|\item +|not (s.l = length)|} +{| +0<=s[l=>l+1;a(l)=>e].l and +s[l=>l+1;a(l)=>e].l<=length +|} +and we again exploit the theory of records to rewrite as +\VC{| +0<=s.l and s.l <= length|\item +|not (s.l = length)|} +{| +0<=s.l+1 and +s.l+1<=length +|} +And the proof follows by |and|-splitting hypotheses and conclusion and by +applying the laws of arithmetic. + +@ {\it Third conjunct.} +This is the interesting part. +We expand the definition of |abstraction| on the left hand side of the +conclusion. +This spawns a VC showing that the argument to |abstraction| satisfies +|invariant|, but we did that earlier. + +\VC{| +invar(s)|\item +|not (size(abstraction(s)) = length)|} +{| +if s[l=>l+1;a(l)=>e].l=0 then new_stack else +push(abstraction(s[l=>l+1;a(l)=>e;l=>l-1]), +s[l=>l+1;a(l)=>e].a(s[l=>l+1;a(l)=>e].l)) end if + =push(abstraction(s),e) +|} +and, rewriting according to the theory of records +(especially +|s[l=>l+1;a(l)=>e].a(s[l=>l+1;a(l)=>e].l)| +rewrites to +|s[l=>l+1;a(s.l+1)=>e].a(s.l+1)| +which rewrites to |e|): +\VC{| +invar(s)|\item +|not (size(abstraction(s)) = length)|} +{| +if s.l+1=0 then new_stack else +push(abstraction(s[a(l+1)=>e]),e) end if + =push(abstraction(s),e) +|} +Applying the laws of natural numbers we have +\VC{| +invar(s)|\item +|not (size(abstraction(s)) = length)|} +{| +push(abstraction(s[a(l+1)=>e]),e) = push(abstraction(s),e) +|} + + +And now we show by a lemma that +\VC{|invar(s)|\item |s.l/=length|} +{ +|abstraction(s[a(l+1)=>e])|$\simeq$|abstraction(s)| +} +which is sufficient. +The proof of the lemma is by induction over |l| (type induction of the +predefined type |natural|). + + + + +@ @<Implementation of |popit|@>= +function popit(s:stack) return stack + + + + + + +is + t: stack; +begin + if s.l=0 then raise underflow; end if; + t := s; + t.l := t.l-1; + return t; +end popit; + +@ @<Implementation of |topit|@>= +function topit (s:stack) return element + + + + +is +begin + if s.l=0 then raise underflow; end if; + return s.a(s.l); +end topit; + +@ @<Implementation of |isEmpty|@>= + function isEmpty(s:stack) return boolean + + + + + is + begin + return s.l=0; + end isEmpty; +@ Predicate transformation of isEmpty. +@c + function isEmpty(s:stack) return boolean + + + + + is + begin + + return s.l=0; + + end isEmpty; + +@ Proof of isEmpty. +\VC{|invariant(s)|}{|s.l=0 =is_empty(abstraction(s))|} +Expanding |abstraction(s)|, +\VC{|invariant(s)|}{|s.l=0 =is_empty(if s.l=0 then nil + else cons(abstraction(s[l=>l-1]),l.a(s.l-1)))|} +Simplifying, +\VC{|invariant(s)|}{|(s.l=0)=if s.l=0 then is_empty(nil) + else is_empty(cons(abstraction(s[l=>l-1]),l.a(s.l-1)))|} +which we can rewrite as +\VC{|invariant(s)|}{|(s.l=0)=if s.l=0 then true + else is_empty(cons(abstraction(s[l=>l-1]),l.a(s.l-1)))|} +Simplifying, +\VC{|invariant(s)|}{|true|} + + +@*Index. +This is an index of all the identifiers used in the program. +The numbers are section numbers, not page numbers.
\ No newline at end of file diff --git a/web/spiderweb/src/awk/awk.spider b/web/spiderweb/src/awk/awk.spider new file mode 100644 index 0000000000..0ecc98c8c4 --- /dev/null +++ b/web/spiderweb/src/awk/awk.spider @@ -0,0 +1,168 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language AWK extension awk + +at_sign # + +module definition stmt use stmt +# use as stmt is unavoidable since tangle introduces line breaks + +comment begin <"##"> end newline +macros begin +\def\commentbegin{\#} % we don't want \#\# +macros end + +line begin <"#line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness yes +token number category math mathness yes +token newline category newline translation <> mathness maybe +token pseudo_semi category ignore_scrap mathness no translation <opt-0> + +token \ category backslash translation <> mathness maybe +token + category unorbinop +token - category unorbinop +token * category binop +token / category binop +token < category binop +token > category binop +token >> category binop translation <"\\GG"> +token = category equals translation <"\\K"> +token ~ category binop translation <"\\TI"> +token !~ category binop translation <"\\not\\TI"> +token & category binop translation <"\\amp"> +token % translation <"\\%"> category binop +token ( category open +token [ category lsquare +token ) category close +token ] category close +token { translation <"\\;\\{"-indent> category lbrace +token } translation <"\\}\\"-space> category close +token , category binop translation <",\\,"-opt-3> + +token ; category semi translation <";"-space-opt-2> mathness no +# stuff with semi can be empty in for statements +open semi --> open +semi semi --> semi +semi close --> close +semi --> binop + +# token : category colon +# token | category bar +token != name not_eq translation <"\\I"> category binop +token <= name lt_eq translation <"\\L"> category binop +token >= name gt_eq translation <"\\G"> category binop +token == name eq_eq translation <"\\S"> category binop +token && name and_and translation <"\\W"> category binop +token || name or_or translation <"\\V"> category binop +# token -> name minus_gt translation <"\\MG"> category binop +token ++ name gt_gt category unop translation <"\\uparrow"> +token -- name lt_lt category unop translation <"\\downarrow"> +# preunop is for unary operators that are prefix only +token $ category preunop translation <"\\DO"> mathness yes + +default mathness yes translation <*> + +ilk pattern_like category math +reserved BEGIN ilk pattern_like +reserved END ilk pattern_like + +ilk if_like category if +reserved if +ilk else_like category else +reserved else + +ilk print_like category math +# math forces space between this and other math... +reserved print ilk print_like +reserved printf ilk print_like +reserved sprintf ilk print_like + + +ilk functions category unop mathness yes +reserved length ilk functions +reserved substr ilk functions +reserved index ilk functions +reserved split ilk functions +reserved sqrt ilk functions +reserved log ilk functions +reserved exp ilk functions +reserved int ilk functions + +ilk variables category math mathness yes +reserved NR ilk variables +reserved NF ilk variables +reserved FS ilk variables +reserved RS ilk variables +reserved OFS ilk variables +reserved ORS ilk variables + +ilk for_like category for +reserved for ilk for_like +reserved while ilk for_like + +ilk in_like category binop translation <math_bin-*-"}"> mathness yes +# translation <"\\"-space-*-"\\"-space> +reserved in ilk in_like + +ilk stmt_like category math +reserved break ilk stmt_like +reserved continue ilk stmt_like +reserved next ilk stmt_like +reserved exit ilk stmt_like + + +backslash newline --> math +# The following line must be changed to make a backslash +backslash <"\\backslash"> --> math + +math (binop|unorbinop) math --> math +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +(unop|preunop|unorbinop) math --> math +# unorbinop can only act like unary op as *prefix*, not postfix +math unop --> math +math <"\\"-space> math --> math +# concatenation + +math newline --> stmt +newline --> ignore_scrap + +stmt <force> stmt --> stmt + +(open|lsquare) math close --> math + +math lbrace --> lbrace +lbrace <force> stmt --> lbrace +lbrace <outdent-force> close --> stmt + +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> close else <"\\"-space> if --> if +ifbrace <outdent-force> close else lbrace --> ifbrace +ifbrace <outdent-force> close else newline --> ifline +ifbrace <outdent-force> close --> stmt +(ifline|ifmath) <indent-force> stmt <outdent-force> else <"\\"-space> if --> if +(ifline|ifmath) <indent-force> stmt <outdent-force> else lbrace --> ifbrace +(ifline|ifmath) <indent-force> stmt <outdent-force> else newline --> ifline +(ifline|ifmath) <indent-force> stmt <outdent-force> else --> ifmath +(ifline|ifmath) <indent-force> stmt <outdent> --> stmt + +for <"\\"-space> math --> formath +formath lbrace --> forbrace +formath newline --> forline +forbrace <force> stmt --> forbrace +forbrace <outdent-force> close --> stmt +(forline|formath) <indent-force> stmt <outdent> --> stmt + + + +? ignore_scrap --> #1 + + + diff --git a/web/spiderweb/src/awk/make b/web/spiderweb/src/awk/make new file mode 100644 index 0000000000..5eda54b414 --- /dev/null +++ b/web/spiderweb/src/awk/make @@ -0,0 +1,2 @@ +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=awktangle THEWEAVE=awkweave SPIDER=awk.spider $* diff --git a/web/spiderweb/src/awk/tangle.c b/web/spiderweb/src/awk/tangle.c new file mode 100644 index 0000000000..7cc7250d5d --- /dev/null +++ b/web/spiderweb/src/awk/tangle.c @@ -0,0 +1,2172 @@ +/*1:*/ +#line 44 "tangle.web" + +/*4:*/ +#line 15 "common.h" + +#line 16 "common.h" +#include<stdio.h> + +/*:4*//*94:*/ +#line 1046 "tangle.web" + +#line 1047 "tangle.web" +#include"ctype.h" + +/*:94*/ +#line 45 "tangle.web" + +/*3:*/ +#line 9 "common.h" + +typedef short boolean; +typedef char unsigned eight_bits; +extern boolean program; +extern int phase; + +/*:3*//*5:*/ +#line 24 "common.h" + +typedef char ASCII; +typedef char outer_char; +extern ASCII xord[]; +extern outer_char xchr[]; +ASCII mod_text[400+1]; +ASCII *mod_text_end= mod_text+400; +ASCII *id_first; +ASCII *id_loc; + +/*:5*//*6:*/ +#line 37 "common.h" + +#line 38 "common.h" +extern ASCII buffer[]; +extern ASCII *buffer_end; +extern ASCII *loc; +extern ASCII *limit; + +/*:6*//*7:*/ +#line 55 "common.h" + +typedef struct name_info{ +ASCII *byte_start; +struct name_info *link; +union{ +struct name_info *Rlink; + +eight_bits Ilk; + +}dummy; +ASCII *equiv_or_xref; +}name_info; +typedef name_info *name_pointer; +typedef name_pointer *hash_pointer; +extern ASCII byte_mem[]; +extern ASCII *byte_mem_end; +extern name_info name_dir[]; +extern name_pointer name_dir_end; +extern name_pointer name_ptr; +extern ASCII *byte_ptr; +extern name_pointer hash[]; +extern hash_pointer hash_end; +extern hash_pointer h; +extern name_pointer id_lookup(); +extern name_pointer mod_lookup(); +extern name_pointer prefix_lookup(); + +/*:7*//*8:*/ +#line 98 "common.h" + +extern history; + +/*:8*//*9:*/ +#line 109 "common.h" + +extern include_depth; +extern FILE *file[]; +extern FILE *change_file; +extern char C_file_name[]; +extern char tex_file_name[]; +extern char file_name[][60]; + +extern char change_file_name[]; +extern line[]; +extern change_line; +extern boolean input_has_ended; +extern boolean changing; + +/*:9*//*10:*/ +#line 124 "common.h" + +#line 125 "common.h" +typedef unsigned short sixteen_bits; +extern sixteen_bits module_count; +extern boolean changed_module[]; +extern boolean print_where; + +/*:10*//*11:*/ +#line 131 "common.h" + +#line 132 "common.h" +extern int argc; +extern char * *argv; +extern no_xref; + +/*:11*//*12:*/ +#line 144 "common.h" + +FILE *C_file; +FILE *tex_file; +#line 81 "tangle.web" + +/*:12*/ +#line 46 "tangle.web" + +/*14:*/ +#line 107 "tangle.web" + +#line 108 "tangle.web" +typedef struct{ +eight_bits *tok_start; +sixteen_bits text_link; +}text; +typedef text *text_pointer; + +/*:14*//*25:*/ +#line 254 "tangle.web" + +typedef struct{ +eight_bits *end_field; +eight_bits *byte_field; +name_pointer name_field; +text_pointer repl_field; +sixteen_bits mod_field; +}output_state; +typedef output_state *stack_pointer; + +/*:25*/ +#line 47 "tangle.web" + +/*15:*/ +#line 114 "tangle.web" + +#line 115 "tangle.web" +text text_info[2000]; +text_pointer text_info_end= text_info+2000-1; +text_pointer text_ptr; +eight_bits tok_mem[150000]; +eight_bits *tok_mem_end= tok_mem+150000-1; +eight_bits *tok_ptr; + +/*:15*//*21:*/ +#line 185 "tangle.web" + +text_pointer last_unnamed; + +/*:21*//*26:*/ +#line 270 "tangle.web" + +output_state cur_state; + +output_state stack[50+1]; +stack_pointer stack_ptr; +stack_pointer stack_end= stack+50; + +/*:26*//*37:*/ +#line 413 "tangle.web" + +int cur_val; + + +/*:37*//*46:*/ +#line 520 "tangle.web" + +#line 521 "tangle.web" +short balances[128]; +/*:46*//*50:*/ +#line 583 "tangle.web" + +#line 584 "tangle.web" +name_pointer parm_ptr; + +/*:50*//*62:*/ +#line 706 "tangle.web" + +eight_bits out_state; +boolean protect; + +/*:62*//*64:*/ +#line 735 "tangle.web" + +name_pointer output_files[256]; +name_pointer *cur_out_file, *end_output_files, *an_output_file; +char cur_module_char; +char output_file_name[400]; + +/*:64*//*78:*/ +#line 101 "outtoks.web" +char C_file_extension[]= "awk"; +/*:78*//*80:*/ +#line 106 "outtoks.web" +char the_at_sign= 35; + +/*:80*//*86:*/ +#line 943 "tangle.web" + +eight_bits ccode[128]; + +/*:86*//*88:*/ +#line 975 "tangle.web" +short tracing; +#line 976 "tangle.web" +/*:88*//*91:*/ +#line 1009 "tangle.web" + +#line 1010 "tangle.web" +boolean comment_continues= 0; + +/*:91*//*93:*/ +#line 1043 "tangle.web" + +name_pointer cur_module; + +/*:93*//*108:*/ +#line 1310 "tangle.web" + +text_pointer cur_text; +eight_bits next_control; + +/*:108*//*111:*/ +#line 1373 "tangle.web" + +ASCII param_name_texts[256]; +ASCII *param_name_texts_end= param_name_texts+256; +ASCII *param_names[32]; +short next_param_name; +ASCII *next_param_name_text; + +/*:111*//*132:*/ +#line 1693 "tangle.web" + +#line 1694 "tangle.web" +extern sixteen_bits module_count; + +/*:132*/ +#line 48 "tangle.web" + + +main(ac,av) +char * *av; +{ +argc= ac;argv= av; +program= 0; +/*16:*/ +#line 122 "tangle.web" + +#line 123 "tangle.web" +text_info->tok_start= tok_ptr= tok_mem; +text_ptr= text_info+1;text_ptr->tok_start= tok_mem; + + +/*:16*//*18:*/ +#line 132 "tangle.web" + +name_dir->equiv_or_xref= (ASCII *)text_info; + +/*:18*//*22:*/ +#line 188 "tangle.web" +last_unnamed= text_info;text_info->text_link= 0; +#line 189 "tangle.web" + +/*:22*//*47:*/ +#line 522 "tangle.web" + +#line 523 "tangle.web" +{int i; +for(i= 0;i<128;i++)balances[i]= 0; +/*48:*/ +#line 529 "tangle.web" + +#line 530 "tangle.web" +balances[40]= 1; +balances[41]= -1; +balances[91]= 1; +balances[93]= -1; +balances[123]= 1; +balances[125]= -1; + +/*:48*/ +#line 525 "tangle.web" +; +} +/*:47*//*65:*/ +#line 745 "tangle.web" + +#line 746 "tangle.web" +cur_out_file= end_output_files= output_files+256; + +/*:65*//*87:*/ +#line 946 "tangle.web" +{ +#line 947 "tangle.web" +int c; +for(c= 0;c<=127;c++)ccode[c]= 0; +ccode[' ']= ccode[011]= ccode['*']= 255; +ccode['@']= '@'; +ccode['=']= 2; +ccode['d']= ccode['D']= 252; +ccode['f']= ccode['F']= 251; +ccode['c']= ccode['C']= 253; +ccode['u']= ccode['U']= 253; +ccode['^']= ccode[':']= ccode['.']= ccode['t']= ccode['T']= 250; +ccode['&']= 127; +ccode['<']= ccode['(']= 254; +ccode['`']= 249; +ccode['\'']= 5; +ccode['"']= 6; + + + +ccode['@']= ccode[35]; +ccode[35]= 35; + +#ifdef DEBUG +ccode['0']= ccode['1']= ccode['2']= ccode['3']= ccode['4']= 248; +#endif DEBUG + +} + +/*:87*//*89:*/ +#line 976 "tangle.web" +tracing= 0; +#line 977 "tangle.web" + +/*:89*//*104:*/ +#line 1239 "tangle.web" +mod_text[0]= ' '; +#line 1240 "tangle.web" + +/*:104*//*113:*/ +#line 1385 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1385 "tangle.web" +; +#line 1386 "tangle.web" + +/*:113*/ +#line 55 "tangle.web" +; +common_init(); +printf("This is AWK TANGLE (generated at 5:29 PM on April 5, 1993)\n"); +phase_one(); +phase_two(); +wrap_up(); +} + +/*:1*//*19:*/ +#line 138 "tangle.web" + +#line 139 "tangle.web" +names_match(p,first,l) +name_pointer p; +ASCII *first; +int l; +{ +if(((p+1)->byte_start-(p)->byte_start)!=l)return 0; +return!strncmp(first,p->byte_start,l); +} + +/*:19*//*20:*/ +#line 149 "tangle.web" + +#line 150 "tangle.web" +init_node(node) +name_pointer node; +{ +node->equiv_or_xref= (ASCII *)text_info; + +} +init_p(p,t) +name_pointer p; +eight_bits t; +{ +p->dummy.Ilk= t; +} + + + +/*:20*//*24:*/ +#line 219 "tangle.web" +store_two_bytes(x) +sixteen_bits x; +{ +if(tok_ptr+2>tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; + *tok_ptr++= x>>8; + *tok_ptr++= x&255; +} + + +/*:24*//*28:*/ +#line 294 "tangle.web" +push_level(p) +#line 295 "tangle.web" +name_pointer p; +{ +/*29:*/ +#line 306 "tangle.web" + +#line 307 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>0){ +printf("\nPushing ");fflush(stdout),write(1,(p)->byte_start,(((p)+1)->byte_start-((p))->byte_start)); +printf(" =nd[%d]",p-name_dir); +} +#endif TRACE_MACROS + +/*:29*/ +#line 297 "tangle.web" +; +if(stack_ptr==stack_end){{printf("\n! Sorry, capacity exceeded: ");err_print("stack");history= 3;wrap_up();};}; + *stack_ptr= cur_state; +stack_ptr++; +cur_state.name_field= p;cur_state.repl_field= (text_pointer)p->equiv_or_xref; +cur_state.byte_field= cur_state.repl_field->tok_start;cur_state.end_field= (cur_state.repl_field+1)->tok_start; +cur_state.mod_field= 0; +} + +/*:28*//*30:*/ +#line 321 "tangle.web" +pop_level() +#line 322 "tangle.web" +{int number_of_parameters; +/*33:*/ +#line 363 "tangle.web" + +#line 364 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>0){ +printf("\nPopping ");fflush(stdout),write(1,(cur_state.name_field)->byte_start,(((cur_state.name_field)+1)->byte_start-((cur_state.name_field))->byte_start)); +printf(" =nd[%d]",cur_state.name_field-name_dir); +} + +#endif TRACE_MACROS + + + +/*:33*/ +#line 323 "tangle.web" +; +if(cur_state.repl_field->text_link==0){ +if(cur_state.name_field->dummy.Ilk==1){ +/*31:*/ +#line 338 "tangle.web" + +#line 339 "tangle.web" +number_of_parameters= *(cur_state.repl_field->tok_start); +/*32:*/ +#line 357 "tangle.web" + +#line 358 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>1){ +printf("\nUnstacking %d parameters",number_of_parameters); +} +#endif TRACE_MACROS +/*:32*/ +#line 340 "tangle.web" +; +while(number_of_parameters-->0){ +name_ptr--;text_ptr--; +#ifdef TRACE_MACROS +byte_ptr-= 2; +#endif TRACE_MACROS +} +#ifdef STAT +#ifdef STAT_HAS_BEEN_FIXED +if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr; + + +#endif STAT_HAS_BEEN_FIXED +#endif STAT +tok_ptr= text_ptr->tok_start; + + +/*:31*/ +#line 326 "tangle.web" +; +} +}else if(cur_state.repl_field->text_link<2000){ +cur_state.repl_field= cur_state.repl_field->text_link+text_info; +cur_state.byte_field= cur_state.repl_field->tok_start;cur_state.end_field= (cur_state.repl_field+1)->tok_start; +return; +} +stack_ptr--; +if(stack_ptr>stack)cur_state= *stack_ptr; +} + + +/*:30*//*38:*/ +#line 418 "tangle.web" +sixteen_bits +#line 419 "tangle.web" + get_output() +{ +sixteen_bits a; +restart:if(stack_ptr==stack)return 0; +if(cur_state.byte_field==cur_state.end_field){ +cur_val= -((int)cur_state.mod_field); +pop_level(); +if(cur_val==0)goto restart; +out_char(129);return; +} +a= *cur_state.byte_field++; +if(a<128) +if(a==7){ +/*40:*/ +#line 454 "tangle.web" + +#line 455 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf(" [#%d]", *cur_state.byte_field); +} +#endif TRACE_MACROS + +/*:40*/ +#line 432 "tangle.web" +; +/*39:*/ +#line 452 "tangle.web" + +#line 453 "tangle.web" +push_level(name_ptr- *cur_state.byte_field++);goto restart; +/*:39*/ +#line 434 "tangle.web" +; +}else +out_char(a); +else{ +a= (a-128) *256+ *cur_state.byte_field++; +switch(a/10240){ +case 0: +/*41:*/ +#line 461 "tangle.web" + +#line 462 "tangle.web" +if(name_dir[a].dummy.Ilk==1){ +/*42:*/ +#line 475 "tangle.web" + +#line 476 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf("\nExpanding macro (");fflush(stdout),write(1,(name_dir+a)->byte_start,(((name_dir+a)+1)->byte_start-((name_dir+a))->byte_start)); +printf("=nd[%d])",a); +} +#endif TRACE_MACROS + +/*:42*/ +#line 463 "tangle.web" +; +/*44:*/ +#line 492 "tangle.web" + +#line 493 "tangle.web" +{int number_of_parameters; +while(cur_state.byte_field==cur_state.end_field&&stack_ptr>stack)pop_level(); +number_of_parameters= *(((text_pointer)name_dir[a].equiv_or_xref)->tok_start); +if(number_of_parameters>0){ +if(stack_ptr==stack|| *cur_state.byte_field!=40){ +printf("\n! No parameters given for "); +fflush(stdout),write(1,(a+name_dir)->byte_start,(((a+name_dir)+1)->byte_start-((a+name_dir))->byte_start)); +err_print(""); +goto restart; +} +cur_state.byte_field++; +parm_ptr= name_ptr; +while(number_of_parameters-->0){ +/*49:*/ +#line 537 "tangle.web" + +#line 538 "tangle.web" +{int bal; +eight_bits b,oldb; +sixteen_bits c; +bal= 0; +/*59:*/ +#line 647 "tangle.web" + +#line 648 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf("\nScanning #%d...",number_of_parameters+1); +} +#endif TRACE_MACROS +/*:59*/ +#line 542 "tangle.web" +; +while(1){ +b= *cur_state.byte_field++; +if(b==7){ +b= *cur_state.byte_field++; +/*56:*/ +#line 613 "tangle.web" + +#line 614 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf(" <#%d=",b);fflush(stdout),write(1,(name_ptr-b)->byte_start,(((name_ptr-b)+1)->byte_start-((name_ptr-b))->byte_start));printf("=nd[%d]>", +name_ptr-b-name_dir); +} +#endif TRACE_MACROS + +/*:56*/ +#line 547 "tangle.web" +; +c= name_ptr-name_dir-b; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 128+(c/256);}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= c%256;}; +}else{ +if(b>=128){ +/*57:*/ +#line 621 "tangle.web" + +#line 622 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +int c; +printf(" <"); +c= (b-128) *256+ *cur_state.byte_field; +switch(c/10240){ +case 0:fflush(stdout),write(1,(name_dir+c)->byte_start,(((name_dir+c)+1)->byte_start-((name_dir+c))->byte_start)); +printf(" =nd[%d]",c); +break; +case 1:printf("MODULE");break; +default:printf("CONTEXT");break; +} +printf(">"); +} +#endif TRACE_MACROS + +/*:57*/ +#line 553 "tangle.web" +; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= b;}; +b= *cur_state.byte_field++; +}else if(bal==0&&((number_of_parameters==0&&b==41) +||(number_of_parameters>0&&b==44))){ +goto done; +}else if(/*51:*/ +#line 586 "tangle.web" +(b==2||b==3) +#line 587 "tangle.web" +/*:51*/ +#line 559 "tangle.web" +){ +/*52:*/ +#line 587 "tangle.web" + +#line 588 "tangle.web" +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= b;}; +oldb= b; +/*53:*/ +#line 601 "tangle.web" + +#line 602 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2)printf(" <"); +#endif TRACE_MACROS +/*:53*/ +#line 590 "tangle.web" +; +while((b= *cur_state.byte_field++)!=oldb){ +/*54:*/ +#line 605 "tangle.web" + +#line 606 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2)printf("%c",b); +#endif TRACE_MACROS +/*:54*/ +#line 592 "tangle.web" +; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= b;}; +if(cur_state.byte_field>=cur_state.end_field) +{printf("\n! This can't happen: ");err_print("string or constant didn't end in token list");history= 3;wrap_up();}; +} +/*55:*/ +#line 609 "tangle.web" + +#line 610 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2)printf(">"); +#endif TRACE_MACROS +/*:55*/ +#line 597 "tangle.web" +; + + + +/*:52*/ +#line 560 "tangle.web" +; +}else{ +/*58:*/ +#line 638 "tangle.web" + +#line 639 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf(" <"); +if(31<b&&b<127)printf("%c",b); +printf(">"); +} +#endif TRACE_MACROS + +/*:58*/ +#line 562 "tangle.web" +; +bal+= balances[b]; +} +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= b;}; +} +} +done: +parm_ptr->equiv_or_xref= (ASCII *)text_ptr; +text_ptr->text_link= 0; +parm_ptr->dummy.Ilk= 2; +#ifdef TRACE_MACROS +if(byte_ptr+2>=byte_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("byte memory");history= 3;wrap_up();};}; + *byte_ptr++= 35; *byte_ptr++= number_of_parameters+1+48; +#endif TRACE_MACROS +if(parm_ptr>=name_dir_end){{printf("\n! Sorry, capacity exceeded: ");err_print("name");history= 3;wrap_up();};}; +(++parm_ptr)->byte_start= byte_ptr; +if(text_ptr>=text_info_end){{printf("\n! Sorry, capacity exceeded: ");err_print("text");history= 3;wrap_up();};}; +(++text_ptr)->tok_start= tok_ptr; +/*60:*/ +#line 653 "tangle.web" + +#line 654 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>1){ +printf("\nStacked ");fflush(stdout),write(1,(parm_ptr-1)->byte_start,(((parm_ptr-1)+1)->byte_start-((parm_ptr-1))->byte_start)); +printf("=nd[%d]",parm_ptr-1-name_dir); +} +#endif TRACE_MACROS + +/*:60*/ +#line 580 "tangle.web" +; +} + +/*:49*/ +#line 507 "tangle.web" +; +} +name_ptr= parm_ptr; + +} +} + +/*:44*/ +#line 465 "tangle.web" +; +push_level(name_dir+a); +cur_state.byte_field++; +goto restart; +}else if(name_dir[a].dummy.Ilk==2){ +/*43:*/ +#line 483 "tangle.web" + +#line 484 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf("\nExpanding parameter (");fflush(stdout),write(1,(name_dir+a)->byte_start,(((name_dir+a)+1)->byte_start-((name_dir+a))->byte_start)); +printf("=nd[%d])",a); +} +#endif TRACE_MACROS + + +/*:43*/ +#line 470 "tangle.web" +; +push_level(name_dir+a); +goto restart; +} + +/*:41*/ +#line 441 "tangle.web" +; +cur_val= a;out_char(130);break; +case 1:/*61:*/ +#line 664 "tangle.web" + +#line 665 "tangle.web" +a-= 10240; +if((a+name_dir)->equiv_or_xref!=(ASCII *)text_info)push_level(a+name_dir); +else if(a!=0){ +printf("\n! Not present: <");fflush(stdout),write(1,(a+name_dir)->byte_start,(((a+name_dir)+1)->byte_start-((a+name_dir))->byte_start));err_print(">"); + +} +goto restart; + +/*:61*/ +#line 443 "tangle.web" +; +default:cur_val= a-20480;if(cur_val>0)cur_state.mod_field= cur_val; +out_char(129); +} +} +return 1; +} + + +/*:38*//*63:*/ +#line 714 "tangle.web" +flush_buffer() +#line 715 "tangle.web" +{ +putc('\n',C_file); +if(line[include_depth]%100==0){ +printf("."); +if(line[include_depth]%500==0)printf("%d",line[include_depth]); +fflush(stdout); +} +line[include_depth]++; +} + +/*:63*//*67:*/ +#line 764 "tangle.web" + +#line 765 "tangle.web" +phase_two(){ +line[include_depth]= 1; +if(text_info->text_link==0){ +if(end_output_files==cur_out_file){ +printf("\n! No program text was specified.");{if(history==0)history= 1;}; + +} +}else{ +printf("\nWriting the output files: (%s)",C_file_name);fflush(stdout); +/*27:*/ +#line 283 "tangle.web" + +#line 284 "tangle.web" +stack_ptr= stack+1;cur_state.name_field= name_dir;cur_state.repl_field= text_info->text_link+text_info; +cur_state.byte_field= cur_state.repl_field->tok_start;cur_state.end_field= (cur_state.repl_field+1)->tok_start;cur_state.mod_field= 0; + +/*:27*/ +#line 774 "tangle.web" +; +while(stack_ptr>stack)get_output(); +flush_buffer(); +} +if(end_output_files>cur_out_file){ +if(text_info->text_link==0){ +printf("\nWriting the output files: ");fflush(stdout); +} +/*68:*/ +#line 790 "tangle.web" + +#line 791 "tangle.web" +for(an_output_file= end_output_files;an_output_file>cur_out_file;){ +an_output_file--; +strncpy(output_file_name,( *an_output_file)->byte_start,400); +output_file_name[(( *an_output_file+1)->byte_start-( *an_output_file)->byte_start)]= '\0'; +fclose(C_file); +C_file= fopen(output_file_name,"w"); +if(C_file==NULL){ +{printf("! Cannot open output file:");err_print(output_file_name);history= 3;wrap_up();} +}else{ +printf(" (%s)",output_file_name);fflush(stdout); +} +stack_ptr= stack+1; +cur_state.name_field= ( *an_output_file); +cur_state.repl_field= (text_pointer)cur_state.name_field->equiv_or_xref; +cur_state.byte_field= cur_state.repl_field->tok_start; +cur_state.end_field= (cur_state.repl_field+1)->tok_start; +cur_state.mod_field= 0; +while(stack_ptr>stack)get_output(); +flush_buffer(); +} + + + +/*:68*/ +#line 782 "tangle.web" + +} +printf("\nDone."); +} + +/*:67*//*69:*/ +#line 816 "tangle.web" +out_char(cur_char) +#line 817 "tangle.web" +eight_bits cur_char; +{ +ASCII *j; +/*70:*/ +#line 841 "tangle.web" + +#line 842 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +switch(cur_char){ +case 10:printf(" [\\n]");break; +case 2: +printf("[STRING]");break; +case 127: +printf("[JOIN]");break; +case 3: +printf("[CONSTANT]");break; +case 130: +printf(" [");fflush(stdout),write(1,(cur_val+name_dir)->byte_start,(((cur_val+name_dir)+1)->byte_start-((cur_val+name_dir))->byte_start));printf("]"); +break; +case 129: +if(cur_val>0){ +printf(" [%d:]",cur_val); +}else if(cur_val<0){ +printf(" [:%d]",-cur_val); +}else{ +printf("[LINE NUMBER]"); +} +break; + +default: +if(31<cur_char&&cur_char<127){ +printf(" [%c]",cur_char); +}else{ +printf(" [\\%3o]",cur_char); +} +} +} +#endif TRACE_MACROS + + + + +/*:70*/ +#line 820 "tangle.web" +; +switch(cur_char){ +case 10:if(protect)putc(' ',C_file); +if(protect||out_state==4)putc('\\',C_file); + +flush_buffer();if(out_state!=4)out_state= 0;break; +/*71:*/ +#line 878 "tangle.web" + +#line 879 "tangle.web" +case 130: +if(out_state==1)putc(' ',C_file); +for(j= (cur_val+name_dir)->byte_start;j<(name_dir+cur_val+1)->byte_start; +j++)putc( *j,C_file); +out_state= 1;break; + +/*:71*/ +#line 826 "tangle.web" +; +/*72:*/ +#line 885 "tangle.web" + +#line 886 "tangle.web" +case 129: +if(cur_val>0){ +fprintf(C_file,"%s","##"); +fprintf(C_file,"%d:",cur_val); +fprintf(C_file,"%s","\n"); +}else if(cur_val<0){ +fprintf(C_file,"%s","##"); +fprintf(C_file,":%d",-cur_val); +fprintf(C_file,"%s","\n"); +}else{ +sixteen_bits a; +a= 256 * *cur_state.byte_field++; +a+= *cur_state.byte_field++; +fprintf(C_file,"\n%s","#line"); +fprintf(C_file," %d \"",a); +cur_val= *cur_state.byte_field++; +cur_val= 256 *(cur_val-128)+ *cur_state.byte_field++; +for(j= (cur_val+name_dir)->byte_start;j<(name_dir+cur_val+1)->byte_start; +j++)putc( *j,C_file); +fprintf(C_file,"\"%s\n","" +#line 910 "tangle.web" +); +} +break; + +#line 1 "outtoks.web" +/*:72*/ +#line 827 "tangle.web" +; +/*75:*/ +#line 46 "outtoks.web" + +#line 47 "outtoks.web" +case 26: +fprintf(C_file,"%s","=="); +if(out_state!=4)out_state= 0; +break; +case 25: +fprintf(C_file,"%s","&&"); +if(out_state!=4)out_state= 0; +break; +case 24: +fprintf(C_file,"%s","||"); +if(out_state!=4)out_state= 0; +break; +case 28: +fprintf(C_file,"%s","<="); +if(out_state!=4)out_state= 0; +break; +case 23: +fprintf(C_file,"%s","++"); +if(out_state!=4)out_state= 0; +break; +case 27: +fprintf(C_file,"%s",">="); +if(out_state!=4)out_state= 0; +break; +case 29: +fprintf(C_file,"%s","!="); +if(out_state!=4)out_state= 0; +break; +case 31: +fprintf(C_file,"%s",">>"); +if(out_state!=4)out_state= 0; +break; +case 22: +fprintf(C_file,"%s","--"); +if(out_state!=4)out_state= 0; +break; +case 30: +fprintf(C_file,"%s","!~"); +if(out_state!=4)out_state= 0; +break; +/*:75*//*76:*/ +#line 87 "outtoks.web" + +#line 88 "outtoks.web" +/*:76*/ +#line 828 "tangle.web" + +case 127:out_state= 3;break; +case 3:if(out_state==4){ +out_state= 1;break; +} +if(out_state==1)putc(' ',C_file);out_state= 4;break; +case 2:if(out_state==4)out_state= 0; +else out_state= 4;break; +default:putc(cur_char,C_file);if(out_state!=4)out_state= 0; +break; +} +} + +/*:69*//*90:*/ +#line 981 "tangle.web" +eight_bits skip_ahead() +#line 982 "tangle.web" +{ +eight_bits c; +while(1){ +if(loc>limit&&(get_line()==0))return(255); + *(limit+1)= 35; +while( *loc!=35)loc++; +if(loc<=limit){ +loc++;c= ccode[ *loc]; +#ifdef DEBUG +if(c==248){ +tracing= *loc-48;c= 0; +} +#endif DEBUG +loc++; +if(c!=0|| *(loc-1)=='>')return(c); +} +} +} + +/*:90*//*92:*/ +#line 1012 "tangle.web" + +#line 1013 "tangle.web" +skip_comment() +{ +ASCII c; +if(1){ +get_line(); +return(comment_continues= 0); +}else{ +while(1){ +if(loc>limit) +if(get_line())return(comment_continues= 1); +else{ +err_print("! Input ended in mid-comment"); + +return(comment_continues= 0); +} +c= *(loc++); +/*82:*/ +#line 121 "outtoks.web" + + +/*:82*/ +#line 1029 "tangle.web" + +if(c==35){ +if(ccode[ *loc]==255){ +err_print("! Section name ended in mid-comment");loc--; + +return(comment_continues= 0); +} +else loc++; +} +} +} +} +/*:92*//*95:*/ +#line 1052 "tangle.web" +eight_bits get_next() +#line 1053 "tangle.web" +{ +eight_bits c; +while(1){ +if(loc>limit){ +if(get_line()==0)return(255); +else if(print_where){ +print_where= 0; +/*125:*/ +#line 1586 "tangle.web" + +#line 1587 "tangle.web" +store_two_bytes(53248); +if(changing)id_first= change_file_name; +else id_first= file_name[include_depth]; +id_loc= id_first+strlen(id_first); +if(changing)store_two_bytes((sixteen_bits)change_line); +else store_two_bytes((sixteen_bits)line[include_depth]); +{int a= id_lookup(id_first,id_loc,0)-name_dir;{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+128;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;};} + +/*:125*/ +#line 1060 "tangle.web" +; +} +else return(10); +} +c= *loc; +if(comment_continues){ +skip_comment(); +if(comment_continues||1)return(10); +else continue; +} +/*81:*/ +#line 109 "outtoks.web" + +#line 110 "outtoks.web" +{int len;len= strlen("##"); +if(loc+len<=limit&&!strncmp(loc,"##",len)){ +loc+= len; +skip_comment(); +if(comment_continues||1) +return('\n'); +else continue; +} +} +/*:81*/ +#line 1070 "tangle.web" + +loc++; +if(isdigit(c)||c=='\\'||c=='.')/*97:*/ +#line 1092 "tangle.web" +{ +#line 1093 "tangle.web" +id_first= loc-1; +if( *id_first=='.'&&!isdigit( *loc))goto mistake; +if( *id_first=='\\')while(isdigit( *loc))loc++; +else{ +if( *id_first=='0'){ +if( *loc=='x'|| *loc=='X'){ +loc++;while(isxdigit( *loc))loc++;goto found; +} +} +while(isdigit( *loc))loc++; +if( *loc=='.'){ +loc++; +while(isdigit( *loc))loc++; +} +if( *loc=='e'|| *loc=='E'){ +if( *++loc=='+'|| *loc=='-')loc++; +while(isdigit( *loc))loc++; +} +} +found: +id_loc= loc; +return(3); +} + +/*:97*/ +#line 1072 "tangle.web" + +else if(isalpha(c)||c=='_'||c=='$')/*96:*/ +#line 1084 "tangle.web" +{ +#line 1085 "tangle.web" +id_first= --loc; +while(isalpha( *++loc)||isdigit( *loc)|| *loc=='_'); +if( *loc=='$')while(isdigit( *++loc)|| *loc=='$'); + +id_loc= loc;return(130); +} + +/*:96*/ +#line 1073 "tangle.web" + +else if(c=='\''||c=='\"')/*98:*/ +#line 1122 "tangle.web" +{ +#line 1123 "tangle.web" +ASCII delim= c; + + +if(delim=='\''&&(loc+1>=limit|| +( *loc!='\\'&& *loc!=35&&loc[1]!='\'')|| +( *loc=='\\'&&(loc+2>=limit||loc[2]!='\''))|| +( *loc==35&& +(loc+2>=limit||loc[1]!=35||loc[2]!='\'')) +))goto mistake; +id_first= mod_text+1; +id_loc= mod_text; *++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<=mod_text_end) *id_loc= 10; + +} +if((c= *loc++)==delim){ +if(++id_loc<=mod_text_end) *id_loc= c; +break; +} +if(c=='\\'){ +if(loc>=limit)continue; +if(++id_loc<=mod_text_end) *id_loc= '\\'; +c= *loc++; +} +if(++id_loc<=mod_text_end) *id_loc= c; +} +if(id_loc>=mod_text_end){ +printf("\n! String too long: "); + +fflush(stdout),write(1,mod_text+1,25); +printf("...");history= 2; +} +id_loc++; +return(2); +} + +/*:98*/ +#line 1074 "tangle.web" + +else if(c==35)/*99:*/ +#line 1171 "tangle.web" +{ +#line 1172 "tangle.web" +c= ccode[ *loc++]; +switch(c){ +case 0:continue; +case 250:while((c= skip_ahead())==35); + +if( *(loc-1)!='>')err_print("! Improper @ within control text"); + +continue; +case 254: +cur_module_char= *(loc-1); +/*103:*/ +#line 1221 "tangle.web" +{ +#line 1222 "tangle.web" +ASCII *k; +/*105:*/ +#line 1241 "tangle.web" + +#line 1242 "tangle.web" +k= mod_text; +while(1){ +if(loc>limit&&get_line()==0){ +err_print("! Input ended in section name"); + +loc= buffer+1;break; +} +c= *loc; +/*106:*/ +#line 1265 "tangle.web" + +#line 1266 "tangle.web" +if(c==35){ +c= *(loc+1); +if(c=='>'){ +loc+= 2;break; +} +if(ccode[c]==255){ +err_print("! Section name didn't end");break; + +} + *(++k)= 35;loc++; +} + +/*:106*/ +#line 1250 "tangle.web" +; +loc++;if(k<mod_text_end)k++; +if(c==' '||c==011){ +c= ' ';if( *(k-1)==' ')k--; +} + *k= c; +} +if(k>=mod_text_end){ +printf("\n! Section name too long: "); + +fflush(stdout),write(1,mod_text+1,25); +printf("...");{if(history==0)history= 1;}; +} +if( *k==' '&&k>mod_text)k--; + +/*:105*/ +#line 1223 "tangle.web" +; +if(k-mod_text>3&&strncmp(k-2,"...",3)==0)cur_module= prefix_lookup(mod_text+1,k-3); +else cur_module= mod_lookup(mod_text+1,k); +if(cur_module_char=='('){ +/*66:*/ +#line 749 "tangle.web" + +#line 750 "tangle.web" +{ +if(cur_out_file>output_files){ +for(an_output_file= cur_out_file; +an_output_file<end_output_files;an_output_file++) +if( *an_output_file==cur_module)break; +if(an_output_file==end_output_files) + *--cur_out_file= cur_module; +}else{ +{{printf("\n! Sorry, capacity exceeded: ");err_print("output files");history= 3;wrap_up();};}; +} +} + +/*:66*/ +#line 1228 "tangle.web" + +} +return(254); +} + +/*:103*/ +#line 1182 "tangle.web" +; +case 2:/*107:*/ +#line 1283 "tangle.web" +{ +#line 1284 "tangle.web" +id_first= loc++; *(limit+1)= 35; *(limit+2)= '>'; +while( *loc!=35|| *(loc+1)!='>')loc++; +if(loc>=limit)err_print("! Verbatim string didn't end"); + +id_loc= loc;loc+= 2; +return(2); +} + +/*:107*/ +#line 1183 "tangle.web" +; +#ifdef DEBUG +case 248:tracing= *(loc-1)-'0';continue; +#endif DEBUG +case 249:/*100:*/ +#line 1194 "tangle.web" + +#line 1195 "tangle.web" +id_first= loc; +if( *loc=='\\')loc++; +while( *loc!='\''){ +loc++; +if(loc>limit){ +err_print("! String didn't end");loc= limit-1;break; +} +} +loc++; +return(249); + +/*:100*/ +#line 1187 "tangle.web" +; +case 5:/*101:*/ +#line 1206 "tangle.web" +{ +#line 1207 "tangle.web" +id_first= loc; +while('0'<= *loc&& *loc<'8')loc++; +id_loc= loc; +return(5); +} + +/*:101*/ +#line 1188 "tangle.web" +; +case 6:/*102:*/ +#line 1213 "tangle.web" +{ +#line 1214 "tangle.web" +id_first= loc; +while(isxdigit( *loc))loc++; +id_loc= loc; +return(6); +} + + +/*:102*/ +#line 1189 "tangle.web" +; +default:return(c); +} +} + +/*:99*/ +#line 1075 "tangle.web" + +else if(c==' '||c==011){ +continue; +} +mistake:/*74:*/ +#line 3 "outtoks.web" + +#line 4 "outtoks.web" +if(loc+1<=limit){ +if(strncmp("==",loc-1,2)==0){ +loc+= 1; +return 26; +} +else if(strncmp("&&",loc-1,2)==0){ +loc+= 1; +return 25; +} +else if(strncmp("||",loc-1,2)==0){ +loc+= 1; +return 24; +} +else if(strncmp("<=",loc-1,2)==0){ +loc+= 1; +return 28; +} +else if(strncmp("++",loc-1,2)==0){ +loc+= 1; +return 23; +} +else if(strncmp(">=",loc-1,2)==0){ +loc+= 1; +return 27; +} +else if(strncmp("!=",loc-1,2)==0){ +loc+= 1; +return 29; +} +else if(strncmp(">>",loc-1,2)==0){ +loc+= 1; +return 31; +} +else if(strncmp("--",loc-1,2)==0){ +loc+= 1; +return 22; +} +else if(strncmp("!~",loc-1,2)==0){ +loc+= 1; +return 30; +} +} +/*:74*/ +#line 1079 "tangle.web" + +return(c); +} +} + +/*:95*//*109:*/ +#line 1314 "tangle.web" +scan_repl(t) +#line 1315 "tangle.web" +eight_bits t; +{ +sixteen_bits a; +int set_print_where; +if(t==254){/*125:*/ +#line 1586 "tangle.web" + +#line 1587 "tangle.web" +store_two_bytes(53248); +if(changing)id_first= change_file_name; +else id_first= file_name[include_depth]; +id_loc= id_first+strlen(id_first); +if(changing)store_two_bytes((sixteen_bits)change_line); +else store_two_bytes((sixteen_bits)line[include_depth]); +{int a= id_lookup(id_first,id_loc,0)-name_dir;{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+128;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;};} + +/*:125*/ +#line 1319 "tangle.web" +;} + + +while(1){ +if(t==1){ +print_where= 0; +} +a= get_next(); +if(t==1){ +set_print_where= print_where; +} +switch(a){ +/*124:*/ +#line 1529 "tangle.web" + +#line 1530 "tangle.web" +case 130: +{short n; +if((n= parameter_number(id_first,id_loc))!=0){ +#ifdef TRACE_MACROS +if(tracing>1){ +printf("\nIdentified ");fflush(stdout),write(1,id_first,id_loc-id_first); +printf(" as parameter number %d (%d from back)",n,next_param_name-n+1); +} +#endif TRACE_MACROS +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 7;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= next_param_name-n+1;}; +}else{ +a= id_lookup(id_first,id_loc,0)-name_dir; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+128;};{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;}; +} +} +break; +case 254:if(t!=254)goto done; +else{ +/*126:*/ +#line 1596 "tangle.web" +{ +#line 1597 "tangle.web" +ASCII *try_loc= loc; +while( *try_loc==' '&&try_loc<limit)try_loc++; +if( *try_loc=='+'&&try_loc<limit)try_loc++; +while( *try_loc==' '&&try_loc<limit)try_loc++; +if( *try_loc=='=')err_print("! Nested named modules. Missing @?"); + +} + +/*:126*/ +#line 1549 "tangle.web" +; +a= cur_module-name_dir; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+168;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;}; +/*125:*/ +#line 1586 "tangle.web" + +#line 1587 "tangle.web" +store_two_bytes(53248); +if(changing)id_first= change_file_name; +else id_first= file_name[include_depth]; +id_loc= id_first+strlen(id_first); +if(changing)store_two_bytes((sixteen_bits)change_line); +else store_two_bytes((sixteen_bits)line[include_depth]); +{int a= id_lookup(id_first,id_loc,0)-name_dir;{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+128;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;};} + +/*:125*/ +#line 1553 "tangle.web" +;break; +} +case 3:case 2: +/*127:*/ +#line 1605 "tangle.web" + +#line 1606 "tangle.web" +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;}; +while(id_first<id_loc){ +if( *id_first==35)id_first++; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= *id_first++;}; +} +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;};break; + +/*:127*/ +#line 1556 "tangle.web" +; +case 249: +/*128:*/ +#line 1613 "tangle.web" +{ +#line 1614 "tangle.web" +int c; +if( *id_first==35){ +c= xchr[ *id_first++]; +if( *id_first!=35)err_print("! Double @ within string"); +} +else if( *id_first=='\\'){ +id_first++; +switch( *id_first){ +case't':c= 9;break; +case'n':c= 10;break; +case'b':c= 8;break; +case'0':c= 0;break; +case'\\':c= 92;break; +default:err_print("! Unrecognized escape sequence"); +} +} +else c= xchr[ *id_first]; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; + + +app_decimal((long)c); +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +} +break; + +/*:128*/ +#line 1558 "tangle.web" +; +case 5: +/*129:*/ +#line 1640 "tangle.web" +{ +#line 1641 "tangle.web" +long sum= 0; +while(id_first<id_loc){ +sum= 8 *sum+ *id_first++-'0'; +if(sum>67108864)err_print("! Octal constant exceeds @\"04000000"); +} +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +app_decimal(sum); +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +} + +/*:129*/ +#line 1560 "tangle.web" +;break; +case 6: +/*130:*/ +#line 1651 "tangle.web" +{ +#line 1652 "tangle.web" +long sum= 0; +while(id_first<id_loc){ +sum= 16 *sum+ +(isdigit( *id_first) +? *id_first-'0' +:isupper( *id_first) +? *id_first-'A'+10 +: *id_first-'a'+10 +); +id_first++; +if(sum>67108864)err_print("! Hex constant exceeds @\"04000000"); +} +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +app_decimal(sum); +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +} + +/*:130*/ +#line 1562 "tangle.web" +;break; +case 10: +#ifdef NEWLINES_IN_MACROS +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;}; +#else +if(t==1)continue; +else{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;}; +#endif NEWLINES_IN_MACROS +break; +case 252:case 251:case 253: +if(t!=254)goto done; +else{ +err_print("! @d, @f and @u are ignored in C text");continue; + +} +case 255:goto done; + +/*:124*/ +#line 1334 "tangle.web" + +default:{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;}; +} +} +done:next_control= (eight_bits)a; +if(text_ptr>text_info_end){{printf("\n! Sorry, capacity exceeded: ");err_print("text");history= 3;wrap_up();};}; +if(t==1){ +/*110:*/ +#line 1358 "tangle.web" + +#line 1359 "tangle.web" +tok_ptr-= 2; +while( *tok_ptr<128&& *(tok_ptr+1)==10)tok_ptr--; +tok_ptr+= 2; + +/*:110*/ +#line 1341 "tangle.web" +; +} +cur_text= text_ptr;(++text_ptr)->tok_start= tok_ptr; +print_where= set_print_where; +} + +/*:109*//*116:*/ +#line 1408 "tangle.web" + +#line 1409 "tangle.web" +int parameter_number(first,loc) +ASCII *first, *loc; +{ +ASCII *f, *p; +int n; +for(n= 0;n<next_param_name;n++){ +if(loc-first==param_names[n+1]-param_names[n]){ + +for(f= first,p= param_names[n];f<loc;) +if( *f++!= *p++)goto nomatch; +return n+1; +} +nomatch:continue; +} +return 0; +} + + +/*:116*//*131:*/ +#line 1670 "tangle.web" + +#line 1671 "tangle.web" +app_decimal(c) +long c; +{long power; +if(c==0){{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= '0';};return;} +if(c<0){{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= '-';};c= -c;} +for(power= 1;c>=power;power *= 10); + +for(power/= 10;power>=1;power/= 10){ +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= '0'+c/power;}; +c%= power; + +} +} + + + +/*:131*//*133:*/ +#line 1697 "tangle.web" +scan_module() +#line 1698 "tangle.web" +{ +name_pointer p; +text_pointer q; +sixteen_bits a; +module_count++; +if( *(loc-1)=='*') +printf("*%d",module_count);fflush(stdout); +/*134:*/ +#line 1714 "tangle.web" + +next_control= 0; +while(1){ +done_scanning: +while(next_control<=251) +if((next_control= skip_ahead())==254){ + +loc-= 2;next_control= get_next(); +} +if(next_control!=252)break; +/*117:*/ +#line 1433 "tangle.web" + +#line 1434 "tangle.web" +/*123:*/ +#line 1521 "tangle.web" + +#line 1522 "tangle.web" +while((next_control= get_next())==10); + +/*:123*/ +#line 1434 "tangle.web" + +/*121:*/ +#line 1484 "tangle.web" + +#line 1485 "tangle.web" +if(next_control!=130){ +err_print("! Macro name must be an identifier"); + +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1488 "tangle.web" +; +}else{ +p= id_lookup(id_first,id_loc,1); +if(p->dummy.Ilk!=1){ +#ifdef WARN_USE_BEFORE_DEF +printf("\n! Warning: macro name "); +fflush(stdout),write(1,(p)->byte_start,(((p)+1)->byte_start-((p))->byte_start)); +printf(" was used before it was defined"); +{if(history==0)history= 1;}; +#endif WARN_USE_BEFORE_DEF +p->dummy.Ilk= 1; +}else if(p+1!=name_ptr){ +err_print("! Macro name is multiply defined: "); +} +} + +/*:121*/ +#line 1436 "tangle.web" +; +/*120:*/ +#line 1469 "tangle.web" + +#line 1470 "tangle.web" +/*123:*/ +#line 1521 "tangle.web" + +#line 1522 "tangle.web" +while((next_control= get_next())==10); + +/*:123*/ +#line 1470 "tangle.web" + +if(next_control==40){ +do{ +/*122:*/ +#line 1504 "tangle.web" + +#line 1505 "tangle.web" +/*123:*/ +#line 1521 "tangle.web" + +#line 1522 "tangle.web" +while((next_control= get_next())==10); + +/*:123*/ +#line 1505 "tangle.web" +; +if(next_control!=130){ +err_print("! Macro parameter name not an identifier"); + +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1509 "tangle.web" +; +}else{ +if(parameter_number(id_first,id_loc)!=0){ +err_print("! Duplicate parameters in macro definition"); + +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1514 "tangle.web" +; +}else{ +/*114:*/ +#line 1387 "tangle.web" + +#line 1388 "tangle.web" +/*115:*/ +#line 1393 "tangle.web" + +#line 1394 "tangle.web" +if(next_param_name==32) +{{printf("\n! Sorry, capacity exceeded: ");err_print("parameter names");history= 3;wrap_up();};}; +if(id_loc-id_first> +param_name_texts_end-next_param_name_text) +{{printf("\n! Sorry, capacity exceeded: ");err_print("parameter name texts");history= 3;wrap_up();};}; + + +/*:115*/ +#line 1388 "tangle.web" +; +while(id_first<id_loc) + *next_param_name_text++= *id_first++; +param_names[++next_param_name]= next_param_name_text; + +/*:114*/ +#line 1516 "tangle.web" +; +} +} + + +/*:122*/ +#line 1473 "tangle.web" +; +/*123:*/ +#line 1521 "tangle.web" + +#line 1522 "tangle.web" +while((next_control= get_next())==10); + +/*:123*/ +#line 1474 "tangle.web" + +}while(next_control==44); +if(next_control!=41){ +err_print("! Macro parameter list must end with )"); +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1478 "tangle.web" +; +} +next_control= get_next(); +} + + +/*:120*/ +#line 1439 "tangle.web" +; +if(next_control!=61){ +err_print("! You must put an = sign before the macro replacement text"); +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1442 "tangle.web" +; +} +/*118:*/ +#line 1451 "tangle.web" + +#line 1452 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>1){ +printf("\nScanning definition of macro ");fflush(stdout),write(1,(p)->byte_start,(((p)+1)->byte_start-((p))->byte_start)); +} +#endif TRACE_MACROS + +/*:118*/ +#line 1444 "tangle.web" +; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= next_param_name;}; +scan_repl(1); +p->equiv_or_xref= (ASCII *)cur_text; +/*119:*/ +#line 1458 "tangle.web" + +#line 1459 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf("\nMacro ");fflush(stdout),write(1,(p)->byte_start,(((p)+1)->byte_start-((p))->byte_start)); +printf("'s replacement text is in text_info[%d]",cur_text-text_info); +} +#endif TRACE_MACROS + + +/*:119*/ +#line 1448 "tangle.web" +; +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1449 "tangle.web" +; + +/*:117*/ +#line 1724 "tangle.web" +; +cur_text->text_link= 0; +} + +/*:134*/ +#line 1705 "tangle.web" +; +/*136:*/ +#line 1738 "tangle.web" + +#line 1739 "tangle.web" +switch(next_control){ +case 253:p= name_dir;break; +case 254:p= cur_module; +/*137:*/ +#line 1750 "tangle.web" + +#line 1751 "tangle.web" +while((next_control= get_next())=='+'); +if(next_control!='='){ +err_print("! C text flushed, = sign is missing"); + +while((next_control= skip_ahead())!=255); +return; +} + +/*:137*/ +#line 1742 "tangle.web" +; +break; +default:return; +} +/*138:*/ +#line 1759 "tangle.web" + +#line 1760 "tangle.web" +store_two_bytes((sixteen_bits)(53248+module_count)); + +/*:138*/ +#line 1746 "tangle.web" +; +scan_repl(254); +/*139:*/ +#line 1762 "tangle.web" + +#line 1763 "tangle.web" +if(p==name_dir||p==0){ +(last_unnamed)->text_link= cur_text-text_info;last_unnamed= cur_text; +} +else if(p->equiv_or_xref==(ASCII *)text_info)p->equiv_or_xref= (ASCII *)cur_text; + +else{ +q= (text_pointer)p->equiv_or_xref; +while(q->text_link<2000)q= q->text_link+text_info; +q->text_link= cur_text-text_info; +} +cur_text->text_link= 2000; + +/*:139*/ +#line 1748 "tangle.web" +; + +/*:136*/ +#line 1706 "tangle.web" +; +} + +/*:133*//*140:*/ +#line 1775 "tangle.web" +phase_one(){ +#line 1776 "tangle.web" +phase= 1; +module_count= 0; +reset_input(); +while((next_control= skip_ahead())!=255); +while(!input_has_ended)scan_module(); +check_complete(); +phase= 2; +} + +/*:140*//*141:*/ +#line 1785 "tangle.web" +print_stats(){ +#line 1786 "tangle.web" +printf("\nMemory usage statistics:\n"); +printf("%d names (out of %d)\n",name_ptr-name_dir,4000); +printf("%d replacement texts (out of %d)\n",text_ptr-text_info,2000); +printf("%d bytes (out of %d)\n",byte_ptr-byte_mem,90000); +printf("%d tokens (out of %d)\n",tok_ptr-tok_mem,150000); +} + +/*:141*/ diff --git a/web/spiderweb/src/big-web.ch b/web/spiderweb/src/big-web.ch new file mode 100644 index 0000000000..6dcf6269d0 --- /dev/null +++ b/web/spiderweb/src/big-web.ch @@ -0,0 +1,59 @@ +From oravax!fred@wrath.cs.cornell.edu Thu Feb 9 18:05:48 1989 +Received: from princeton.Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.68) + id AA25210; Thu, 9 Feb 89 18:05:46 EST +Received: from CU-ARPA.CS.CORNELL.EDU by Princeton.EDU (5.58+++/2.5) + id AA03857; Thu, 9 Feb 89 18:04:48 EST +Received: from WRATH.CS.CORNELL.EDU by cu-arpa.cs.cornell.edu (5.61/1.91d) + id AA08274; Thu, 9 Feb 89 18:04:18 -0500 +Received: by wrath.cs.cornell.edu (5.61/1.91d) + id AA17731; Thu, 9 Feb 89 18:04:14 -0500 +Received: by oravax.UUCP (5.51/5.17) + id AA08548; Thu, 9 Feb 89 17:43:00 EST +Date: Thu, 9 Feb 89 17:43:00 EST +From: oravax!fred@wrath.cs.cornell.edu (Charles Mills) +Message-Id: <8902092243.AA08548@oravax.UUCP> +To: nr@Princeton.EDU +Subject: Re: tangle and weave +Status: R + +The changes (just like those of stangle which were made in, if I recall +aright, November) were actually made with a .ch file, big.ch: + +big.ch: +@x +@d max_refs = 20000 /* number of cross-references; must be less than 65536 */ +@y +@d max_refs = 40000 /* number of cross-references; must be less than 65536 */ +@z +@x +@d max_toks = 20000 /* number of symbols in \cee\ texts being parsed; +@y +@d max_toks = 40000 /* number of symbols in \cee\ texts being parsed; +@z +@x +@d max_texts = 2000 /* number of phrases in \cee\ texts being parsed; +@y +@d max_texts = 4000 /* number of phrases in \cee\ texts being parsed; +@z +@x +@d max_scraps = 1000 /* number of tokens in \cee\ texts being parsed */ +@y +@d max_scraps = 1500 /* number of tokens in \cee\ texts being parsed */ +@z +@x +@d stack_size = 400 /* number of simultaneous output levels */ +@y +@d stack_size = 800 /* number of simultaneous output levels */ +@z + +make: +/bin/make -f ../master/WebMakefile \ + THETANGLE=stangle THEWEAVE=sweave SPIDER=s.spider CHANGES=big.ch$* + +Your master source files have not been touched, and even your +.../ssl/weave.web, though it was regenerated, came out the same +as before. No anxiety on this score was in order at this end, and +if any had been expressed to me I'd have squelched it. + +fred + diff --git a/web/spiderweb/src/c++/c++.spider b/web/spiderweb/src/c++/c++.spider new file mode 100644 index 0000000000..b368450540 --- /dev/null +++ b/web/spiderweb/src/c++/c++.spider @@ -0,0 +1,368 @@ +# +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# modified for c++ by Ed Kademan <kademan@stat.wisc.edu> +# Thu Aug 10 12:47:13 CDT 1989 +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language C++ extension cc + +at_sign @ + +comment begin <"//"> end newline + +default translation <*> mathness yes + +token identifier category simp mathness yes +token number category math mathness yes +token newline category newline mathness maybe translation <> +token pseudo_semi category semi mathness maybe translation <"\\relax"> + +module definition stmt use math + +token + category unorbinop +token - category unorbinop +token * category unorbinop translation <"{*}"> +token / category dot +token < category less +token > category greater +token = category equals translation <"\\leftarrow"> tangleto <"="-space> +token . category dot +token ~ category unop translation <"\\TI"> +token & category unorbinop translation <"\\amp"> +token ^ translation <"\\^"> category binop +token | category binop +token ? translation <"\\?"> category question +token % translation <"\\%"> category binop +token # translation <"\\#"> category sharp +token ! category unop translation <"\\neg"> +token \ category backslash translation <"\\backslash"> +token ( category open +token ) category close +token [ category open +token ] category close +token { translation <"\\{"-indent> category lbrace +token } translation <"\\}"> category rbrace +token , category comma translation <",\\;"> +token ; category semi +token : category colon +token :: category coloncolon translation <"\\CC"> +token ++ category unop translation <"\\PP"> +token -- category unop translation <"\\MM"> +token != translation <"\\I"> category binop +token <= translation <"\\L"> category binop +token >= translation <"\\G"> category binop +token == translation <"\\S"> category binop +token && translation <"\\W"> category binop +token || translation <"\\V"> category binop +token -> translation <"\\MG"> category binop +token >> translation <"\\GG"> category binop +token << translation <"\\LL"> category binop + +macros begin +\def\CC{\mathrel{:{:}}} +\def\CCE{\mathrel{:{:}=}} +\def\FE{\mathrel{/=}} +\def\PP{\mathord{++}} +\def\PE{\mathrel{+=}} +\def\MM{\mathord{--}} +\def\ME{\mathrel{-=}} +\def\MG{\mathrel{\to}} +\def\GG{\mathrel{>\!>}} +\def\LL{\mathrel{<\!<}} +\def\TE{\mathrel{\ast=}} +\def\CE{\mathrel{\%=}} +\def\HE{\mathrel{\uparrow=}} +\def\AE{\mathrel{\amp=}} +\def\OE{\mathrel{|=}} +\let\openbraces=\{ +\let\closebraces=\} +\def\{{\ifmmode\openbraces\else$\openbraces$\fi} +\def\}{\ifmmode\closebraces\else$\closebraces$\fi} +\def\?{\mathrel?} +\def\s{\ } +\def\setfilefonts{\let\\=\. \let\|=\. \let\&=\.} +macros end + +default translation <*-"\\"-space> + +ilk case_like category case +ilk do_like category do +ilk else_like category else +ilk enum_like category enum +ilk for_like category for +ilk if_like category if +ilk int_like category decl_head translation <*> +ilk new_like category new +ilk sizeof_like category sizeof +ilk struct_like category struct +ilk switch_like category switch +ilk this_like category simp +ilk typedef_like category typedef + +default translation <*> + +reserved asm ilk sizeof_like +reserved auto ilk int_like +reserved break ilk case_like +reserved case ilk case_like +reserved char ilk int_like +reserved class ilk struct_like +reserved const ilk int_like +reserved continue ilk case_like +reserved default ilk case_like +reserved delete ilk this_like +reserved do ilk do_like +reserved double ilk int_like +reserved else ilk else_like +reserved enum ilk enum_like +reserved extern ilk int_like +reserved float ilk int_like +reserved for ilk for_like +reserved friend ilk int_like +reserved goto ilk case_like +reserved if ilk if_like +reserved inline ilk int_like +reserved int ilk int_like +reserved long ilk int_like +reserved new ilk new_like +reserved operator ilk this_like +reserved overload ilk int_like +reserved private ilk case_like +reserved protected ilk case_like +reserved public ilk case_like +reserved register ilk int_like +reserved return ilk case_like +reserved short ilk int_like +reserved sizeof ilk sizeof_like +reserved static ilk int_like +reserved struct ilk struct_like +reserved switch ilk switch_like +reserved this ilk this_like +reserved typedef ilk typedef_like +reserved union ilk struct_like +reserved unsigned ilk int_like +reserved virtual ilk int_like +reserved void ilk int_like +reserved while ilk for_like + +# we indulge in a trick to avoid treating +# ASCII (*fp)(); +# as a statement (function call). We use instead +# ASCII ===> (*fp)(); +token ===> translation <"\\relax"> tangleto <space> category decl_head + + +# +# There appears to be a bug in spidery weave. If the very last line of a +# web file ends with a preprocessor directive weave fails to print it out. +# The first line below fixes this problem. +preproc [ ignore_scrap ] --> preproc newline +? ignore_scrap --> #1 +# dropped, because we've overflowed yacc! +#### DON'T DO THIS! it makes it impossible to add translation on the left +#### ignore_scrap ? --> #2 + + +# because of declarations, we have to be very careful about converting +# simp to math + +(math|simp) unop --> math +math (binop|unorbinop) (math|simp) --> math +math comma <opt-9> (math|simp) --> math +# we're not allowed math simp --> statement because math simp could be fn_decl +math math --> math +(math|simp) semi --> stmt +# so to hack the omission above, we include (usually a cast) +math <"\\"-space> stmt --> stmt + +(open|simpopen|question|unop|unorbinop|case) [ simp ] --> (open|simpopen|question|unop|unorbinop|case) math +[ simp ] binop --> math binop +# old: +# [ simp ] equals --> math equals +# math [ equals ] --> math binop + +simp* colon --> tag + +# can't have simp open --> open because that causes ( to eat all id's to its left. +simp open --> simpopen + +(open|simpopen) math close --> math +(open|simpopen) <"\\,"> close --> math +# following needed for for statements +open stmt <"\\"-space> --> open + +(new|simp|decl_head) <"\\"-space> decl_head --> decl_head +[ simp ] math (equals|comma|semi) --> decl_head math (equals|comma|semi) +[ (decl_head|simp) simp ] (simp|math) --> decl_head (simp|math) +(simp|decl_head) <"\\"-space> (simp|math)* comma --> decl_head +[ (simp|decl_head) <"\\"-space> (simp|math)* ] semi --> math semi +(simp|decl_head) <"\\"-space> (simp|math)* equals --> decl_equals +(open|simpopen) [ (simp|decl_head) <"\\"-space> (simp|math)* equals ] --> (open|simpopen) decl_equals +decl_equals math comma --> decl_head +[ decl_equals math ] semi --> math semi +decl_equals [ simp ] --> decl_equals math + +# here we try to deal with casts and argument lists, e.g. +# (ASCII *) malloc(sizeof (ASCII *)); +# char *malloc(int); + +# If the type is predefined, we know we have a cast +(open|simpopen) decl_head close --> cast +(open|simpopen) [ decl_head <"\\"-space> simp ] --> (open|simpopen) decl_head +(open|simpopen) [ decl_head (unorbinop|math) ] --> (open|simpopen) decl_head +(open|simpopen) decl_head comma --> arglist +arglist (decl_head|unorbinop|math) --> arglist +arglist <"\\"-space> simp --> arglist +arglist comma --> arglist +arglist close --> math + +# and here are some common cases of casts with non-predefined types +# for other cases you'll have to use "declares" +(open|simpopen) math <"\\"-space> unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop unorbinop unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop close --> cast +(open|simpopen) math <"\\"-space> unorbinop unorbinop close --> cast +(open|simpopen) math <"\\"-space> unorbinop unorbinop unorbinop close --> cast + +# the math here seems to be a cast. We don't convert to cast because it looks +# too much like a cycle +(open|simpopen) [ math <"\\"-space> simp ] --> (open|simpopen) math + +# Here is the destiny of casts +cast <"\\"-space> (math|simp) --> math +cast (newline|ignore_scrap) --> cast +cast --> math + +question math colon --> binop + +unop math --> math +<"{"> unorbinop <"}"> math --> math +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +sizeof (math|simp) --> math + +struct simp* <"\\"-space> lbrace --> structbrace +struct lbrace --> structbrace +struct (simp|decl_head)* colon (simp|decl_head) lbrace --> structbrace +struct (simp|decl_head)* colon case (simp|decl_head) lbrace --> structbrace +structbrace [ simp ] --> structbrace decl_head +structbrace <force> stmt --> structbrace +structbrace <outdent-force> rbrace --> struct_head +structbrace <outdent-force> tagged_stmt --> structbrace +[ struct_head ] simp --> decl_head simp +# some people say e.g. struct blah {...}; is this K&R? +[ struct_head ] semi --> math semi +struct [ simp (newline|ignore_scrap) ] --> struct simp +struct simp --> decl_head +decl_head <"\\"-space> struct --> struct + +# enumeration types are like structures and unions, but they have math +# instead of many decls... +enum simp* <"\\"-space> lbrace --> enumbrace +enum lbrace --> enumbrace +enumbrace math rbrace <outdent> --> enum_head +[ enum_head ] simp --> decl_head simp +[ enum_head ] semi --> math semi +enum [ simp (newline|ignore_scrap) ] --> enum simp +enum simp --> decl_head +decl_head <"\\"-space> enum --> enum + +typedef [ simp ] --> typedef decl_head +typedef stmt --> stmt + +[ math* <indent> ] (lbrace|decl_head|stmt) --> fn_decl (lbrace|decl_head|stmt) +[ (simp|decl_head) <"\\"-space> math* <indent> ] (lbrace|decl_head|stmt) --> fn_decl (lbrace|decl_head|stmt) +# The following statment will always have braces and never be tagged +fn_decl <outdent-force> stmt --> stmt +math colon fn_decl --> fn_decl + +(open|simpopen) [ stmt <"\\"-space> stmt ] --> (open|simpopen) stmt + +lbrace <outdent-force> rbrace --> stmt +lbrace <force> stmt --> lbrace +lbrace <outdent-force> tagged_stmt --> lbrace +lbrace (math|simp) <outdent> rbrace --> math + +# if math can be followed by a brace, or no. +# ifmath and ifbrace can have an attached else or else if clause +# else, for, and while are formatted like if, but can't have an +# attached else clause, so we use formath and forbrace + +if math --> ifmath +ifmath <"\\"-space> lbrace --> ifbrace +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> tagged_stmt --> ifbrace +ifbrace [ rbrace (newline|ignore_scrap) ] --> ifbrace rbrace +ifbrace rbrace [ else (newline|ignore_scrap) ] --> ifbrace rbrace else +ifbrace <outdent-force> rbrace <"\\"-space> else if --> if +ifbrace <outdent-force> rbrace <"\\"-space> else lbrace --> forbrace +ifbrace <outdent-force> rbrace <"\\"-space> else --> formath +ifbrace <outdent-force> rbrace --> stmt + +# Assume simple statements attached to if will never be tagged + +ifmath [ stmt (newline|ignore_scrap) ] --> ifmath stmt +ifmath stmt [ else (newline|ignore_scrap) ] --> ifmath stmt else +ifmath <indent-force> stmt <outdent-force> else if --> if +ifmath <indent-force> stmt <outdent-force> else lbrace --> forbrace +ifmath <indent-force> stmt <outdent-force> else --> formath +ifmath <indent-force> stmt <outdent> --> stmt + +for math --> formath +formath <"\\"-space> lbrace --> forbrace +forbrace <force> stmt --> forbrace +forbrace <outdent-force> tagged_stmt --> forbrace +forbrace <outdent-force> rbrace --> stmt +formath <indent-force> stmt <outdent> --> stmt + +# we need an extra indent for switch, becuase the cases will be backed out +switch math lbrace <indent> --> switchbrace +switchbrace <outdent-force> tagged_stmt --> switchbrace +# This next should never happen +switchbrace <force> stmt --> switchbrace +switchbrace <outdent-outdent-force> rbrace --> stmt + + + +# handle do-while (while has category for) +do lbrace --> dobrace +dobrace <force> stmt --> dobrace +dobrace <outdent-force> tagged_stmt --> dobrace +dobrace rbrace for --> math +do <indent-force> stmt <outdent-force> for --> math + +case semi --> stmt +case math semi --> stmt +case colon --> tag +case math colon --> tag +tag <force> tag --> tag +tag <indent-force> stmt --> tagged_stmt + +stmt <force> stmt --> stmt +stmt <outdent-force> tagged_stmt --> stmt +semi --> stmt + +# control sequence \8 puts things on the left margin +<force-"\\8"> sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +preproc backslash <force-"\\8\\hskip1em"-space> newline --> preproc +preproc <force-outdent> newline --> ignore_scrap +preproc !(less|lesssimp|backslash|newline) --> preproc +newline --> ignore_scrap + +[ less (simp|decl_head) ] (dot|greater) --> lesssimp (dot|greater) +lesssimp dot simp --> lesssimp +<"{\\setfilefonts"-space> lesssimp greater <"}"> --> math +lesssimp --> unop +less --> binop +greater --> binop +dot --> binop + + +(decl_head|simp) coloncolon (decl_head|simp) --> simp +math coloncolon (decl_head|simp) --> math +decl_head stmt --> stmt + +# The following handles "~" for destructors. +coloncolon <"\\,"> unop --> coloncolon +unop decl_head --> decl_head diff --git a/web/spiderweb/src/c++/make b/web/spiderweb/src/c++/make new file mode 100644 index 0000000000..bc9e63f905 --- /dev/null +++ b/web/spiderweb/src/c++/make @@ -0,0 +1,3 @@ +#!/bin/csh -f +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=c++tangle THEWEAVE=c++weave SPIDER=c++.spider $* diff --git a/web/spiderweb/src/c/c.spider b/web/spiderweb/src/c/c.spider new file mode 100644 index 0000000000..6aac7f3ec9 --- /dev/null +++ b/web/spiderweb/src/c/c.spider @@ -0,0 +1,350 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language C extension c + +at_sign @ + +comment begin <"/*"> end <"*/"> + +default translation <*> mathness yes + +token identifier category simp mathness yes +token number category math mathness yes +token newline category newline mathness maybe translation <> +token pseudo_semi category semi mathness maybe translation <"\\relax"> + +module definition stmt use math + +token + category unorbinop +token - category unorbinop +token * category unorbinop translation <"{*}"> tangleto <space-"*"> +# avoid inadvertant /* +token / category dot +token < category less translation <> +token > category greater translation <> +token = category equals translation <"\\leftarrow"> tangleto <"="-space> +# avoid inadvertant =- +token . category dot +token ~ category unop translation <"\\TI"> +token & category unorbinop translation <"\\amp"> +token ^ translation <"\\^"> category binop +token | category binop +token ? translation <"\\?"> category question +token % translation <"\\%"> category binop +token # translation <"\\#"> category sharp +token ! category unop translation <"\\neg"> +token \ category backslash translation <"\\backslash"> +token ( category open +token ) category close +token [ category open +token ] category close +token { translation <"\\{"-indent> category lbrace +token } translation <"\\}"> category rbrace +token , category comma translation <",\\;"> +token ; category semi +token : category colon +token ++ category unop translation <"\\PP"> +token -- category unop translation <"\\MM"> +token != translation <"\\I"> category binop +token <= translation <"\\L"> category binop +token >= translation <"\\G"> category binop +token == translation <"\\S"> category binop +token && translation <"\\W"> category binop +token || translation <"\\V"> category binop +token -> translation <"\\MG"> category binop +token >> translation <"\\GG"> category binop +token << translation <"\\LL"> category binop + +macros begin +\def\CC{\mathrel{:{:}}} +\def\CCE{\mathrel{:{:}=}} +\def\FE{\mathrel{/=}} +\def\PP{\mathord{++}} +\def\PE{\mathrel{+=}} +\def\MM{\mathord{--}} +\def\ME{\mathrel{-=}} +\def\MG{\mathrel{\to}} +\def\GG{\mathrel{>\!>}} +\def\LL{\mathrel{<\!<}} +\def\TE{\mathrel{\ast=}} +\def\CE{\mathrel{\%=}} +\def\HE{\mathrel{\uparrow=}} +\def\AE{\mathrel{\amp=}} +\def\OE{\mathrel{|=}} +\let\openbraces=\{ +\let\closebraces=\} +\def\{{\ifmmode\openbraces\else$\openbraces$\fi} +\def\}{\ifmmode\closebraces\else$\closebraces$\fi} +\def\?{\mathrel?} +\def\s{\ } +macros end + +default translation <*-"\\"-space> + +ilk case_like category case +ilk int_like category decl_head translation <*> +ilk else_like category else +ilk enum_like category enum +ilk if_like category if +ilk for_like category for +ilk do_like category do +ilk sizeof_like category sizeof +ilk struct_like category struct +ilk switch_like category switch +ilk typedef_like category typedef + +default translation <*> + +reserved auto ilk int_like +reserved break ilk case_like +reserved case ilk case_like +reserved char ilk int_like +reserved continue ilk case_like +reserved default ilk case_like +reserved do ilk do_like +reserved double ilk int_like +reserved else ilk else_like +reserved enum ilk enum_like +reserved extern ilk int_like +reserved float ilk int_like +reserved for ilk for_like +reserved goto ilk case_like +reserved if ilk if_like +reserved int ilk int_like +reserved long ilk int_like +reserved register ilk int_like +reserved return ilk case_like +reserved short ilk int_like +reserved sizeof ilk sizeof_like +reserved static ilk int_like +reserved struct ilk struct_like +reserved switch ilk switch_like +reserved typedef ilk typedef_like +reserved union ilk struct_like +reserved unsigned ilk int_like +reserved void ilk int_like +reserved while ilk for_like + +# we indulge in a trick to avoid treating +# ASCII (*fp)(); +# as a statement (function call). We use instead +# ASCII ===> (*fp)(); +token ===> translation <"\\relax"> tangleto <space> category decl_head + + +# +? ignore_scrap --> #1 +# dropped, because we've overflowed yacc! +#### DON'T DO THIS! it makes it impossible to add translation on the left +#### ignore_scrap ? --> #2 + + +# because of declarations, we have to be very careful about converting +# simp to math + +(math|simp) unop --> math +math (binop|unorbinop) (math|simp) --> math +math comma <opt-9> (math|simp) --> math +# we're not allowed math simp --> statement because math simp could be fn_decl +math math --> math +(math|simp) semi --> stmt +# so to hack the omission above, we include (usually a cast) +math <"\\"-space> stmt --> stmt + +(open|simpopen|question|unop|unorbinop|case) [ simp ] --> (open|simpopen|question|unop|unorbinop|case) math +[ simp ] binop --> math binop +# old: +# [ simp ] equals --> math equals +# math [ equals ] --> math binop + +simp* colon --> tag + +# can't have simp open --> open because that causes ( to eat all id's to its left. +simp open --> simpopen + +(open|simpopen) math close --> math +(open|simpopen) <"\\,"> close --> math +# following needed for for statements +open stmt <"\\"-space> --> open + +# here we try to deal with casts and argument lists, e.g. +# (ASCII *) malloc(sizeof (ASCII *)); +# char *malloc(int); + +# If the type is predefined, we know we have a cast +(open|simpopen) decl_head close --> cast +(open|simpopen) [ decl_head (unorbinop|math|simp) ] --> (open|simpopen) decl_head +(open|simpopen) decl_head comma --> arglist +arglist (decl_head|unorbinop|math) --> arglist +arglist close --> math + +# and here are some common cases of casts with non-predefined types +# for other cases you'll have to use "declares" +(open|simpopen) math <"\\"-space> unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop unorbinop unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop close --> cast +(open|simpopen) math <"\\"-space> unorbinop unorbinop close --> cast +(open|simpopen) math <"\\"-space> unorbinop unorbinop unorbinop close --> cast + +# the math here seems to be a cast. We don't convert to cast because it looks +# too much like a cycle +(open|simpopen) [ math <"\\"-space> simp ] --> (open|simpopen) math + +# Here is the destiny of casts +cast <"\\"-space> (math|simp) --> math +cast (newline|ignore_scrap) --> cast +cast --> math + + + +question math colon --> binop + +unop math --> math +<"{"> unorbinop <"}"> math --> math +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +sizeof (math|simp) --> math + +(simp|decl_head) <"\\"-space> decl_head --> decl_head +[ simp ] math (equals|comma|semi) --> decl_head math (equals|comma|semi) +[ (decl_head|simp) simp ] (simp|math) --> decl_head (simp|math) +(simp|decl_head) <"\\"-space> (simp|math)* comma --> decl_head +(simp|decl_head) <"\\"-space> (simp|math)* semi --> decl +(simp|decl_head) <"\\"-space> (simp|math)* equals --> decl_equals +decl_equals math comma --> decl_head +decl_equals math semi --> decl +decl_equals [ simp ] --> decl_equals math + +struct simp* <"\\"-space> lbrace --> structbrace +struct lbrace --> structbrace +structbrace [ simp ] --> structbrace decl_head +structbrace <force> decl --> structbrace +structbrace <outdent-force> rbrace --> struct_head +[ struct_head ] simp --> decl_head simp +# some people say e.g. struct blah {...}; is this K&R? +struct_head semi --> decl +struct [ simp (newline|ignore_scrap) ] --> struct simp +struct simp --> decl_head +decl_head <"\\"-space> struct --> struct + +# enumeration types are like structures and unions, but they have math +# instead of many decls... +enum simp* <"\\"-space> lbrace --> enumbrace +enum lbrace --> enumbrace +enumbrace math rbrace <outdent> --> enum_head +[ enum_head ] simp --> decl_head simp +enum_head semi --> decl +enum [ simp (newline|ignore_scrap) ] --> enum simp +enum simp --> decl_head +decl_head <"\\"-space> enum --> enum + +typedef [ simp ] --> typedef decl_head +typedef decl --> decl + + + + +[ math* <indent> ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +[ (simp|decl_head) <"\\"-space> math* <indent> ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +fn_decl <force> decl --> fn_decl +# The following statment will always have braces and never be tagged +fn_decl <outdent-force> stmt --> function +# include stmt here to cover module definition +(stmt|decl|function) <big_force> function --> function +function <big_force> decl --> decl + +(stmt|decl) <force> decl --> decl +decl <big_force> stmt --> stmt +decl <outdent-big_force> tagged_stmt --> stmt + + +lbrace <outdent-force> rbrace --> stmt +lbrace <force> stmt --> lbrace +lbrace <outdent-force> tagged_stmt --> lbrace +lbrace (math|simp) <outdent> rbrace --> math + +# if math can be followed by a brace, or no. +# ifmath and ifbrace can have an attached else or else if clause +# else, for, and while are formatted like if, but can't have an +# attached else clause, so we use formath and forbrace + +if math --> ifmath +ifmath <"\\"-space> lbrace --> ifbrace +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> tagged_stmt --> ifbrace +ifbrace [ rbrace (newline|ignore_scrap) ] --> ifbrace rbrace +ifbrace rbrace [ else (newline|ignore_scrap) ] --> ifbrace rbrace else +ifbrace <outdent-force> rbrace <"\\"-space> else if --> if +ifbrace <outdent-force> rbrace <"\\"-space> else lbrace --> forbrace +ifbrace <outdent-force> rbrace <"\\"-space> else --> formath +ifbrace <outdent-force> rbrace --> stmt + +# Assume simple statements attached to if will never be tagged + +ifmath [ stmt (newline|ignore_scrap) ] --> ifmath stmt +ifmath stmt [ else (newline|ignore_scrap) ] --> ifmath stmt else +ifmath <indent-force> stmt <outdent-force> else if --> if +ifmath <indent-force> stmt <outdent-force> else lbrace --> forbrace +ifmath <indent-force> stmt <outdent-force> else --> formath +ifmath <indent-force> stmt <outdent> --> stmt + +for math --> formath +formath <"\\"-space> lbrace --> forbrace +forbrace <force> stmt --> forbrace +forbrace <outdent-force> tagged_stmt --> forbrace +forbrace <outdent-force> rbrace --> stmt +formath <indent-force> stmt <outdent> --> stmt + +# we need an extra indent for switch, becuase the cases will be backed out +switch math lbrace <indent> --> switchbrace +switchbrace <outdent-force> tagged_stmt --> switchbrace +# This next should never happen +switchbrace <force> stmt --> switchbrace +switchbrace <outdent-outdent-force> rbrace --> stmt + + + +# handle do-while (while has category for) +do lbrace --> dobrace +dobrace <force> stmt --> dobrace +dobrace <outdent-force> tagged_stmt --> dobrace +dobrace <outdent-force> rbrace <"\\"-space> for --> math +do <indent-force> stmt <outdent-force> for --> math + +case semi --> stmt +case math semi --> stmt +case colon --> tag +case math colon --> tag +tag <force> tag --> tag +tag <indent-force> stmt --> tagged_stmt + +stmt <force> stmt --> stmt +stmt <outdent-force> tagged_stmt --> stmt +semi --> stmt + +# control sequence \8 puts things on the left margin +<force-"\\8"> sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +preproc backslash <force-"\\8\\hskip1em"-space> newline --> preproc +preproc <force-outdent> newline --> ignore_scrap +preproc !(less|lesssimp|backslash|newline) --> preproc +newline --> ignore_scrap + +less simp --> lesssimp +lesssimp dot simp --> lesssimp +<"\\LN"> lesssimp greater <"\\RN"> --> math +<"<"> lesssimp --> unop +less <"<"> --> binop +greater <">"> --> binop +dot --> binop + +macros begin +\let\LN\langle +\let\RN\rangle +macros end + + + + + diff --git a/web/spiderweb/src/c/local.guide b/web/spiderweb/src/c/local.guide new file mode 100644 index 0000000000..350b52c64a --- /dev/null +++ b/web/spiderweb/src/c/local.guide @@ -0,0 +1,4 @@ +#define in code should be done verbatim, otherwise trouble with +parentheses.... + +===> to force declaration. diff --git a/web/spiderweb/src/c/make b/web/spiderweb/src/c/make new file mode 100644 index 0000000000..0261e8df62 --- /dev/null +++ b/web/spiderweb/src/c/make @@ -0,0 +1,3 @@ +#!/bin/csh -f +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=ceetangle THEWEAVE=ceeweave SPIDER=c.spider $* diff --git a/web/spiderweb/src/c/new.spider b/web/spiderweb/src/c/new.spider new file mode 100644 index 0000000000..d361bb99a9 --- /dev/null +++ b/web/spiderweb/src/c/new.spider @@ -0,0 +1,407 @@ +Return-Path: <smith%zeus@harvard.harvard.edu> +Received: by jumbo.pa.dec.com; id AA01901; Thu, 26 Jul 90 08:43:40 -0700 +Received: by decpa.pa.dec.com; id AA11390; Thu, 26 Jul 90 08:43:34 -0700 +Received: from cs.Princeton.EDU by Princeton.EDU (5.61++/2.48/princeton) + id AA16823; Thu, 26 Jul 90 11:43:18 -0400 +Received: by cs.Princeton.EDU (5.57/1.105) + id AA04017; Thu, 26 Jul 90 11:43:53 EDT +Received: from harvard.harvard.edu by Princeton.EDU (5.61++/2.48/princeton) + id AA16820; Thu, 26 Jul 90 11:43:07 -0400 +Message-Id: <9007261543.AA16820@Princeton.EDU> +Received: by harvard.harvard.edu (5.54/a0.25) + (for nr@princeton.edu) id AA00320; Thu, 26 Jul 90 11:43:21 EDT +Date: Thu, 26 Jul 90 11:43:21 EDT +Received: by zeus.HARVARD.EDU; Thu, 26 Jul 90 11:41:04 EDT +From: smith%zeus@harvard.harvard.edu (Steven Smith) +To: nr@Princeton.EDU +Subject: Spidery WEB + +Prof. Ramsey: + +FYI: I've been using your Spidery WEB system and have introduced the +followng changes to c.spider: + +1) c.spider hung on the declaration (cf. K&R p. 123) + + struct { + int x; + int *y; + } *p; + +I fixed this by changing + + [ struct_head ] simp --> decl_head simp + +to + [ struct_head ] (math|simp) --> decl_head (math|simp) + + +2) I introduced the category `asterisk' so that `*' can be used as the +\mathbin `*' or the \mathord `{*}' by TeX, depending on the context. +Search for `asterisk' below to see the changes. + +Steven Smith +smith@sandalphon.harvard.edu + + +The file c.spider: +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Cut Here %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +# +# Alterations: +# 7/25/90 Steven T. Smith; Allowed declaration of ptr to structures. +# 7/25/90 Steven T. Smith; Introduced `asterisk' category. +# 7/25/90 Steven T. Smith; Changed `->' to different \mathord. +language C extension c + +at_sign @ + +comment begin <"/*"> end <"*/"> + +default translation <*> mathness yes + +token identifier category simp mathness yes +token number category math mathness yes +token newline category newline mathness maybe translation <> +token pseudo_semi category semi mathness maybe translation <"\\relax"> + +module definition stmt use math + +token + category unorbinop +token - category unorbinop +token * category asterisk tangleto <space-"*"> +# avoid inadvertant /* +token / category dot +token < category less translation <> +token > category greater translation <> +token = category equals translation <"\\leftarrow"> tangleto <"="-space> +# avoid inadvertant =- +token . category dot +token ~ category unop translation <"\\TI"> +token & category unorbinop translation <"\\amp"> +token ^ translation <"\\^"> category binop +token | category binop +token ? translation <"\\?"> category question +token % translation <"\\%"> category binop +token # translation <"\\#"> category sharp +token ! category unop translation <"\\neg"> +token \ category backslash translation <"\\backslash"> +token ( category open +token ) category close +token [ category open +token ] category close +token { translation <"\\{"-indent> category lbrace +token } translation <"\\}"> category rbrace +token , category comma translation <",\\;"> +token ; category semi +token : category colon +token ++ category unop translation <"\\PP"> +token -- category unop translation <"\\MM"> +token != translation <"\\I"> category binop +token <= translation <"\\L"> category binop +token >= translation <"\\G"> category binop +token == translation <"\\S"> category binop +token && translation <"\\W"> category binop +token || translation <"\\V"> category binop +token -> translation <"\\MG"> category binop +token >> translation <"\\GG"> category binop +token << translation <"\\LL"> category binop + +macros begin +\def\CC{\mathrel{:{:}}} +\def\CCE{\mathrel{:{:}=}} +\def\FE{\mathrel{/=}} +\def\PP{\mathord{++}} +\def\PE{\mathrel{+=}} +\def\MM{\mathord{--}} +\def\ME{\mathrel{-=}} +\def\MG{\mathord{-\!\triangleright}} +#\def\MG{\mathrel{\to}} +\def\GG{\mathrel{>\!>}} +\def\LL{\mathrel{<\!<}} +\def\TE{\mathrel{\ast=}} +\def\CE{\mathrel{\%=}} +\def\HE{\mathrel{\uparrow=}} +\def\AE{\mathrel{\&=}} +\def\OE{\mathrel{|=}} +\let\openbraces=\{ +\let\closebraces=\} +\def\{{\ifmmode\openbraces\else$\openbraces$\fi} +\def\}{\ifmmode\closebraces\else$\closebraces$\fi} +\def\?{\mathrel?} +\def\s{\ } +macros end + +default translation <*-"\\"-space> + +ilk case_like category case +ilk int_like category decl_head translation <*> +ilk else_like category else +ilk enum_like category enum +ilk if_like category if +ilk for_like category for +ilk do_like category do +ilk sizeof_like category sizeof +ilk struct_like category struct +ilk switch_like category switch +ilk typedef_like category typedef + +default translation <*> + +reserved auto ilk int_like +reserved break ilk case_like +reserved case ilk case_like +reserved char ilk int_like +reserved continue ilk case_like +reserved default ilk case_like +reserved do ilk do_like +reserved double ilk int_like +reserved else ilk else_like +reserved enum ilk enum_like +reserved extern ilk int_like +reserved float ilk int_like +reserved for ilk for_like +reserved goto ilk case_like +reserved if ilk if_like +reserved int ilk int_like +reserved long ilk int_like +reserved register ilk int_like +reserved return ilk case_like +reserved short ilk int_like +reserved sizeof ilk sizeof_like +reserved static ilk int_like +reserved struct ilk struct_like +reserved switch ilk switch_like +reserved typedef ilk typedef_like +reserved union ilk struct_like +reserved unsigned ilk int_like +reserved void ilk int_like +reserved while ilk for_like + +# we indulge in a trick to avoid treating +# ASCII (*fp)(); +# as a statement (function call). We use instead +# ASCII ===> (*fp)(); +token ===> translation <"\\relax"> tangleto <space> category decl_head + + +# +? ignore_scrap --> #1 +# dropped, because we've overflowed yacc! +#### DON'T DO THIS! it makes it impossible to add translation on the left +#### ignore_scrap ? --> #2 + + +# because of declarations, we have to be very careful about converting +# simp to math + +(math|simp) unop --> math +math (binop|unorbinop) (math|simp) --> math +math [ asterisk ] (math|simp) --> math binop (math|simp) +math comma <opt-9> (math|simp) --> math +# we're not allowed math simp --> statement because math simp could be fn_decl +math math --> math +(math|simp) semi --> stmt +# so to hack the omission above, we include (usually a cast) +math <"\\"-space> stmt --> stmt + +(open|simpopen|question|unop|unorbinop|case) [ simp ] --> (open|simpopen|question|unop|unorbinop|case) math +[ simp ] binop --> math binop +# old: +# [ simp ] equals --> math equals +# math [ equals ] --> math binop + +simp* colon --> tag + +# can't have simp open --> open because that causes ( to eat all id's to its left. +simp open --> simpopen + +(open|simpopen) math close --> math +(open|simpopen) <"\\,"> close --> math +# following needed for for statements +open stmt <"\\"-space> --> open + +# here we try to deal with casts and argument lists, e.g. +# (ASCII *) malloc(sizeof (ASCII *)); +# char *malloc(int); + +# If the type is predefined, we know we have a cast +(open|simpopen) decl_head close --> cast +(open|simpopen) [ decl_head (unorbinop|math|simp) ] --> (open|simpopen) decl_head +(open|simpopen) [ decl_head <"\\"-space-"{"> asterisk <"}"> ] --> (open|simpopen) decl_head_ptr +decl_head_ptr <"{"> asterisk <"}"> --> decl_head_ptr +decl_head_ptr --> decl_head +(open|simpopen) decl_head comma --> arglist +arglist (decl_head|unorbinop|math) --> arglist +arglist close --> math + +# and here are some common cases of casts with non-predefined types +# for other cases you'll have to use "declares" +(open|simpopen) math <"\\"-space> unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop unorbinop unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop close --> cast +(open|simpopen) math <"\\"-space> unorbinop unorbinop close --> cast +(open|simpopen) math <"\\"-space> unorbinop unorbinop unorbinop close --> cast + +# the math here seems to be a cast. We don't convert to cast because it looks +# too much like a cycle +(open|simpopen) [ math <"\\"-space> simp ] --> (open|simpopen) math + +# Here is the destiny of casts +cast <"\\"-space> (math|simp) --> math +cast (newline|ignore_scrap) --> cast +cast --> math + + + +question math colon --> binop + +unop math --> math +<"{"> unorbinop <"}"> math --> math +<"{"> asterisk <"}"> (math|simp) --> math +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +[ asterisk ] equals --> unorbinop equals +equals --> binop +sizeof (math|simp) --> math + +(simp|decl_head) <"\\"-space> decl_head --> decl_head +[ simp ] math (equals|comma|semi) --> decl_head math (equals|comma|semi) +[ (decl_head|simp) simp ] (simp|math) --> decl_head (simp|math) +(simp|decl_head) <"\\"-space> (simp|math)* comma --> decl_head +(simp|decl_head) <"\\"-space> (simp|math)* semi --> decl +(simp|decl_head) <"\\"-space> (simp|math)* equals --> decl_equals +decl_equals math comma --> decl_head +decl_equals math semi --> decl +decl_equals [ simp ] --> decl_equals math + +struct simp* <"\\"-space> lbrace --> structbrace +struct lbrace --> structbrace +structbrace [ simp ] --> structbrace decl_head +structbrace <force> decl --> structbrace +structbrace <outdent-force> rbrace --> struct_head +[ struct_head ] (math|simp) --> decl_head (math|simp) +# N.b. K&R p. 123. +# some people say e.g. struct blah {...}; is this K&R? +struct_head semi --> decl +struct [ simp (newline|ignore_scrap) ] --> struct simp +struct simp --> decl_head +decl_head <"\\"-space> struct --> struct + +# enumeration types are like structures and unions, but they have math +# instead of many decls... +enum simp* <"\\"-space> lbrace --> enumbrace +enum lbrace --> enumbrace +enumbrace math rbrace <outdent> --> enum_head +[ enum_head ] simp --> decl_head simp +enum_head semi --> decl +enum [ simp (newline|ignore_scrap) ] --> enum simp +enum simp --> decl_head +decl_head <"\\"-space> enum --> enum + +typedef [ simp ] --> typedef decl_head +typedef decl --> decl + + + + +[ math* <indent> ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +[ (simp|decl_head) <"\\"-space> math* <indent> ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +fn_decl <force> decl --> fn_decl +# The following statment will always have braces and never be tagged +fn_decl <outdent-force> stmt --> function +# include stmt here to cover module definition +(stmt|decl|function) <big_force> function --> function +function <big_force> decl --> decl + +(stmt|decl) <force> decl --> decl +decl <big_force> stmt --> stmt +decl <outdent-big_force> tagged_stmt --> stmt + + +lbrace <outdent-force> rbrace --> stmt +lbrace <force> stmt --> lbrace +lbrace <outdent-force> tagged_stmt --> lbrace +lbrace (math|simp) <outdent> rbrace --> math + +# if math can be followed by a brace, or no. +# ifmath and ifbrace can have an attached else or else if clause +# else, for, and while are formatted like if, but can't have an +# attached else clause, so we use formath and forbrace + +if math --> ifmath +ifmath <"\\"-space> lbrace --> ifbrace +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> tagged_stmt --> ifbrace +ifbrace [ rbrace (newline|ignore_scrap) ] --> ifbrace rbrace +ifbrace rbrace [ else (newline|ignore_scrap) ] --> ifbrace rbrace else +ifbrace <outdent-force> rbrace <"\\"-space> else if --> if +ifbrace <outdent-force> rbrace <"\\"-space> else lbrace --> forbrace +ifbrace <outdent-force> rbrace <"\\"-space> else --> formath +ifbrace <outdent-force> rbrace --> stmt + +# Assume simple statements attached to if will never be tagged + +ifmath [ stmt (newline|ignore_scrap) ] --> ifmath stmt +ifmath stmt [ else (newline|ignore_scrap) ] --> ifmath stmt else +ifmath <indent-force> stmt <outdent-force> else if --> if +ifmath <indent-force> stmt <outdent-force> else lbrace --> forbrace +ifmath <indent-force> stmt <outdent-force> else --> formath +ifmath <indent-force> stmt <outdent> --> stmt + +for math --> formath +formath <"\\"-space> lbrace --> forbrace +forbrace <force> stmt --> forbrace +forbrace <outdent-force> tagged_stmt --> forbrace +forbrace <outdent-force> rbrace --> stmt +formath <indent-force> stmt <outdent> --> stmt + +# we need an extra indent for switch, becuase the cases will be backed out +switch math lbrace <indent> --> switchbrace +switchbrace <outdent-force> tagged_stmt --> switchbrace +# This next should never happen +switchbrace <force> stmt --> switchbrace +switchbrace <outdent-outdent-force> rbrace --> stmt + + + +# handle do-while (while has category for) +do lbrace --> dobrace +dobrace <force> stmt --> dobrace +dobrace <outdent-force> tagged_stmt --> dobrace +dobrace rbrace for --> math +do <indent-force> stmt <outdent-force> for --> math + +case semi --> stmt +case math semi --> stmt +case colon --> tag +case math colon --> tag +tag <force> tag --> tag +tag <indent-force> stmt --> tagged_stmt + +stmt <force> stmt --> stmt +stmt <outdent-force> tagged_stmt --> stmt +semi --> stmt + +# control sequence \8 puts things on the left margin +<force-"\\8"> sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +preproc backslash <force-"\\8\\hskip1em"-space> newline --> preproc +preproc <force-outdent> newline --> ignore_scrap +preproc !(less|lesssimp|backslash|newline) --> preproc +newline --> ignore_scrap + +less simp --> lesssimp +lesssimp dot simp --> lesssimp +<"\\LN"> lesssimp greater <"\\RN"> --> math +<"<"> lesssimp --> unop +less <"<"> --> binop +greater <">"> --> binop +dot --> binop + +macros begin +\let\LN\langle +\let\RN\rangle +macros end + diff --git a/web/spiderweb/src/c/tangle.c b/web/spiderweb/src/c/tangle.c new file mode 100644 index 0000000000..49add84999 --- /dev/null +++ b/web/spiderweb/src/c/tangle.c @@ -0,0 +1,2214 @@ +/*1:*/ +#line 44 "tangle.web" + +/*4:*/ +#line 15 "common.h" + +#line 16 "common.h" +#include<stdio.h> + +/*:4*//*94:*/ +#line 1046 "tangle.web" + +#line 1047 "tangle.web" +#include"ctype.h" + +/*:94*/ +#line 45 "tangle.web" + +/*3:*/ +#line 9 "common.h" + +typedef short boolean; +typedef char unsigned eight_bits; +extern boolean program; +extern int phase; + +/*:3*//*5:*/ +#line 24 "common.h" + +typedef char ASCII; +typedef char outer_char; +extern ASCII xord[]; +extern outer_char xchr[]; +ASCII mod_text[400+1]; +ASCII *mod_text_end= mod_text+400; +ASCII *id_first; +ASCII *id_loc; + +/*:5*//*6:*/ +#line 37 "common.h" + +#line 38 "common.h" +extern ASCII buffer[]; +extern ASCII *buffer_end; +extern ASCII *loc; +extern ASCII *limit; + +/*:6*//*7:*/ +#line 55 "common.h" + +typedef struct name_info{ +ASCII *byte_start; +struct name_info *link; +union{ +struct name_info *Rlink; + +eight_bits Ilk; + +}dummy; +ASCII *equiv_or_xref; +}name_info; +typedef name_info *name_pointer; +typedef name_pointer *hash_pointer; +extern ASCII byte_mem[]; +extern ASCII *byte_mem_end; +extern name_info name_dir[]; +extern name_pointer name_dir_end; +extern name_pointer name_ptr; +extern ASCII *byte_ptr; +extern name_pointer hash[]; +extern hash_pointer hash_end; +extern hash_pointer h; +extern name_pointer id_lookup(); +extern name_pointer mod_lookup(); +extern name_pointer prefix_lookup(); + +/*:7*//*8:*/ +#line 98 "common.h" + +extern history; + +/*:8*//*9:*/ +#line 109 "common.h" + +extern include_depth; +extern FILE *file[]; +extern FILE *change_file; +extern char C_file_name[]; +extern char tex_file_name[]; +extern char file_name[][60]; + +extern char change_file_name[]; +extern line[]; +extern change_line; +extern boolean input_has_ended; +extern boolean changing; + +/*:9*//*10:*/ +#line 124 "common.h" + +#line 125 "common.h" +typedef unsigned short sixteen_bits; +extern sixteen_bits module_count; +extern boolean changed_module[]; +extern boolean print_where; + +/*:10*//*11:*/ +#line 131 "common.h" + +#line 132 "common.h" +extern int argc; +extern char * *argv; +extern no_xref; + +/*:11*//*12:*/ +#line 144 "common.h" + +FILE *C_file; +FILE *tex_file; +#line 81 "tangle.web" + +/*:12*/ +#line 46 "tangle.web" + +/*14:*/ +#line 107 "tangle.web" + +#line 108 "tangle.web" +typedef struct{ +eight_bits *tok_start; +sixteen_bits text_link; +}text; +typedef text *text_pointer; + +/*:14*//*25:*/ +#line 254 "tangle.web" + +typedef struct{ +eight_bits *end_field; +eight_bits *byte_field; +name_pointer name_field; +text_pointer repl_field; +sixteen_bits mod_field; +}output_state; +typedef output_state *stack_pointer; + +/*:25*/ +#line 47 "tangle.web" + +/*15:*/ +#line 114 "tangle.web" + +#line 115 "tangle.web" +text text_info[2000]; +text_pointer text_info_end= text_info+2000-1; +text_pointer text_ptr; +eight_bits tok_mem[150000]; +eight_bits *tok_mem_end= tok_mem+150000-1; +eight_bits *tok_ptr; + +/*:15*//*21:*/ +#line 185 "tangle.web" + +text_pointer last_unnamed; + +/*:21*//*26:*/ +#line 270 "tangle.web" + +output_state cur_state; + +output_state stack[50+1]; +stack_pointer stack_ptr; +stack_pointer stack_end= stack+50; + +/*:26*//*37:*/ +#line 413 "tangle.web" + +int cur_val; + + +/*:37*//*46:*/ +#line 520 "tangle.web" + +#line 521 "tangle.web" +short balances[128]; +/*:46*//*50:*/ +#line 583 "tangle.web" + +#line 584 "tangle.web" +name_pointer parm_ptr; + +/*:50*//*62:*/ +#line 706 "tangle.web" + +eight_bits out_state; +boolean protect; + +/*:62*//*64:*/ +#line 735 "tangle.web" + +name_pointer output_files[256]; +name_pointer *cur_out_file, *end_output_files, *an_output_file; +char cur_module_char; +char output_file_name[400]; + +/*:64*//*78:*/ +#line 143 "outtoks.web" +char C_file_extension[]= "c"; +/*:78*//*80:*/ +#line 148 "outtoks.web" +char the_at_sign= 64; + +/*:80*//*86:*/ +#line 943 "tangle.web" + +eight_bits ccode[128]; + +/*:86*//*88:*/ +#line 975 "tangle.web" +short tracing; +#line 976 "tangle.web" +/*:88*//*91:*/ +#line 1009 "tangle.web" + +#line 1010 "tangle.web" +boolean comment_continues= 0; + +/*:91*//*93:*/ +#line 1043 "tangle.web" + +name_pointer cur_module; + +/*:93*//*108:*/ +#line 1310 "tangle.web" + +text_pointer cur_text; +eight_bits next_control; + +/*:108*//*111:*/ +#line 1373 "tangle.web" + +ASCII param_name_texts[256]; +ASCII *param_name_texts_end= param_name_texts+256; +ASCII *param_names[32]; +short next_param_name; +ASCII *next_param_name_text; + +/*:111*//*132:*/ +#line 1693 "tangle.web" + +#line 1694 "tangle.web" +extern sixteen_bits module_count; + +/*:132*/ +#line 48 "tangle.web" + + +main(ac,av) +char * *av; +{ +argc= ac;argv= av; +program= 0; +/*16:*/ +#line 122 "tangle.web" + +#line 123 "tangle.web" +text_info->tok_start= tok_ptr= tok_mem; +text_ptr= text_info+1;text_ptr->tok_start= tok_mem; + + +/*:16*//*18:*/ +#line 132 "tangle.web" + +name_dir->equiv_or_xref= (ASCII *)text_info; + +/*:18*//*22:*/ +#line 188 "tangle.web" +last_unnamed= text_info;text_info->text_link= 0; +#line 189 "tangle.web" + +/*:22*//*47:*/ +#line 522 "tangle.web" + +#line 523 "tangle.web" +{int i; +for(i= 0;i<128;i++)balances[i]= 0; +/*48:*/ +#line 529 "tangle.web" + +#line 530 "tangle.web" +balances[40]= 1; +balances[41]= -1; +balances[91]= 1; +balances[93]= -1; +balances[123]= 1; +balances[125]= -1; + +/*:48*/ +#line 525 "tangle.web" +; +} +/*:47*//*65:*/ +#line 745 "tangle.web" + +#line 746 "tangle.web" +cur_out_file= end_output_files= output_files+256; + +/*:65*//*87:*/ +#line 946 "tangle.web" +{ +#line 947 "tangle.web" +int c; +for(c= 0;c<=127;c++)ccode[c]= 0; +ccode[' ']= ccode[011]= ccode['*']= 255; +ccode['@']= '@'; +ccode['=']= 2; +ccode['d']= ccode['D']= 252; +ccode['f']= ccode['F']= 251; +ccode['c']= ccode['C']= 253; +ccode['u']= ccode['U']= 253; +ccode['^']= ccode[':']= ccode['.']= ccode['t']= ccode['T']= 250; +ccode['&']= 127; +ccode['<']= ccode['(']= 254; +ccode['`']= 249; +ccode['\'']= 5; +ccode['"']= 6; + + + +ccode['@']= ccode[64]; +ccode[64]= 64; + +#ifdef DEBUG +ccode['0']= ccode['1']= ccode['2']= ccode['3']= ccode['4']= 248; +#endif DEBUG + +} + +/*:87*//*89:*/ +#line 976 "tangle.web" +tracing= 0; +#line 977 "tangle.web" + +/*:89*//*104:*/ +#line 1239 "tangle.web" +mod_text[0]= ' '; +#line 1240 "tangle.web" + +/*:104*//*113:*/ +#line 1385 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1385 "tangle.web" +; +#line 1386 "tangle.web" + +/*:113*/ +#line 55 "tangle.web" +; +common_init(); +printf("This is C TANGLE (generated at 5:29 PM on April 5, 1993)\n"); +phase_one(); +phase_two(); +wrap_up(); +} + +/*:1*//*19:*/ +#line 138 "tangle.web" + +#line 139 "tangle.web" +names_match(p,first,l) +name_pointer p; +ASCII *first; +int l; +{ +if(((p+1)->byte_start-(p)->byte_start)!=l)return 0; +return!strncmp(first,p->byte_start,l); +} + +/*:19*//*20:*/ +#line 149 "tangle.web" + +#line 150 "tangle.web" +init_node(node) +name_pointer node; +{ +node->equiv_or_xref= (ASCII *)text_info; + +} +init_p(p,t) +name_pointer p; +eight_bits t; +{ +p->dummy.Ilk= t; +} + + + +/*:20*//*24:*/ +#line 219 "tangle.web" +store_two_bytes(x) +sixteen_bits x; +{ +if(tok_ptr+2>tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; + *tok_ptr++= x>>8; + *tok_ptr++= x&255; +} + + +/*:24*//*28:*/ +#line 294 "tangle.web" +push_level(p) +#line 295 "tangle.web" +name_pointer p; +{ +/*29:*/ +#line 306 "tangle.web" + +#line 307 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>0){ +printf("\nPushing ");fflush(stdout),write(1,(p)->byte_start,(((p)+1)->byte_start-((p))->byte_start)); +printf(" =nd[%d]",p-name_dir); +} +#endif TRACE_MACROS + +/*:29*/ +#line 297 "tangle.web" +; +if(stack_ptr==stack_end){{printf("\n! Sorry, capacity exceeded: ");err_print("stack");history= 3;wrap_up();};}; + *stack_ptr= cur_state; +stack_ptr++; +cur_state.name_field= p;cur_state.repl_field= (text_pointer)p->equiv_or_xref; +cur_state.byte_field= cur_state.repl_field->tok_start;cur_state.end_field= (cur_state.repl_field+1)->tok_start; +cur_state.mod_field= 0; +} + +/*:28*//*30:*/ +#line 321 "tangle.web" +pop_level() +#line 322 "tangle.web" +{int number_of_parameters; +/*33:*/ +#line 363 "tangle.web" + +#line 364 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>0){ +printf("\nPopping ");fflush(stdout),write(1,(cur_state.name_field)->byte_start,(((cur_state.name_field)+1)->byte_start-((cur_state.name_field))->byte_start)); +printf(" =nd[%d]",cur_state.name_field-name_dir); +} + +#endif TRACE_MACROS + + + +/*:33*/ +#line 323 "tangle.web" +; +if(cur_state.repl_field->text_link==0){ +if(cur_state.name_field->dummy.Ilk==1){ +/*31:*/ +#line 338 "tangle.web" + +#line 339 "tangle.web" +number_of_parameters= *(cur_state.repl_field->tok_start); +/*32:*/ +#line 357 "tangle.web" + +#line 358 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>1){ +printf("\nUnstacking %d parameters",number_of_parameters); +} +#endif TRACE_MACROS +/*:32*/ +#line 340 "tangle.web" +; +while(number_of_parameters-->0){ +name_ptr--;text_ptr--; +#ifdef TRACE_MACROS +byte_ptr-= 2; +#endif TRACE_MACROS +} +#ifdef STAT +#ifdef STAT_HAS_BEEN_FIXED +if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr; + + +#endif STAT_HAS_BEEN_FIXED +#endif STAT +tok_ptr= text_ptr->tok_start; + + +/*:31*/ +#line 326 "tangle.web" +; +} +}else if(cur_state.repl_field->text_link<2000){ +cur_state.repl_field= cur_state.repl_field->text_link+text_info; +cur_state.byte_field= cur_state.repl_field->tok_start;cur_state.end_field= (cur_state.repl_field+1)->tok_start; +return; +} +stack_ptr--; +if(stack_ptr>stack)cur_state= *stack_ptr; +} + + +/*:30*//*38:*/ +#line 418 "tangle.web" +sixteen_bits +#line 419 "tangle.web" + get_output() +{ +sixteen_bits a; +restart:if(stack_ptr==stack)return 0; +if(cur_state.byte_field==cur_state.end_field){ +cur_val= -((int)cur_state.mod_field); +pop_level(); +if(cur_val==0)goto restart; +out_char(129);return; +} +a= *cur_state.byte_field++; +if(a<128) +if(a==7){ +/*40:*/ +#line 454 "tangle.web" + +#line 455 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf(" [#%d]", *cur_state.byte_field); +} +#endif TRACE_MACROS + +/*:40*/ +#line 432 "tangle.web" +; +/*39:*/ +#line 452 "tangle.web" + +#line 453 "tangle.web" +push_level(name_ptr- *cur_state.byte_field++);goto restart; +/*:39*/ +#line 434 "tangle.web" +; +}else +out_char(a); +else{ +a= (a-128) *256+ *cur_state.byte_field++; +switch(a/10240){ +case 0: +/*41:*/ +#line 461 "tangle.web" + +#line 462 "tangle.web" +if(name_dir[a].dummy.Ilk==1){ +/*42:*/ +#line 475 "tangle.web" + +#line 476 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf("\nExpanding macro (");fflush(stdout),write(1,(name_dir+a)->byte_start,(((name_dir+a)+1)->byte_start-((name_dir+a))->byte_start)); +printf("=nd[%d])",a); +} +#endif TRACE_MACROS + +/*:42*/ +#line 463 "tangle.web" +; +/*44:*/ +#line 492 "tangle.web" + +#line 493 "tangle.web" +{int number_of_parameters; +while(cur_state.byte_field==cur_state.end_field&&stack_ptr>stack)pop_level(); +number_of_parameters= *(((text_pointer)name_dir[a].equiv_or_xref)->tok_start); +if(number_of_parameters>0){ +if(stack_ptr==stack|| *cur_state.byte_field!=40){ +printf("\n! No parameters given for "); +fflush(stdout),write(1,(a+name_dir)->byte_start,(((a+name_dir)+1)->byte_start-((a+name_dir))->byte_start)); +err_print(""); +goto restart; +} +cur_state.byte_field++; +parm_ptr= name_ptr; +while(number_of_parameters-->0){ +/*49:*/ +#line 537 "tangle.web" + +#line 538 "tangle.web" +{int bal; +eight_bits b,oldb; +sixteen_bits c; +bal= 0; +/*59:*/ +#line 647 "tangle.web" + +#line 648 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf("\nScanning #%d...",number_of_parameters+1); +} +#endif TRACE_MACROS +/*:59*/ +#line 542 "tangle.web" +; +while(1){ +b= *cur_state.byte_field++; +if(b==7){ +b= *cur_state.byte_field++; +/*56:*/ +#line 613 "tangle.web" + +#line 614 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf(" <#%d=",b);fflush(stdout),write(1,(name_ptr-b)->byte_start,(((name_ptr-b)+1)->byte_start-((name_ptr-b))->byte_start));printf("=nd[%d]>", +name_ptr-b-name_dir); +} +#endif TRACE_MACROS + +/*:56*/ +#line 547 "tangle.web" +; +c= name_ptr-name_dir-b; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 128+(c/256);}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= c%256;}; +}else{ +if(b>=128){ +/*57:*/ +#line 621 "tangle.web" + +#line 622 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +int c; +printf(" <"); +c= (b-128) *256+ *cur_state.byte_field; +switch(c/10240){ +case 0:fflush(stdout),write(1,(name_dir+c)->byte_start,(((name_dir+c)+1)->byte_start-((name_dir+c))->byte_start)); +printf(" =nd[%d]",c); +break; +case 1:printf("MODULE");break; +default:printf("CONTEXT");break; +} +printf(">"); +} +#endif TRACE_MACROS + +/*:57*/ +#line 553 "tangle.web" +; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= b;}; +b= *cur_state.byte_field++; +}else if(bal==0&&((number_of_parameters==0&&b==41) +||(number_of_parameters>0&&b==44))){ +goto done; +}else if(/*51:*/ +#line 586 "tangle.web" +(b==2||b==3) +#line 587 "tangle.web" +/*:51*/ +#line 559 "tangle.web" +){ +/*52:*/ +#line 587 "tangle.web" + +#line 588 "tangle.web" +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= b;}; +oldb= b; +/*53:*/ +#line 601 "tangle.web" + +#line 602 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2)printf(" <"); +#endif TRACE_MACROS +/*:53*/ +#line 590 "tangle.web" +; +while((b= *cur_state.byte_field++)!=oldb){ +/*54:*/ +#line 605 "tangle.web" + +#line 606 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2)printf("%c",b); +#endif TRACE_MACROS +/*:54*/ +#line 592 "tangle.web" +; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= b;}; +if(cur_state.byte_field>=cur_state.end_field) +{printf("\n! This can't happen: ");err_print("string or constant didn't end in token list");history= 3;wrap_up();}; +} +/*55:*/ +#line 609 "tangle.web" + +#line 610 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2)printf(">"); +#endif TRACE_MACROS +/*:55*/ +#line 597 "tangle.web" +; + + + +/*:52*/ +#line 560 "tangle.web" +; +}else{ +/*58:*/ +#line 638 "tangle.web" + +#line 639 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf(" <"); +if(31<b&&b<127)printf("%c",b); +printf(">"); +} +#endif TRACE_MACROS + +/*:58*/ +#line 562 "tangle.web" +; +bal+= balances[b]; +} +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= b;}; +} +} +done: +parm_ptr->equiv_or_xref= (ASCII *)text_ptr; +text_ptr->text_link= 0; +parm_ptr->dummy.Ilk= 2; +#ifdef TRACE_MACROS +if(byte_ptr+2>=byte_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("byte memory");history= 3;wrap_up();};}; + *byte_ptr++= 35; *byte_ptr++= number_of_parameters+1+48; +#endif TRACE_MACROS +if(parm_ptr>=name_dir_end){{printf("\n! Sorry, capacity exceeded: ");err_print("name");history= 3;wrap_up();};}; +(++parm_ptr)->byte_start= byte_ptr; +if(text_ptr>=text_info_end){{printf("\n! Sorry, capacity exceeded: ");err_print("text");history= 3;wrap_up();};}; +(++text_ptr)->tok_start= tok_ptr; +/*60:*/ +#line 653 "tangle.web" + +#line 654 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>1){ +printf("\nStacked ");fflush(stdout),write(1,(parm_ptr-1)->byte_start,(((parm_ptr-1)+1)->byte_start-((parm_ptr-1))->byte_start)); +printf("=nd[%d]",parm_ptr-1-name_dir); +} +#endif TRACE_MACROS + +/*:60*/ +#line 580 "tangle.web" +; +} + +/*:49*/ +#line 507 "tangle.web" +; +} +name_ptr= parm_ptr; + +} +} + +/*:44*/ +#line 465 "tangle.web" +; +push_level(name_dir+a); +cur_state.byte_field++; +goto restart; +}else if(name_dir[a].dummy.Ilk==2){ +/*43:*/ +#line 483 "tangle.web" + +#line 484 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf("\nExpanding parameter (");fflush(stdout),write(1,(name_dir+a)->byte_start,(((name_dir+a)+1)->byte_start-((name_dir+a))->byte_start)); +printf("=nd[%d])",a); +} +#endif TRACE_MACROS + + +/*:43*/ +#line 470 "tangle.web" +; +push_level(name_dir+a); +goto restart; +} + +/*:41*/ +#line 441 "tangle.web" +; +cur_val= a;out_char(130);break; +case 1:/*61:*/ +#line 664 "tangle.web" + +#line 665 "tangle.web" +a-= 10240; +if((a+name_dir)->equiv_or_xref!=(ASCII *)text_info)push_level(a+name_dir); +else if(a!=0){ +printf("\n! Not present: <");fflush(stdout),write(1,(a+name_dir)->byte_start,(((a+name_dir)+1)->byte_start-((a+name_dir))->byte_start));err_print(">"); + +} +goto restart; + +/*:61*/ +#line 443 "tangle.web" +; +default:cur_val= a-20480;if(cur_val>0)cur_state.mod_field= cur_val; +out_char(129); +} +} +return 1; +} + + +/*:38*//*63:*/ +#line 714 "tangle.web" +flush_buffer() +#line 715 "tangle.web" +{ +putc('\n',C_file); +if(line[include_depth]%100==0){ +printf("."); +if(line[include_depth]%500==0)printf("%d",line[include_depth]); +fflush(stdout); +} +line[include_depth]++; +} + +/*:63*//*67:*/ +#line 764 "tangle.web" + +#line 765 "tangle.web" +phase_two(){ +line[include_depth]= 1; +if(text_info->text_link==0){ +if(end_output_files==cur_out_file){ +printf("\n! No program text was specified.");{if(history==0)history= 1;}; + +} +}else{ +printf("\nWriting the output files: (%s)",C_file_name);fflush(stdout); +/*27:*/ +#line 283 "tangle.web" + +#line 284 "tangle.web" +stack_ptr= stack+1;cur_state.name_field= name_dir;cur_state.repl_field= text_info->text_link+text_info; +cur_state.byte_field= cur_state.repl_field->tok_start;cur_state.end_field= (cur_state.repl_field+1)->tok_start;cur_state.mod_field= 0; + +/*:27*/ +#line 774 "tangle.web" +; +while(stack_ptr>stack)get_output(); +flush_buffer(); +} +if(end_output_files>cur_out_file){ +if(text_info->text_link==0){ +printf("\nWriting the output files: ");fflush(stdout); +} +/*68:*/ +#line 790 "tangle.web" + +#line 791 "tangle.web" +for(an_output_file= end_output_files;an_output_file>cur_out_file;){ +an_output_file--; +strncpy(output_file_name,( *an_output_file)->byte_start,400); +output_file_name[(( *an_output_file+1)->byte_start-( *an_output_file)->byte_start)]= '\0'; +fclose(C_file); +C_file= fopen(output_file_name,"w"); +if(C_file==NULL){ +{printf("! Cannot open output file:");err_print(output_file_name);history= 3;wrap_up();} +}else{ +printf(" (%s)",output_file_name);fflush(stdout); +} +stack_ptr= stack+1; +cur_state.name_field= ( *an_output_file); +cur_state.repl_field= (text_pointer)cur_state.name_field->equiv_or_xref; +cur_state.byte_field= cur_state.repl_field->tok_start; +cur_state.end_field= (cur_state.repl_field+1)->tok_start; +cur_state.mod_field= 0; +while(stack_ptr>stack)get_output(); +flush_buffer(); +} + + + +/*:68*/ +#line 782 "tangle.web" + +} +printf("\nDone."); +} + +/*:67*//*69:*/ +#line 816 "tangle.web" +out_char(cur_char) +#line 817 "tangle.web" +eight_bits cur_char; +{ +ASCII *j; +/*70:*/ +#line 841 "tangle.web" + +#line 842 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +switch(cur_char){ +case 10:printf(" [\\n]");break; +case 2: +printf("[STRING]");break; +case 127: +printf("[JOIN]");break; +case 3: +printf("[CONSTANT]");break; +case 130: +printf(" [");fflush(stdout),write(1,(cur_val+name_dir)->byte_start,(((cur_val+name_dir)+1)->byte_start-((cur_val+name_dir))->byte_start));printf("]"); +break; +case 129: +if(cur_val>0){ +printf(" [%d:]",cur_val); +}else if(cur_val<0){ +printf(" [:%d]",-cur_val); +}else{ +printf("[LINE NUMBER]"); +} +break; + +default: +if(31<cur_char&&cur_char<127){ +printf(" [%c]",cur_char); +}else{ +printf(" [\\%3o]",cur_char); +} +} +} +#endif TRACE_MACROS + + + + +/*:70*/ +#line 820 "tangle.web" +; +switch(cur_char){ +case 10:if(protect)putc(' ',C_file); +if(protect||out_state==4)putc('\\',C_file); + +flush_buffer();if(out_state!=4)out_state= 0;break; +/*71:*/ +#line 878 "tangle.web" + +#line 879 "tangle.web" +case 130: +if(out_state==1)putc(' ',C_file); +for(j= (cur_val+name_dir)->byte_start;j<(name_dir+cur_val+1)->byte_start; +j++)putc( *j,C_file); +out_state= 1;break; + +/*:71*/ +#line 826 "tangle.web" +; +/*72:*/ +#line 885 "tangle.web" + +#line 886 "tangle.web" +case 129: +if(cur_val>0){ +fprintf(C_file,"%s","/*"); +fprintf(C_file,"%d:",cur_val); +fprintf(C_file,"%s","*/"); +}else if(cur_val<0){ +fprintf(C_file,"%s","/*"); +fprintf(C_file,":%d",-cur_val); +fprintf(C_file,"%s","*/"); +}else{ +sixteen_bits a; +a= 256 * *cur_state.byte_field++; +a+= *cur_state.byte_field++; +fprintf(C_file,"\n%s","#line"); +fprintf(C_file," %d \"",a); +cur_val= *cur_state.byte_field++; +cur_val= 256 *(cur_val-128)+ *cur_state.byte_field++; +for(j= (cur_val+name_dir)->byte_start;j<(name_dir+cur_val+1)->byte_start; +j++)putc( *j,C_file); +fprintf(C_file,"\"%s\n","" +#line 910 "tangle.web" +); +} +break; + +#line 1 "outtoks.web" +/*:72*/ +#line 827 "tangle.web" +; +/*75:*/ +#line 58 "outtoks.web" + +#line 59 "outtoks.web" +case 26: +fprintf(C_file,"%s","=="); +if(out_state!=4)out_state= 0; +break; +case 23: +fprintf(C_file,"%s","->"); +if(out_state!=4)out_state= 0; +break; +case 25: +fprintf(C_file,"%s","&&"); +if(out_state!=4)out_state= 0; +break; +case 24: +fprintf(C_file,"%s","||"); +if(out_state!=4)out_state= 0; +break; +case 21: +fprintf(C_file,"%s","<<"); +if(out_state!=4)out_state= 0; +break; +case 28: +fprintf(C_file,"%s","<="); +if(out_state!=4)out_state= 0; +break; +case 20: +if(out_state==4){ +fprintf(C_file,"%s","===>"); +}else{ +fprintf(C_file,"%s"," "); +} +if(out_state!=4)out_state= 0; +break; +case 31: +fprintf(C_file,"%s","++"); +if(out_state!=4)out_state= 0; +break; +case 27: +fprintf(C_file,"%s",">="); +if(out_state!=4)out_state= 0; +break; +case 22: +fprintf(C_file,"%s",">>"); +if(out_state!=4)out_state= 0; +break; +case 29: +fprintf(C_file,"%s","!="); +if(out_state!=4)out_state= 0; +break; +case 30: +fprintf(C_file,"%s","--"); +if(out_state!=4)out_state= 0; +break; +/*:75*//*76:*/ +#line 111 "outtoks.web" + +#line 112 "outtoks.web" +case'=': +if(out_state==4){ +fprintf(C_file,"%s","="); +}else{ +fprintf(C_file,"%s","= "); +} +if(out_state!=4)out_state= 0; +break; +case'*': +if(out_state==4){ +fprintf(C_file,"%s","*"); +}else{ +fprintf(C_file,"%s"," *"); +} +if(out_state!=4)out_state= 0; +break; +/*:76*/ +#line 828 "tangle.web" + +case 127:out_state= 3;break; +case 3:if(out_state==4){ +out_state= 1;break; +} +if(out_state==1)putc(' ',C_file);out_state= 4;break; +case 2:if(out_state==4)out_state= 0; +else out_state= 4;break; +default:putc(cur_char,C_file);if(out_state!=4)out_state= 0; +break; +} +} + +/*:69*//*90:*/ +#line 981 "tangle.web" +eight_bits skip_ahead() +#line 982 "tangle.web" +{ +eight_bits c; +while(1){ +if(loc>limit&&(get_line()==0))return(255); + *(limit+1)= 64; +while( *loc!=64)loc++; +if(loc<=limit){ +loc++;c= ccode[ *loc]; +#ifdef DEBUG +if(c==248){ +tracing= *loc-48;c= 0; +} +#endif DEBUG +loc++; +if(c!=0|| *(loc-1)=='>')return(c); +} +} +} + +/*:90*//*92:*/ +#line 1012 "tangle.web" + +#line 1013 "tangle.web" +skip_comment() +{ +ASCII c; +if(0){ +get_line(); +return(comment_continues= 0); +}else{ +while(1){ +if(loc>limit) +if(get_line())return(comment_continues= 1); +else{ +err_print("! Input ended in mid-comment"); + +return(comment_continues= 0); +} +c= *(loc++); +/*82:*/ +#line 163 "outtoks.web" + +{int len;len= strlen("*/"); +if(loc+len-1<=limit&&!strncmp(loc-1,"*/",len)){ +loc+= len-1;return(comment_continues= 0);}} +/*:82*/ +#line 1029 "tangle.web" + +if(c==64){ +if(ccode[ *loc]==255){ +err_print("! Section name ended in mid-comment");loc--; + +return(comment_continues= 0); +} +else loc++; +} +} +} +} +/*:92*//*95:*/ +#line 1052 "tangle.web" +eight_bits get_next() +#line 1053 "tangle.web" +{ +eight_bits c; +while(1){ +if(loc>limit){ +if(get_line()==0)return(255); +else if(print_where){ +print_where= 0; +/*125:*/ +#line 1586 "tangle.web" + +#line 1587 "tangle.web" +store_two_bytes(53248); +if(changing)id_first= change_file_name; +else id_first= file_name[include_depth]; +id_loc= id_first+strlen(id_first); +if(changing)store_two_bytes((sixteen_bits)change_line); +else store_two_bytes((sixteen_bits)line[include_depth]); +{int a= id_lookup(id_first,id_loc,0)-name_dir;{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+128;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;};} + +/*:125*/ +#line 1060 "tangle.web" +; +} +else return(10); +} +c= *loc; +if(comment_continues){ +skip_comment(); +if(comment_continues||0)return(10); +else continue; +} +/*81:*/ +#line 151 "outtoks.web" + +#line 152 "outtoks.web" +{int len;len= strlen("/*"); +if(loc+len<=limit&&!strncmp(loc,"/*",len)){ +loc+= len; +skip_comment(); +if(comment_continues||0) +return('\n'); +else continue; +} +} +/*:81*/ +#line 1070 "tangle.web" + +loc++; +if(isdigit(c)||c=='\\'||c=='.')/*97:*/ +#line 1092 "tangle.web" +{ +#line 1093 "tangle.web" +id_first= loc-1; +if( *id_first=='.'&&!isdigit( *loc))goto mistake; +if( *id_first=='\\')while(isdigit( *loc))loc++; +else{ +if( *id_first=='0'){ +if( *loc=='x'|| *loc=='X'){ +loc++;while(isxdigit( *loc))loc++;goto found; +} +} +while(isdigit( *loc))loc++; +if( *loc=='.'){ +loc++; +while(isdigit( *loc))loc++; +} +if( *loc=='e'|| *loc=='E'){ +if( *++loc=='+'|| *loc=='-')loc++; +while(isdigit( *loc))loc++; +} +} +found: +id_loc= loc; +return(3); +} + +/*:97*/ +#line 1072 "tangle.web" + +else if(isalpha(c)||c=='_'||c=='$')/*96:*/ +#line 1084 "tangle.web" +{ +#line 1085 "tangle.web" +id_first= --loc; +while(isalpha( *++loc)||isdigit( *loc)|| *loc=='_'); +if( *loc=='$')while(isdigit( *++loc)|| *loc=='$'); + +id_loc= loc;return(130); +} + +/*:96*/ +#line 1073 "tangle.web" + +else if(c=='\''||c=='\"')/*98:*/ +#line 1122 "tangle.web" +{ +#line 1123 "tangle.web" +ASCII delim= c; + + +if(delim=='\''&&(loc+1>=limit|| +( *loc!='\\'&& *loc!=64&&loc[1]!='\'')|| +( *loc=='\\'&&(loc+2>=limit||loc[2]!='\''))|| +( *loc==64&& +(loc+2>=limit||loc[1]!=64||loc[2]!='\'')) +))goto mistake; +id_first= mod_text+1; +id_loc= mod_text; *++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<=mod_text_end) *id_loc= 10; + +} +if((c= *loc++)==delim){ +if(++id_loc<=mod_text_end) *id_loc= c; +break; +} +if(c=='\\'){ +if(loc>=limit)continue; +if(++id_loc<=mod_text_end) *id_loc= '\\'; +c= *loc++; +} +if(++id_loc<=mod_text_end) *id_loc= c; +} +if(id_loc>=mod_text_end){ +printf("\n! String too long: "); + +fflush(stdout),write(1,mod_text+1,25); +printf("...");history= 2; +} +id_loc++; +return(2); +} + +/*:98*/ +#line 1074 "tangle.web" + +else if(c==64)/*99:*/ +#line 1171 "tangle.web" +{ +#line 1172 "tangle.web" +c= ccode[ *loc++]; +switch(c){ +case 0:continue; +case 250:while((c= skip_ahead())==64); + +if( *(loc-1)!='>')err_print("! Improper @ within control text"); + +continue; +case 254: +cur_module_char= *(loc-1); +/*103:*/ +#line 1221 "tangle.web" +{ +#line 1222 "tangle.web" +ASCII *k; +/*105:*/ +#line 1241 "tangle.web" + +#line 1242 "tangle.web" +k= mod_text; +while(1){ +if(loc>limit&&get_line()==0){ +err_print("! Input ended in section name"); + +loc= buffer+1;break; +} +c= *loc; +/*106:*/ +#line 1265 "tangle.web" + +#line 1266 "tangle.web" +if(c==64){ +c= *(loc+1); +if(c=='>'){ +loc+= 2;break; +} +if(ccode[c]==255){ +err_print("! Section name didn't end");break; + +} + *(++k)= 64;loc++; +} + +/*:106*/ +#line 1250 "tangle.web" +; +loc++;if(k<mod_text_end)k++; +if(c==' '||c==011){ +c= ' ';if( *(k-1)==' ')k--; +} + *k= c; +} +if(k>=mod_text_end){ +printf("\n! Section name too long: "); + +fflush(stdout),write(1,mod_text+1,25); +printf("...");{if(history==0)history= 1;}; +} +if( *k==' '&&k>mod_text)k--; + +/*:105*/ +#line 1223 "tangle.web" +; +if(k-mod_text>3&&strncmp(k-2,"...",3)==0)cur_module= prefix_lookup(mod_text+1,k-3); +else cur_module= mod_lookup(mod_text+1,k); +if(cur_module_char=='('){ +/*66:*/ +#line 749 "tangle.web" + +#line 750 "tangle.web" +{ +if(cur_out_file>output_files){ +for(an_output_file= cur_out_file; +an_output_file<end_output_files;an_output_file++) +if( *an_output_file==cur_module)break; +if(an_output_file==end_output_files) + *--cur_out_file= cur_module; +}else{ +{{printf("\n! Sorry, capacity exceeded: ");err_print("output files");history= 3;wrap_up();};}; +} +} + +/*:66*/ +#line 1228 "tangle.web" + +} +return(254); +} + +/*:103*/ +#line 1182 "tangle.web" +; +case 2:/*107:*/ +#line 1283 "tangle.web" +{ +#line 1284 "tangle.web" +id_first= loc++; *(limit+1)= 64; *(limit+2)= '>'; +while( *loc!=64|| *(loc+1)!='>')loc++; +if(loc>=limit)err_print("! Verbatim string didn't end"); + +id_loc= loc;loc+= 2; +return(2); +} + +/*:107*/ +#line 1183 "tangle.web" +; +#ifdef DEBUG +case 248:tracing= *(loc-1)-'0';continue; +#endif DEBUG +case 249:/*100:*/ +#line 1194 "tangle.web" + +#line 1195 "tangle.web" +id_first= loc; +if( *loc=='\\')loc++; +while( *loc!='\''){ +loc++; +if(loc>limit){ +err_print("! String didn't end");loc= limit-1;break; +} +} +loc++; +return(249); + +/*:100*/ +#line 1187 "tangle.web" +; +case 5:/*101:*/ +#line 1206 "tangle.web" +{ +#line 1207 "tangle.web" +id_first= loc; +while('0'<= *loc&& *loc<'8')loc++; +id_loc= loc; +return(5); +} + +/*:101*/ +#line 1188 "tangle.web" +; +case 6:/*102:*/ +#line 1213 "tangle.web" +{ +#line 1214 "tangle.web" +id_first= loc; +while(isxdigit( *loc))loc++; +id_loc= loc; +return(6); +} + + +/*:102*/ +#line 1189 "tangle.web" +; +default:return(c); +} +} + +/*:99*/ +#line 1075 "tangle.web" + +else if(c==' '||c==011){ +continue; +} +mistake:/*74:*/ +#line 3 "outtoks.web" + +#line 4 "outtoks.web" +if(loc+3<=limit){ +if(strncmp("===>",loc-1,4)==0){ +loc+= 3; +return 20; +} +} +if(loc+2<=limit){ +} +if(loc+1<=limit){ +if(strncmp("==",loc-1,2)==0){ +loc+= 1; +return 26; +} +else if(strncmp("->",loc-1,2)==0){ +loc+= 1; +return 23; +} +else if(strncmp("&&",loc-1,2)==0){ +loc+= 1; +return 25; +} +else if(strncmp("||",loc-1,2)==0){ +loc+= 1; +return 24; +} +else if(strncmp("<<",loc-1,2)==0){ +loc+= 1; +return 21; +} +else if(strncmp("<=",loc-1,2)==0){ +loc+= 1; +return 28; +} +else if(strncmp("++",loc-1,2)==0){ +loc+= 1; +return 31; +} +else if(strncmp(">=",loc-1,2)==0){ +loc+= 1; +return 27; +} +else if(strncmp(">>",loc-1,2)==0){ +loc+= 1; +return 22; +} +else if(strncmp("!=",loc-1,2)==0){ +loc+= 1; +return 29; +} +else if(strncmp("--",loc-1,2)==0){ +loc+= 1; +return 30; +} +} +/*:74*/ +#line 1079 "tangle.web" + +return(c); +} +} + +/*:95*//*109:*/ +#line 1314 "tangle.web" +scan_repl(t) +#line 1315 "tangle.web" +eight_bits t; +{ +sixteen_bits a; +int set_print_where; +if(t==254){/*125:*/ +#line 1586 "tangle.web" + +#line 1587 "tangle.web" +store_two_bytes(53248); +if(changing)id_first= change_file_name; +else id_first= file_name[include_depth]; +id_loc= id_first+strlen(id_first); +if(changing)store_two_bytes((sixteen_bits)change_line); +else store_two_bytes((sixteen_bits)line[include_depth]); +{int a= id_lookup(id_first,id_loc,0)-name_dir;{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+128;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;};} + +/*:125*/ +#line 1319 "tangle.web" +;} + + +while(1){ +if(t==1){ +print_where= 0; +} +a= get_next(); +if(t==1){ +set_print_where= print_where; +} +switch(a){ +/*124:*/ +#line 1529 "tangle.web" + +#line 1530 "tangle.web" +case 130: +{short n; +if((n= parameter_number(id_first,id_loc))!=0){ +#ifdef TRACE_MACROS +if(tracing>1){ +printf("\nIdentified ");fflush(stdout),write(1,id_first,id_loc-id_first); +printf(" as parameter number %d (%d from back)",n,next_param_name-n+1); +} +#endif TRACE_MACROS +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 7;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= next_param_name-n+1;}; +}else{ +a= id_lookup(id_first,id_loc,0)-name_dir; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+128;};{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;}; +} +} +break; +case 254:if(t!=254)goto done; +else{ +/*126:*/ +#line 1596 "tangle.web" +{ +#line 1597 "tangle.web" +ASCII *try_loc= loc; +while( *try_loc==' '&&try_loc<limit)try_loc++; +if( *try_loc=='+'&&try_loc<limit)try_loc++; +while( *try_loc==' '&&try_loc<limit)try_loc++; +if( *try_loc=='=')err_print("! Nested named modules. Missing @?"); + +} + +/*:126*/ +#line 1549 "tangle.web" +; +a= cur_module-name_dir; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+168;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;}; +/*125:*/ +#line 1586 "tangle.web" + +#line 1587 "tangle.web" +store_two_bytes(53248); +if(changing)id_first= change_file_name; +else id_first= file_name[include_depth]; +id_loc= id_first+strlen(id_first); +if(changing)store_two_bytes((sixteen_bits)change_line); +else store_two_bytes((sixteen_bits)line[include_depth]); +{int a= id_lookup(id_first,id_loc,0)-name_dir;{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= (a/256)+128;}; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a%256;};} + +/*:125*/ +#line 1553 "tangle.web" +;break; +} +case 3:case 2: +/*127:*/ +#line 1605 "tangle.web" + +#line 1606 "tangle.web" +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;}; +while(id_first<id_loc){ +if( *id_first==64)id_first++; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= *id_first++;}; +} +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;};break; + +/*:127*/ +#line 1556 "tangle.web" +; +case 249: +/*128:*/ +#line 1613 "tangle.web" +{ +#line 1614 "tangle.web" +int c; +if( *id_first==64){ +c= xchr[ *id_first++]; +if( *id_first!=64)err_print("! Double @ within string"); +} +else if( *id_first=='\\'){ +id_first++; +switch( *id_first){ +case't':c= 9;break; +case'n':c= 10;break; +case'b':c= 8;break; +case'0':c= 0;break; +case'\\':c= 92;break; +default:err_print("! Unrecognized escape sequence"); +} +} +else c= xchr[ *id_first]; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; + + +app_decimal((long)c); +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +} +break; + +/*:128*/ +#line 1558 "tangle.web" +; +case 5: +/*129:*/ +#line 1640 "tangle.web" +{ +#line 1641 "tangle.web" +long sum= 0; +while(id_first<id_loc){ +sum= 8 *sum+ *id_first++-'0'; +if(sum>67108864)err_print("! Octal constant exceeds @\"04000000"); +} +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +app_decimal(sum); +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +} + +/*:129*/ +#line 1560 "tangle.web" +;break; +case 6: +/*130:*/ +#line 1651 "tangle.web" +{ +#line 1652 "tangle.web" +long sum= 0; +while(id_first<id_loc){ +sum= 16 *sum+ +(isdigit( *id_first) +? *id_first-'0' +:isupper( *id_first) +? *id_first-'A'+10 +: *id_first-'a'+10 +); +id_first++; +if(sum>67108864)err_print("! Hex constant exceeds @\"04000000"); +} +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +app_decimal(sum); +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= 3;}; +} + +/*:130*/ +#line 1562 "tangle.web" +;break; +case 10: +#ifdef NEWLINES_IN_MACROS +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;}; +#else +if(t==1)continue; +else{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;}; +#endif NEWLINES_IN_MACROS +break; +case 252:case 251:case 253: +if(t!=254)goto done; +else{ +err_print("! @d, @f and @u are ignored in C text");continue; + +} +case 255:goto done; + +/*:124*/ +#line 1334 "tangle.web" + +default:{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= a;}; +} +} +done:next_control= (eight_bits)a; +if(text_ptr>text_info_end){{printf("\n! Sorry, capacity exceeded: ");err_print("text");history= 3;wrap_up();};}; +if(t==1){ +/*110:*/ +#line 1358 "tangle.web" + +#line 1359 "tangle.web" +tok_ptr-= 2; +while( *tok_ptr<128&& *(tok_ptr+1)==10)tok_ptr--; +tok_ptr+= 2; + +/*:110*/ +#line 1341 "tangle.web" +; +} +cur_text= text_ptr;(++text_ptr)->tok_start= tok_ptr; +print_where= set_print_where; +} + +/*:109*//*116:*/ +#line 1408 "tangle.web" + +#line 1409 "tangle.web" +int parameter_number(first,loc) +ASCII *first, *loc; +{ +ASCII *f, *p; +int n; +for(n= 0;n<next_param_name;n++){ +if(loc-first==param_names[n+1]-param_names[n]){ + +for(f= first,p= param_names[n];f<loc;) +if( *f++!= *p++)goto nomatch; +return n+1; +} +nomatch:continue; +} +return 0; +} + + +/*:116*//*131:*/ +#line 1670 "tangle.web" + +#line 1671 "tangle.web" +app_decimal(c) +long c; +{long power; +if(c==0){{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= '0';};return;} +if(c<0){{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= '-';};c= -c;} +for(power= 1;c>=power;power *= 10); + +for(power/= 10;power>=1;power/= 10){ +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= '0'+c/power;}; +c%= power; + +} +} + + + +/*:131*//*133:*/ +#line 1697 "tangle.web" +scan_module() +#line 1698 "tangle.web" +{ +name_pointer p; +text_pointer q; +sixteen_bits a; +module_count++; +if( *(loc-1)=='*') +printf("*%d",module_count);fflush(stdout); +/*134:*/ +#line 1714 "tangle.web" + +next_control= 0; +while(1){ +done_scanning: +while(next_control<=251) +if((next_control= skip_ahead())==254){ + +loc-= 2;next_control= get_next(); +} +if(next_control!=252)break; +/*117:*/ +#line 1433 "tangle.web" + +#line 1434 "tangle.web" +/*123:*/ +#line 1521 "tangle.web" + +#line 1522 "tangle.web" +while((next_control= get_next())==10); + +/*:123*/ +#line 1434 "tangle.web" + +/*121:*/ +#line 1484 "tangle.web" + +#line 1485 "tangle.web" +if(next_control!=130){ +err_print("! Macro name must be an identifier"); + +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1488 "tangle.web" +; +}else{ +p= id_lookup(id_first,id_loc,1); +if(p->dummy.Ilk!=1){ +#ifdef WARN_USE_BEFORE_DEF +printf("\n! Warning: macro name "); +fflush(stdout),write(1,(p)->byte_start,(((p)+1)->byte_start-((p))->byte_start)); +printf(" was used before it was defined"); +{if(history==0)history= 1;}; +#endif WARN_USE_BEFORE_DEF +p->dummy.Ilk= 1; +}else if(p+1!=name_ptr){ +err_print("! Macro name is multiply defined: "); +} +} + +/*:121*/ +#line 1436 "tangle.web" +; +/*120:*/ +#line 1469 "tangle.web" + +#line 1470 "tangle.web" +/*123:*/ +#line 1521 "tangle.web" + +#line 1522 "tangle.web" +while((next_control= get_next())==10); + +/*:123*/ +#line 1470 "tangle.web" + +if(next_control==40){ +do{ +/*122:*/ +#line 1504 "tangle.web" + +#line 1505 "tangle.web" +/*123:*/ +#line 1521 "tangle.web" + +#line 1522 "tangle.web" +while((next_control= get_next())==10); + +/*:123*/ +#line 1505 "tangle.web" +; +if(next_control!=130){ +err_print("! Macro parameter name not an identifier"); + +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1509 "tangle.web" +; +}else{ +if(parameter_number(id_first,id_loc)!=0){ +err_print("! Duplicate parameters in macro definition"); + +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1514 "tangle.web" +; +}else{ +/*114:*/ +#line 1387 "tangle.web" + +#line 1388 "tangle.web" +/*115:*/ +#line 1393 "tangle.web" + +#line 1394 "tangle.web" +if(next_param_name==32) +{{printf("\n! Sorry, capacity exceeded: ");err_print("parameter names");history= 3;wrap_up();};}; +if(id_loc-id_first> +param_name_texts_end-next_param_name_text) +{{printf("\n! Sorry, capacity exceeded: ");err_print("parameter name texts");history= 3;wrap_up();};}; + + +/*:115*/ +#line 1388 "tangle.web" +; +while(id_first<id_loc) + *next_param_name_text++= *id_first++; +param_names[++next_param_name]= next_param_name_text; + +/*:114*/ +#line 1516 "tangle.web" +; +} +} + + +/*:122*/ +#line 1473 "tangle.web" +; +/*123:*/ +#line 1521 "tangle.web" + +#line 1522 "tangle.web" +while((next_control= get_next())==10); + +/*:123*/ +#line 1474 "tangle.web" + +}while(next_control==44); +if(next_control!=41){ +err_print("! Macro parameter list must end with )"); +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1478 "tangle.web" +; +} +next_control= get_next(); +} + + +/*:120*/ +#line 1439 "tangle.web" +; +if(next_control!=61){ +err_print("! You must put an = sign before the macro replacement text"); +/*135:*/ +#line 1732 "tangle.web" + +#line 1733 "tangle.web" +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1733 "tangle.web" +; +p->dummy.Ilk= 0; +goto done_scanning; + + +/*:135*/ +#line 1442 "tangle.web" +; +} +/*118:*/ +#line 1451 "tangle.web" + +#line 1452 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>1){ +printf("\nScanning definition of macro ");fflush(stdout),write(1,(p)->byte_start,(((p)+1)->byte_start-((p))->byte_start)); +} +#endif TRACE_MACROS + +/*:118*/ +#line 1444 "tangle.web" +; +{if(tok_ptr==tok_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("token");history= 3;wrap_up();};}; *tok_ptr++= next_param_name;}; +scan_repl(1); +p->equiv_or_xref= (ASCII *)cur_text; +/*119:*/ +#line 1458 "tangle.web" + +#line 1459 "tangle.web" +#ifdef TRACE_MACROS +if(tracing>2){ +printf("\nMacro ");fflush(stdout),write(1,(p)->byte_start,(((p)+1)->byte_start-((p))->byte_start)); +printf("'s replacement text is in text_info[%d]",cur_text-text_info); +} +#endif TRACE_MACROS + + +/*:119*/ +#line 1448 "tangle.web" +; +/*112:*/ +#line 1380 "tangle.web" + +#line 1381 "tangle.web" +next_param_name= 0; +next_param_name_text= param_name_texts; +param_names[next_param_name]= next_param_name_text; + +/*:112*/ +#line 1449 "tangle.web" +; + +/*:117*/ +#line 1724 "tangle.web" +; +cur_text->text_link= 0; +} + +/*:134*/ +#line 1705 "tangle.web" +; +/*136:*/ +#line 1738 "tangle.web" + +#line 1739 "tangle.web" +switch(next_control){ +case 253:p= name_dir;break; +case 254:p= cur_module; +/*137:*/ +#line 1750 "tangle.web" + +#line 1751 "tangle.web" +while((next_control= get_next())=='+'); +if(next_control!='='){ +err_print("! C text flushed, = sign is missing"); + +while((next_control= skip_ahead())!=255); +return; +} + +/*:137*/ +#line 1742 "tangle.web" +; +break; +default:return; +} +/*138:*/ +#line 1759 "tangle.web" + +#line 1760 "tangle.web" +store_two_bytes((sixteen_bits)(53248+module_count)); + +/*:138*/ +#line 1746 "tangle.web" +; +scan_repl(254); +/*139:*/ +#line 1762 "tangle.web" + +#line 1763 "tangle.web" +if(p==name_dir||p==0){ +(last_unnamed)->text_link= cur_text-text_info;last_unnamed= cur_text; +} +else if(p->equiv_or_xref==(ASCII *)text_info)p->equiv_or_xref= (ASCII *)cur_text; + +else{ +q= (text_pointer)p->equiv_or_xref; +while(q->text_link<2000)q= q->text_link+text_info; +q->text_link= cur_text-text_info; +} +cur_text->text_link= 2000; + +/*:139*/ +#line 1748 "tangle.web" +; + +/*:136*/ +#line 1706 "tangle.web" +; +} + +/*:133*//*140:*/ +#line 1775 "tangle.web" +phase_one(){ +#line 1776 "tangle.web" +phase= 1; +module_count= 0; +reset_input(); +while((next_control= skip_ahead())!=255); +while(!input_has_ended)scan_module(); +check_complete(); +phase= 2; +} + +/*:140*//*141:*/ +#line 1785 "tangle.web" +print_stats(){ +#line 1786 "tangle.web" +printf("\nMemory usage statistics:\n"); +printf("%d names (out of %d)\n",name_ptr-name_dir,4000); +printf("%d replacement texts (out of %d)\n",text_ptr-text_info,2000); +printf("%d bytes (out of %d)\n",byte_ptr-byte_mem,90000); +printf("%d tokens (out of %d)\n",tok_ptr-tok_mem,150000); +} + +/*:141*/ diff --git a/web/spiderweb/src/concrete-kernel.diff b/web/spiderweb/src/concrete-kernel.diff new file mode 100644 index 0000000000..eb3929b55d --- /dev/null +++ b/web/spiderweb/src/concrete-kernel.diff @@ -0,0 +1,200 @@ +From stevea@vast.unsw.edu.au Sun Jul 26 20:36:46 1992 +Received: from Princeton.EDU by fs.Princeton.EDU (4.1/1.105) + id AA27727; Sun, 26 Jul 92 20:36:44 EDT +Received: from conch.vast.unsw.edu.au by Princeton.EDU (5.65b/2.93/princeton) + id AA14011; Sun, 26 Jul 92 20:36:35 -0400 +Received: from mucket.vast.unsw.edu.au by conch.vast.unsw.edu.au (5.65/1.2) + id AA10447; Mon, 27 Jul 92 10:36:25 +1000 +Received: by mucket.vast.unsw.edu.au (5.65/client-1.3) + id AA20338; Mon, 27 Jul 92 10:36:24 +1000 +Message-Id: <9207270036.AA20338@mucket.vast.unsw.edu.au> +To: Norman Ramsey <nr@Princeton.EDU> +Cc: stevea@vast.unsw.edu.au +Subject: Re: Minor annoyance in ceeweave... +In-Reply-To: Your message of "Fri, 24 Jul 92 14:12:49 -0400." + <9207241812.AA09444@cs.Princeton.EDU> +Date: Mon, 27 Jul 92 10:36:23 +1000 +From: stevea@vast.unsw.edu.au +Status: R + +Hi Norman, + As requested, here are the diffs. I'd love to try and work the +NFSS in, but I think that requires LaTeX. Oh well.... + I've also tacked on the ccbx10 diffs with ccr10. This is a major +kludge, and I don't recommend using it at anything higher than +\magstep2. + + Hope they're useful. + + cheers + -steve + +--------------------<webkernel.tex diffs>--------------------- +19,34c19,22 +< %% +< %% This has all been modified to utilise the concrete font set created +< %% by Knuth. The font ccbx10 is a kludged together version of a bold +< %% face conrete font, which really is bad, but usable at the +< %% resolutions required (never use this font at high magnification if +< %% you wish to retain your presentation!). Its probably all a bit of +< %% overkill, but the definition of many of the \fam's is necessary due +< %% to the use of \bf etc, in math mode. Many of the script and +< %% scriptscript fonts will never be used, but it doesn't hurt to be +< %% sure. +< %% Any bugs, suggestions, etc, would be welcome. +< %% +< %% Steve Avery <stevea@vast.unsw.edu.au> July 27 1992 +< %% +< +< \font\titlefont=ccr7 scaled\magstep4 % title on the contents page +--- +> \font\eightrm=cmr8 +> \font\sc=cmcsc10 +> \let\mainfont=\tenrm +> \font\titlefont=cmr7 scaled\magstep4 % title on the contents page +37,68d24 +< +< \font\tenrm=ccr10 \font\eightrm = ccr8 +< \font\sevenrm = ccr7 +< \font\fiverm = ccr5 +< \font\tentt=cmtt10 \font\seventt = cmtt10 at 7pt +< \font\fivett = cmtt10 at 5pt +< \font\tensc=cccsc10 \font\sevensc = cccsc10 at 7pt +< \font\fivesc = cccsc10 at 5pt +< \font\tenit=ccmi10 \font\sevenit = ccmi10 at 7pt % Using ccti mixes +< \font\fiveit = ccmi10 at 5pt % up : and . +< \font\tensl=ccsl10 \font\sevensl = ccsl10 at 7pt +< \font\fivesl = ccsl10 at 5pt +< \font\tenbf=ccbx10 \font\sevenbf = ccbx10 at 7pt +< \font\fivebf = ccbx10 at 5pt +< +< \newfam\itfam \def\it{\fam\itfam\tenit} \textfont\itfam = \tenit +< \scriptfont\itfam = \sevenit +< \scriptscriptfont\itfam = \fiveit +< \newfam\slfam \def\sl{\fam\slfam\tensl} \textfont\slfam = \tensl +< \scriptfont\slfam = \sevensl +< \scriptscriptfont\slfam = \fivesl +< \newfam\bffam \def\bf{\fam\bffam\tenbf} \textfont\bffam = \tenbf +< \scriptfont\bffam = \sevenbf +< \scriptscriptfont\bffam = \fivebf +< +< \def\rm{\fam0 \tenrm} \textfont0=\tenrm +< \scriptfont0=\sevenrm +< \scriptscriptfont0=\fiverm +< \def\it{\fam1 \tenit} \textfont1=\tenit +< \scriptfont0=\sevenit +< \scriptscriptfont0=\fiveit +< +70,71d25 +< \let\sc\tensc +< \let\mainfont=\tenrm +430d383 +< \mainfont + +----------------<diffs between ccr10.mf and ccbx10.mf>------------- +4c4 +< font_identifier:="CCR"; font_size 10pt#; +--- +> font_identifier:="CCRBX"; font_size 10pt#; +6,7c6,7 +< u#:=20/36pt#; % unit width +< width_adj#:=0pt#; % width adjustment for certain characters +--- +> u#:=23/36pt#; % unit width +> width_adj#:=11/36pt#; % width adjustment for certain characters +9c9 +< cap_serif_fit#:=3/36pt#; % extra sidebar near uppercase serifs +--- +> cap_serif_fit#:=5/36pt#; % extra sidebar near uppercase serifs +14c14 +< cap_height#:=246/36pt#; % height of caps +--- +> cap_height#:=247/36pt#; % height of caps +16c16 +< x_height#:=165/36pt#; % height of lowercase without ascenders +--- +> x_height#:=170/36pt#; % height of lowercase without ascenders +18c18 +< bar_height#:=92/36pt#; % height of crossbar in lowercase e +--- +> bar_height#:=90/36pt#; % height of crossbar in lowercase e +23,24c23,24 +< tiny#:=11/36pt#; % diameter of rounded corners +< fine#:=6/36pt#; % diameter of sharply rounded corners +--- +> tiny#:=17/36pt#; % diameter of rounded corners +> fine#:=9/36pt#; % diameter of sharply rounded corners +26,36c26,36 +< hair#:=21/36pt#; % lowercase hairline breadth +< stem#:=25/36pt#; % lowercase stem breadth +< curve#:=27/36pt#; % lowercase curve breadth +< ess#:=25/36pt#; % breadth in middle of lowercase s +< flare#:=29/36pt#; % diameter of bulbs or breadth of terminals +< dot_size#:=38/36pt#; % diameter of dots +< cap_hair#:=21/36pt#; % uppercase hairline breadth +< cap_stem#:=27/36pt#; % uppercase stem breadth +< cap_curve#:=28/36pt#; % uppercase curve breadth +< cap_ess#:=27/36pt#; % breadth in middle of uppercase s +< rule_thickness#:=.4pt#; % thickness of lines in math symbols +--- +> hair#:=40/36pt#; % lowercase hairline breadth +> stem#:=41/36pt#; % lowercase stem breadth +> curve#:=41/36pt#; % lowercase curve breadth +> ess#:=33/36pt#; % breadth in middle of lowercase s +> flare#:=43/36pt#; % diameter of bulbs or breadth of terminals +> dot_size#:=56/36pt#; % diameter of dots +> cap_hair#:=36/36pt#; % uppercase hairline breadth +> cap_stem#:=48/36pt#; % uppercase stem breadth +> cap_curve#:=49/36pt#; % uppercase curve breadth +> cap_ess#:=40/36pt#; % breadth in middle of uppercase s +> rule_thickness#:=.6pt#; % thickness of lines in math symbols +39,42c39,42 +< bracket#:=5/36pt#; % vertical distance from serif base to tangent +< jut#:=30/36pt#; % protrusion of lowercase serifs +< cap_jut#:=32/36pt#; % protrusion of uppercase serifs +< beak_jut#:=10/36pt#; % horizontal protrusion of beak serifs +--- +> bracket#:=3/36pt#; % vertical distance from serif base to tangent +> jut#:=27/36pt#; % protrusion of lowercase serifs +> cap_jut#:=34/36pt#; % protrusion of uppercase serifs +> beak_jut#:=11/36pt#; % horizontal protrusion of beak serifs +44c44 +< vair#:=21/36pt#; % vertical diameter of hairlines +--- +> vair#:=30/36pt#; % vertical diameter of hairlines +46,49c46,49 +< bar#:=21/36pt#; % lowercase bar thickness +< slab#:=21/36pt#; % serif and arm thickness +< cap_bar#:=21/36pt#; % uppercase bar thickness +< cap_band#:=21/36pt#; % uppercase thickness above/below lobes +--- +> bar#:=31/36pt#; % lowercase bar thickness +> slab#:=31/36pt#; % serif and arm thickness +> cap_bar#:=31/36pt#; % uppercase bar thickness +> cap_band#:=31/36pt#; % uppercase thickness above/below lobes +51,53c51,53 +< serif_drop#:=5/36pt#; % vertical drop of sloped serifs +< stem_corr#:=1/36pt#; % for small refinements of stem breadth +< vair_corr#:=1/36pt#; % for small refinements of hairline height +--- +> serif_drop#:=4/36pt#; % vertical drop of sloped serifs +> stem_corr#:=2/36pt#; % for small refinements of stem breadth +> vair_corr#:=1.5/36pt#; % for small refinements of hairline height +56,57c56,57 +< o#:=4/36pt#; % amount of overshoot for curves +< apex_o#:=3/36pt#; % amount of overshoot for diagonal junctions +--- +> o#:=2/36pt#; % amount of overshoot for curves +> apex_o#:=1/36pt#; % amount of overshoot for diagonal junctions +61,64c61,64 +< math_spread:=0; % extra openness of math symbols +< superness:=8/11; % parameter for superellipses +< superpull:=1/15; % extra openness inside bowls +< beak_darkness:=4/30; % fraction of triangle inside beak serifs +--- +> math_spread:=0.5; % extra openness of math symbols +> superness:=3/4; % parameter for superellipses +> superpull:=1/18; % extra openness inside bowls +> beak_darkness:=4/25; % fraction of triangle inside beak serifs + + diff --git a/web/spiderweb/src/dijkstra/README b/web/spiderweb/src/dijkstra/README new file mode 100644 index 0000000000..ab315905a0 --- /dev/null +++ b/web/spiderweb/src/dijkstra/README @@ -0,0 +1,3 @@ +The spider file for Dijkstra's language of guarded commands isn't really +very good. One problem is that it's hard to come up with ASCII representations +of the operators Dijkstra uses. Suggestions will be appreciated. diff --git a/web/spiderweb/src/dijkstra/binary.web b/web/spiderweb/src/dijkstra/binary.web new file mode 100644 index 0000000000..b0b2ebe38d --- /dev/null +++ b/web/spiderweb/src/dijkstra/binary.web @@ -0,0 +1,267 @@ +\input itemize +\def\title{Binary tree insertion} +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont Inserting into an ordered binary tree} + \vfill} + +@*Preliminaries. +Our object is to design a verified binary tree insertion routine. +To make our lives easier, we will employ some simplifications: +\itemize +\item We will use iteration instead of recursion. +\item We will use Dijkstra's language of guarded commands +\item We will assume the existence of a tree data type, such that + if |t| is a tree either |t| is empty (|t=emptyset|) or + |t| has a left subtree, a right subtree, and a datum + (|t=<<l,d,r>>|). If |t=<<l,d,r>>|, we may write |t.l| for |l|, +|t.d| for |d|, and |t.r| for |r|. +\item We will assume sequences; if |s| is a sequence then either |s| +is empty (|s=empty|) or |s| is an element followed by a sequence (|s=z +Z|). +\item We have a membership operator |member| that will test for +membership in sequences or trees. +\enditemize +@ We want to talk about ordered binary trees, so we'll want the +notion. +@c +ordered.emptyset == true; +ordered.<<l,d,r>>==ordered.l & ordered.r &@| +(forall y:y member l: y<=d) &@| (forall y: y member r: y>=d); + +@ Our mission is to insert a datum |x| into a binary tree |T| such that +the resulting tree is ordered. +We'll do this by creating a new tree |t| which is ordered and the +membership of which is the union of the membership of |t| with +$\{x\}$. +We don't care exactly what happens if |x| is already in the tree, +although we could add a postcondition |x member T ==> T=t|. + +If we state our problem formally, we have +@c +{PRE: ordered.T} +{POST: (forall y::y member t <=> y member T | y=x) & ordered.t} + +@ Let us develop some notion of ``insertion at a node.'' +Perhaps we can use that as a guide to weakening the postcondition and +finding a loop invariant. +In essence what we will want to do is select some empty subtree of +|T|, and replace it with the tree |<<emptyset,x,emptyset>>|. +Let us generalize, and imagine that we have a variable |s| that +represents |T| and points at some node of |T| ``to be replaced.'' +Let |attach.t.s| denote the result of substituting |T| for the subtree +whose root is that node. +In particular if |s| points to the root of |T|, then |attach.t.s=t|. + +@ How can we compute |attach|? We've already seen that if |s| points +to the root of |T|, then |attach.t.s=t|. +Suppose |s| does not point to the root of |T|. +Then there is an |s`| that points to the parent of the node pointed to by +|s|. +Then, there is some |t`| such that |attach.t.s=attach.t`.s`|, and, +furthermore, either |t`=<<t,d,u>>| or |t`=<<u,d,t>>|, for some |u| and +|d|. + +So, let |s| be a sequence of records, and let each record contain: +\itemize +\item A choice (|left| or |right|) +\item A datum |d| +\item A tree |u| +\enditemize +and define +@c +attach.t.empty == t; +attach.t.(<<left,d,u>> s) == attach.<<t,d,u>>.s; +attach.t.(<<right,d,u>> s) == attach.<<u,d,t>>.s; + +@ Now we can imagine our insertion problem as being broken into two +parts. +First, we find the right place to insert |x|. +This means computing an |s| such that +|attach.<<emptyset,x,emptyset>>.s| is what we want. +Second, we have to compute |t| so that +|t=attach.<<emptyset,x,emptyset>>.s|. + +Let's imagine that we already have an |s|. +Then, we can change our postcondition by substituting |attach.t.s| for +|t|, and make that our loop invariant. +We then start out with |t=<<emptyset,x,emptyset>>|, and write a loop +that adds to |t| while removing from |s|. + +Since |s=empty| at the end of the loop, and since |attach.t.empty=t|, the +invariant conjoined with the negation of the guard gives us the +postcondition. +I leave it for the reader to show that the loop body leaves the +quantity |attach.t.s| unchanged. +@c +t := <<emptyset,x,emptyset>>; +{invariant (forall y::y member attach.t.s <=> y member T | y=x) & + ordered.(attach.t.s)} +{bound #s} +do s != empty -> + let choice, data, tree, S satisfy <<choice,data,tree>> S = s; + if choice = left -> + t,s := <<t,data,tree>>, S + [] choice = right -> + t,s := <<tree,data,t>>, S + fi +od +{POST: (forall y::y member t <=> y member T | y=x) & ordered.t} +@ It remains for us to compute a suitable |s| in the first part of the +program. +Let us write |X| for |<<emptyset,x,emptyset>>|. +Then we must assign to |s|, establishing +$$\hbox{| (forall y::y member attach.X.s <=> y member T +|| y=x) & ordered.(attach.X.s)|.% +}$$ +Since |y=x <=> y member X|, that is equivalent to +$$\hbox{ +| (forall y::y member attach.X.s <=> y member T || y member X) & +ordered.(attach.X.s)|.}$$ + +Let us imagine we have a variable |t| such that |T=attach.t.s|. +Then we need +$$\hbox{|y member attach.X.s <=> y member attach.t.s || y member X|}$$ +Now we make use of a property of |attach|, viz.\ +|(forall X::y member attach.X.s <=> y member X || y member +attach.emptyset.s)|. +(The proof is by induction on the length of |s|.) +From this we can get $$ \hbox{ +|t=emptyset ==> (forall y::y member attach.X.s <=> y member +attach.t.s || y member X)|.}\eqno(1)$$ +This suggests the following code fragment: +@c +t,s := T,empty; +{invariant T=attach.t.s & ordered.(attach.X.s)} +do t != emptyset -> + /* loop body */@; +od +{t=emptyset & T=attach.t.s & ordered.(attach.X.s)} +/* which, by (1), implies */ +{(forall y::y member attach.X.s <=> y member T | y=x) & ordered.(attach.X.s)} + +@ The question is now what loop body will maintain the invariant. +Since in our earlier loop we made |t| larger and |s| smaller, we can +imagine inverting that loop to get the new loop. +We also invert the proof that the value of |attach.t.s| remains +unchanged. + +@c +{invariant T=attach.t.s & ordered.(attach.X.s)} +do t != emptyset -> + if <<@tfirst guard@>>>@; -> + t,s := t.l, <<left,t.d,t.r>> s + [] <<@tsecond guard@>>>@; -> + t,s := t.r, <<right,t.d,t.l>> s + fi +od +@ The question remains as to what the guards must be to make the whole +thing work. +Taking the first branch, the weakest precondition of +|ordered.(attach.X.s)| is +@c +ordered.(attach.X.(<<left,t.d,t.r>> s)) +!<=> +ordered.(attach.<<X,t.d,t.r>>.s) +!<= /* by a lemma to follow */ +ordered.(attach.X.s) & +ordered.(attach.t.s) & +x <= t.d +!<= +ordered.(attach.X.s) & +ordered.T & +T=attach.t.s & +x <= t.d + +@ So if we strengthen our invariant to include |ordered.T|, we can +make the first guard |x<=t.d|, and the second guard |x>=t.d|, giving +@c +{invariant T=attach.t.s & ordered.(attach.X.s) & ordered.T} +{bound depth.t} +do t != emptyset -> + if x <= t.d -> + t,s := t.l, <<left,t.d,t.r>> s + [] x >= t.d -> + t,s := t.r, <<right,t.d,t.l>> s + fi +od +{t=emptyset & T=attach.t.s & ordered.(attach.X.s)} +/* which, by (1), implies */ +{(forall y::y member attach.X.s <=> y member T | y=x) & ordered.(attach.X.s)} + +@ Now we have to finish the proof we started earlier. +We use a clever trick involving inorder traversals. +For reference, the inorder traversal is defined by +$$\eqalign{ +|in.emptyset|&|==empty|\cr +|in.<<l,d,r>>|&|==in.l d in.r|\cr +}$$ + +Suppose that +$$ (\forall s::( \exists l,r:: (\forall t:: + |in.(attach.t.s)=l in.t r|))) \eqno (2)$$ +(which we will show in just a moment). +Given |s|, choose such an |l| and |r|. Then we have the lemma we need: +@c +ordered.(attach.<<X,t.d,t.r>>.s) +!<=> /* by (2) */ +sorted.(l x t.d in.(t.r) r) +!<= +sorted.(l x r) & +sorted.(l in.(t.l) t.d in.(t.r) r) & +x <= t.d +!<=> +ordered.(attach.X.s) & +ordered.(attach.t.s) & +x <= t.d +@ We prove (2) by induction on the length of |s|. + +If |s=empty|, then |l=empty| and |r=empty| satisfy |in.(attach.t.s)=l +in.t r|. + +If |s!=empty|, then write |s=z Z|. +Our induction hypothesis is |(exists l`,r`:: (forall +t::in.(attach.t.Z)=l` in.t r`))|. +If |z=<<left,data,tree>>|, then let |l=l`| and |r=data in.tree r`|. +Then, for any |t|, +$$\eqalign{ +in.(attach.t.s) &= +|in.(attach.t.(<<left,data,tree>> Z))|\cr +&=|in.(attach.<<t,data,tree>>.Z)|\cr +&=|l` in.t data in.tree r`|\cr +&=|l in.t r|,\cr}$$ +and that's the induction step. + + +@*The finished program. +Here we put the whole program together: +@c +{PRE:ordered.T} +t,s,X := T, empty, <<emptyset,x,emptyset>>; +{invariant T=attach.t.s & ordered.(attach.X.s) & ordered.T} +{bound depth.t} +do t != emptyset -> + if x <= t.d -> + t,s := t.l, <<left,t.d,t.r>> s + [] x >= t.d -> + t,s := t.r, <<right,t.d,t.l>> s + fi +od; +{(forall y::y member attach.X.s <=> y member T | y=x) & ordered.(attach.X.s)} +t := X; +{invariant (forall y::y member attach.t.s <=> y member T | y=x) & + ordered.(attach.t.s)} +{bound #s} +do s != empty -> + let choice, data, tree, S satisfy <<choice,data,tree>> S = s; + if choice = left -> + t,s := <<t,data,tree>>, S + [] choice = right -> + t,s := <<tree,data,t>>, S + fi +od +{POST: (forall y::y member t <=> y member T | y=x) & ordered.t} +@*Index. + + diff --git a/web/spiderweb/src/dijkstra/d.spider b/web/spiderweb/src/dijkstra/d.spider new file mode 100644 index 0000000000..1ee5199b4f --- /dev/null +++ b/web/spiderweb/src/dijkstra/d.spider @@ -0,0 +1,155 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language Dijkstra + +at_sign @ + +comment begin <"#"> end newline + +default translation <*> mathness yes + +token identifier category math mathness yes +token number category math mathness yes +token newline category ignore_scrap mathness maybe translation <> +token pseudo_semi category semi mathness maybe translation <> + +module definition math use math + +token + category unorbinop +token - category unorbinop +token * category binop +token / category binop +token < category binop +token > category binop +token = category binop +token . category binop +token , category binop translation <",\\,"> +token : category binop +token :: category binop translation <"\\CC"> +token ! category unop translation <"\\lnot"> +token & category binop translation <"\\land"> +token || category binop translation <"\\lor"> +token | category unop +token ( category open +token [ category open +token ) category close +token ] category close +token ` category unop translation <"'"> mathness yes +token { translation <"\\{"> category lbrace +token } translation <"\\}"> category close +token ; category semi +token # category unop translation <"\\#"> +token := category binop translation <"\\CE"> +token != name not_eq translation <"\\I"> category binop +token <= name lt_eq translation <"\\L"> category binop +token >= name gt_eq translation <"\\G"> category binop +token == name eq_eq translation <"\\S"> category binop +token <=> translation <"\\IFF"> category binop +token <-> translation <"\\IFF"> category binop +token >> translation <"\\rangle"> category close +token << translation <"\\langle"> category open +token [] category box translation <"[]"> +# two-characer tokens must have a translation!!!! FIX! +token -> category arrow translation <"\\RA"> +token => category binop translation <"\\RA"> +token ==> category binop translation <"\\LRA"> +token --> category arrow translation <"\\RA"> + +# The following tokens are used in writing proofs +token !<=> category shout translation <"\\IFF"> +token !<= category shout translation <"\\FF"> +token !== category shout translation <"\\S"> + +math <indent-force> shout <outdent-force> math --> math + + +macros begin +\def\LRA{\Longrightarrow} +\def\IFF{\Longleftrightarrow} +\def\FF{\Longleftarrow} +\def\DEF{\buildrel\triangle\over=} +\def\CE{\mathrel{{:}{=}}} +\def\CC{\mathrel{{:}{:}}} +\let\RA\rightarrow +\let\openbraces=\{ +\let\closebraces=\} +\def\{{\ifmmode\openbraces\else$\openbraces$\fi} +\def\}{\ifmmode\closebraces\else$\closebraces$\fi} +macros end + + +ilk if_like category if +ilk fi_like category fi + +reserved if ilk if_like +reserved fi ilk fi_like +reserved do ilk if_like +reserved od ilk fi_like + +ilk unop_like category unop translation <*-"\\"-space> +reserved let ilk unop_like +reserved invariant ilk unop_like +reserved bound ilk unop_like + +ilk binop_like category binop translation <"\\"-space-*-"\\"-space> +reserved satisfy ilk binop_like +reserved sat ilk binop_like + + +default mathness yes + +ilk math_like category math +reserved true ilk math_like +reserved false ilk math_like + +ilk member_like category math translation <"\\member"> +reserved member ilk member_like +macros begin +\def\member{\mathbin{\in}} +macros end + +ilk empty_like category math translation <"\\varepsilon"> mathness yes +reserved empty ilk empty_like + +ilk emptyset_like category math translation <"\\emptyset"> mathness yes +reserved emptyset ilk emptyset_like + +ilk cross_like category unop translation <"\\times"> +reserved cross + +ilk forall_like category unop translation <"\\forall"> +reserved forall + +ilk exists_like category unop translation <"\\exists"> +reserved exists + +ilk number_like category unop translation <"\\number"> +reserved number +macros begin +\def\number{{\bf N}} +macros end + + + + +math <"\\"-space> math --> math +math (binop|unorbinop) math --> math +math unop --> math +(unop|unorbinop) math --> math + +math semi <force> --> unop +math <force> lbrace --> lbrace +lbrace math close --> math +# lbrace math close <force> --> unop + +open math close --> math +open close --> math + +? ignore_scrap --> #1 + +if <"\\"-space> math arrow <indent-force> --> ifbegin +ifbegin math <outdent-force> box --> if +ifbegin math <outdent-force> fi --> math + + diff --git a/web/spiderweb/src/dijkstra/make b/web/spiderweb/src/dijkstra/make new file mode 100644 index 0000000000..2ddee7c9f9 --- /dev/null +++ b/web/spiderweb/src/dijkstra/make @@ -0,0 +1,2 @@ +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype` \ + THETANGLE=dtangle THEWEAVE=dweave SPIDER=d.spider $* diff --git a/web/spiderweb/src/dijkstra/sp.web b/web/spiderweb/src/dijkstra/sp.web new file mode 100644 index 0000000000..9725b2ac10 --- /dev/null +++ b/web/spiderweb/src/dijkstra/sp.web @@ -0,0 +1,28 @@ +@*Dijkstra's shortest path. +Obviously the way to prove Dijkstra's algorithm is the way Dijsktra +would do it himself. +Consider +@u +@<Set |d[u]| to all $\infty$ for all |u| in |V| @>@; +d[v] := 0; +W := {v}; +@<For each |u| in |V-W| and $(v,u) \in E$ + let |d[u]| be the weight of $(v,u)$@>@; +{@tinvariant: $\forall u \in W$, + $d[u]$ is the shortest distance from $v$ to $u$@> & + @t$\forall u \in V-W$, $d[u] } +do |W| != |V| --> + @<Let |u| be a vertex in |V-W| with |d[u]| as small as possible@>@; + @<For each |w| in |V-W| and $(u,w) \in E$@>@; + if d[w] <= d[u] + c(u,w) --> skip + [] d [w] >= d[u] + c(u,w) --> d[w] := d[u] + c(u,w) + fi; + W := W @t$\cup$@> {u} +od + +@*Index. + + + + + diff --git a/web/spiderweb/src/kelem/ac.spider b/web/spiderweb/src/kelem/ac.spider new file mode 100644 index 0000000000..d65ef11e48 --- /dev/null +++ b/web/spiderweb/src/kelem/ac.spider @@ -0,0 +1,496 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language AC extension ac + +at_sign @ + +comment begin <"/*"> end <"*/"> + +default translation <*> mathness yes + +token identifier category simp mathness yes +token number category math mathness yes +token newline category newline mathness maybe translation <> +token pseudo_semi category semi mathness maybe translation <"\\relax"> + +module definition stmt use math + +token + category unorbinop +token - category unorbinop +token * category unorbinop translation <"{*}"> +token / category dot +token < category less translation <> +token > category greater translation <> +token := category equals translation <"\\leftarrow"> +token . category dot +token ~ category unop translation <"\\TI"> +token & category unorbinop translation <"\\amp"> +token ^ translation <"\\^"> category binop +token | category binop +token ? translation <"\\?"> category question +token % translation <"\\%"> category binop +token # translation <"\\#"> category sharp +token ! category unop translation <"\\neg"> +token \ category backslash translation <"\\backslash"> +token ( category open +token ) category close +token [ category open +token ] category close +token { translation <"\\{"-indent> category lbrace +token } translation <"\\}"> category rbrace +token , category comma translation <",\\;"> +token ; category semi +token : category colon +token ++ category unop translation <"\\PP"> +token -- category unop translation <"\\MM"> +token != translation <"\\I"> category binop +token <= translation <"\\L"> category binop +token >= translation <"\\G"> category binop +token = translation <"\\S"> category binop +token && translation <"\\W"> category binop +token || translation <"\\V"> category binop +token -> translation <"\\MG"> category binop +token >> translation <"\\GG"> category binop +token << translation <"\\LL"> category binop + +macros begin +\def\CC{\mathrel{:{:}}} +\def\CCE{\mathrel{:{:}=}} +\def\FE{\mathrel{/=}} +\def\PP{\mathord{++}} +\def\PE{\mathrel{+=}} +\def\MM{\mathord{--}} +\def\ME{\mathrel{-=}} +\def\MG{\mathrel{\to}} +\def\GG{\mathrel{>\!>}} +\def\LL{\mathrel{<\!<}} +\def\TE{\mathrel{\ast=}} +\def\CE{\mathrel{\%=}} +\def\HE{\mathrel{\uparrow=}} +\def\AE{\mathrel{\amp=}} +\def\OE{\mathrel{|=}} +\let\openbraces=\{ +\let\closebraces=\} +\def\{{\ifmmode\openbraces\else$\openbraces$\fi} +\def\}{\ifmmode\closebraces\else$\closebraces$\fi} +\def\?{\mathrel?} +\def\s{\ } +macros end + +default translation <*-"\\"-space> + +ilk case_like category case +ilk int_like category decl_head translation <*> +ilk else_like category else +ilk enum_like category enum +ilk if_like category if +ilk for_like category for +ilk do_like category do +ilk sizeof_like category sizeof +ilk struct_like category struct +ilk switch_like category switch +ilk typedef_like category typedef +ilk IF_like category IF mathness no translation <force-"\\&{IF}"-space-indent> mathness no +ilk THEN_like category THEN translation <outdent-force-"\\&{THEN}"-space-indent> mathness no +ilk ELIF_like category ELIF translation <outdent-force-"\\&{ELIF}"-space-indent> mathness no +ilk ELSE_like category ELSE translation <outdent-force-"\\&{ELSE}"-space-indent> mathness no +ilk FI_like category FI translation <outdent-force-"\\&{FI}"-force> mathness no +ilk BEGIN_like category BEGIN translation <force-"\\&{BEGIN}"-force-indent> mathness no +ilk END_like category END translation <outdent-force-"\\&{END}"-force> mathness no +ilk WHILE_like category WHILE translation <force-"\\&{WHILE}"-space-indent> mathness no +ilk FOR_like category FOR translation <force-"\\&{FOR}"-space-indent> mathness no +ilk AS_like category AS +ilk EXEC_like category EXEC +ilk DO_like category DO translation <outdent-force-"\\&{DO}"-space-indent> mathness no +ilk OD_like category OD translation <outdent-force-"\\&{OD}"-force> mathness no +ilk SWITCH_like category SWITCH translation <force-"\\&{SWITCH}"-space-indent> mathness no +ilk IN_like category IN mathness no translation <space-"\\&{IN}"-force> +ilk CASE_like category CASE translation <outdent-force-"\\&{CASE}"-space-indent> mathness no +ilk DEFAULT_like category DEFAULT translation <force-outdent-"\\&{DEFAULT}"-space-indent> mathness no +ilk BREAK_like category BREAK translation <force-"\\&{BREAK}"-space> mathness no +ilk CONTINUE_like category CONTINUE translation <force-"\\&{CONTINUE}"-force> mathness no +ilk NI_like category NI translation <outdent-force-"\\&{NI}"-force> mathness no +ilk unop_like category unop translation <break_space-*-break_space> +ilk binop_like category binop + +default translation <*> + +reserved auto ilk int_like +reserved break ilk case_like +reserved case ilk case_like +reserved char ilk int_like +reserved const ilk int_like +reserved continue ilk case_like +reserved default ilk case_like +reserved do ilk do_like +reserved double ilk int_like +reserved else ilk else_like +reserved enum ilk enum_like +reserved ENUM ilk enum_like +reserved extern ilk int_like +reserved float ilk int_like +reserved for ilk for_like +reserved goto ilk case_like +reserved if ilk if_like +reserved int ilk int_like +reserved long ilk int_like +reserved register ilk int_like +reserved return ilk case_like +reserved short ilk int_like +reserved signed ilk int_like +reserved sizeof ilk sizeof_like +reserved static ilk int_like +reserved struct ilk struct_like +reserved switch ilk switch_like +reserved typedef ilk typedef_like +reserved union ilk struct_like +reserved unsigned ilk int_like +reserved void ilk int_like +reserved volatile ilk int_like +reserved while ilk for_like + +reserved SIZEOF ilk sizeof_like +reserved STRUCT ilk struct_like +reserved TYPEDEF ilk typedef_like +reserved UNION ilk struct_like + +reserved AUTO ilk int_like +reserved BOOL ilk int_like +reserved CHAR ilk int_like +reserved CONST ilk int_like +reserved DOUBLE ilk int_like +reserved EXTERN ilk int_like +reserved FILE ilk int_like +reserved FLOAT ilk int_like +reserved INT ilk int_like +reserved INTERN ilk int_like +reserved LONG ilk int_like +reserved PROC ilk int_like +reserved REF ilk int_like +reserved REGISTER ilk int_like +reserved SHORT ilk int_like +reserved SIGNED ilk int_like +reserved STATIC ilk int_like +reserved STRING ilk int_like +reserved UNSIGNED ilk int_like +reserved VOID ilk int_like +reserved VOLATILE ilk int_like + +reserved AS ilk AS_like +reserved ASLONGAS ilk AS_like +reserved BEGIN ilk BEGIN_like +reserved BREAK ilk BREAK_like +reserved CASE ilk CASE_like +reserved CONTINUE ilk CONTINUE_like +reserved DEFAULT ilk DEFAULT_like +reserved DO ilk DO_like +reserved ELIF ilk ELIF_like +reserved ELSE ilk ELSE_like +reserved END ilk END_like +reserved EXEC ilk EXEC_like +reserved FI ilk FI_like +reserved FOR ilk FOR_like +reserved GOTO ilk case_like +reserved IF ilk IF_like +reserved IN ilk IN_like +reserved NI ilk NI_like +reserved OD ilk OD_like +reserved RETURN ilk case_like +reserved SWITCH ilk SWITCH_like +reserved THEN ilk THEN_like +reserved WHILE ilk WHILE_like + +reserved TRUE ilk int_like +reserved FALSE ilk int_like +reserved NORMAL ilk int_like +reserved ERROR ilk int_like +reserved UNDEFINED ilk int_like +reserved NULL ilk int_like + +reserved CONT ilk unop_like +reserved NOT ilk unop_like +reserved INCR ilk unop_like +reserved DECR ilk unop_like +reserved ADDR ilk unop_like +reserved MOD ilk binop_like +reserved ANDIF ilk binop_like +reserved ORIF ilk binop_like +reserved AND ilk binop_like +reserved OR ilk binop_like +reserved EXCLOR ilk binop_like +reserved XOR ilk binop_like +reserved COMPLEMENT ilk unop_like +reserved LSHIFT ilk unop_like +reserved RSHIFT ilk unop_like +reserved ASSERT ilk int_like + +# we indulge in a trick to avoid treating +# ASCII (*fp)(); +# as a statement (function call). We use instead +# ASCII ===> (*fp)(); +token ===> translation <"\\relax"> tangleto <space> category decl_head + + +# +? ignore_scrap --> #1 +# dropped, because we've overflowed yacc! +#### DON'T DO THIS! it makes it impossible to add translation on the left +#### ignore_scrap ? --> #2 + + +# because of declarations, we have to be very careful about converting +# simp to math + +(math|simp) unop --> math +math (binop|unorbinop) (math|simp) --> math +math comma <opt-9> (math|simp) --> math +# we're not allowed math simp --> statement because math simp could be fn_decl +math math --> math +(math|simp) semi --> stmt +# so to hack the omission above, we include (usually a cast) +math <"\\"-space> stmt --> stmt + +(open|simpopen|question|unop|unorbinop|case) [ simp ] --> (open|simpopen|question|unop|unorbinop|case) math +[ simp ] binop --> math binop +# old: +# [ simp ] equals --> math equals +# math [ equals ] --> math binop + +simp* colon --> tag + +# can't have simp open --> open because that causes ( to eat all id's to its left. +simp open --> simpopen + +(open|simpopen) math close --> math +(open|simpopen) <"\\,"> close --> math +# following needed for for statements +open stmt <"\\"-space> --> open + +# here we try to deal with casts and argument lists, e.g. +# (ASCII *) malloc(sizeof (ASCII *)); +# char *malloc(int); + +# If the type is predefined, we know we have a cast +(open|simpopen) decl_head close --> cast +(open|simpopen) [ decl_head (unorbinop|math|simp) ] --> (open|simpopen) decl_head +(open|simpopen) decl_head comma --> arglist +arglist (decl_head|unorbinop|math) --> arglist +arglist close --> math + +# and here are some common cases of casts with non-predefined types +# for other cases you'll have to use "declares" +(open|simpopen) math <"\\"-space> unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop unorbinop unorbinop comma --> arglist +(open|simpopen) math <"\\"-space> unorbinop close --> cast +(open|simpopen) math <"\\"-space> unorbinop unorbinop close --> cast +(open|simpopen) math <"\\"-space> unorbinop unorbinop unorbinop close --> cast + +# the math here seems to be a cast. We don't convert to cast because it looks +# too much like a cycle +(open|simpopen) [ math <"\\"-space> simp ] --> (open|simpopen) math + +# Here is the destiny of casts +cast <"\\"-space> (math|simp) --> math +cast (newline|ignore_scrap) --> cast +cast --> math + + + +question math colon --> binop + +unop math --> math +<"{"> unorbinop <"}"> math --> math +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +sizeof (math|simp) --> math + +(simp|decl_head) <"\\"-space> decl_head --> decl_head +[ simp ] math (equals|comma|semi) --> decl_head math (equals|comma|semi) +[ (decl_head|simp) simp ] (simp|math) --> decl_head (simp|math) +(simp|decl_head) <"\\"-space> (simp|math)* comma --> decl_head +(simp|decl_head) <"\\"-space> (simp|math)* semi --> decl +(simp|decl_head) <"\\"-space> (simp|math)* equals --> decl_equals +decl_equals math comma --> decl_head +decl_equals math semi --> decl +decl_equals [ simp ] --> decl_equals math + +struct simp* <"\\"-space> lbrace --> structbrace +struct lbrace --> structbrace +structbrace [ simp ] --> structbrace decl_head +structbrace <force> decl --> structbrace +structbrace <outdent-force> rbrace --> struct_head +[ struct_head ] simp --> decl_head simp +# some people say e.g. struct blah {...}; is this K&R? +struct_head semi --> decl +struct [ simp (newline|ignore_scrap) ] --> struct simp +struct simp --> decl_head +decl_head <"\\"-space> struct --> struct + +# enumeration types are like structures and unions, but they have math +# instead of many decls... +enum simp* <"\\"-space> lbrace --> enumbrace +enum lbrace --> enumbrace +enumbrace math <outdent> rbrace --> enum_head +[ enum_head ] simp --> decl_head simp +enum_head semi --> decl +enum [ simp (newline|ignore_scrap) ] --> enum simp +enum simp --> decl_head +decl_head <"\\"-space> enum --> enum + +typedef [ simp ] --> typedef decl_head +typedef decl --> decl + + + + +[ math* <indent> ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +[ (simp|decl_head) <"\\"-space> math* <indent> ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +fn_decl <force> decl --> fn_decl +# The following statment will always have braces and never be tagged +fn_decl <outdent-force> stmt --> function +# include stmt here to cover module definition +(stmt|decl|function) <big_force> function --> function +function <big_force> decl --> decl + +(stmt|decl) <force> decl --> decl +decl <big_force> stmt --> stmt +decl <outdent-big_force> tagged_stmt --> stmt + + +BEGIN stmt <force> --> BEGIN +BEGIN END --> stmt +BEGIN math END --> stmt +lbrace <outdent-force> rbrace --> stmt +lbrace <force> stmt --> lbrace +lbrace <outdent-force> tagged_stmt --> lbrace +lbrace (math|simp) <outdent> rbrace --> math + +# if math can be followed by a brace, or no. +# ifmath and ifbrace can have an attached else or else if clause +# else, for, and while are formatted like if, but can't have an +# attached else clause, so we use formath and forbrace + +if math --> ifmath +ifmath <"\\"-space> lbrace --> ifbrace +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> tagged_stmt --> ifbrace +ifbrace [ rbrace (newline|ignore_scrap) ] --> ifbrace rbrace +ifbrace rbrace [ else (newline|ignore_scrap) ] --> ifbrace rbrace else +ifbrace <outdent-force> rbrace <"\\"-space> else if --> if +ifbrace <outdent-force> rbrace <"\\"-space> else lbrace --> forbrace +ifbrace <outdent-force> rbrace <"\\"-space> else --> formath +ifbrace <outdent-force> rbrace --> stmt + +# IF THEN ELSE FI +<force> IF math --> IFmath +IFmath <outdent-force> THEN --> IFTHEN +IFTHEN <indent> stmt <force> --> IFTHEN +IFTHEN <outdent-force> tagged_stmt --> IFTHEN +# IFTHEN [ (newline|ignore_scrap) ] --> IFTHEN +IFTHEN <outdent-force> ELIF <indent> math --> IFmath +IFTHEN [ ELSE (newline|ignore_scrap) ] --> IFTHEN ELSE +IFTHEN <outdent-force> ELSE <indent> --> IFELSE +IFELSE stmt --> IFELSE +IFELSE <outdent-force> tagged_stmt --> IFELSE +IFTHEN <outdent-force> FI --> stmt +IFELSE <outdent-force> FI --> stmt + +# Assume simple statements attached to if will never be tagged + +ifmath [ stmt (newline|ignore_scrap) ] --> ifmath stmt +ifmath stmt [ else (newline|ignore_scrap) ] --> ifmath stmt else +ifmath <indent-force> stmt <outdent-force> else if --> if +ifmath <indent-force> stmt <outdent-force> else lbrace --> forbrace +ifmath <indent-force> stmt <outdent-force> else --> formath +ifmath <indent-force> stmt <outdent> --> stmt + +for math --> formath +formath <"\\"-space> lbrace --> forbrace +forbrace <force> stmt --> forbrace +forbrace <outdent-force> tagged_stmt --> forbrace +forbrace <outdent-force> rbrace --> stmt +formath <indent-force> stmt <outdent> --> stmt + +# FOR AS EXEC DO OD +FOR math <space> AS math <space> EXEC math --> FORmath +FORmath DO --> FORDO +FORDO stmt <force> --> FORDO +FORDO stmt OD --> stmt +FORDO math OD --> stmt + +# WHILE DO OD +WHILE math DO --> WHILEDO +WHILEDO stmt <force> --> WHILEDO +WHILEDO stmt OD --> stmt +WHILEDO math OD --> stmt + +# SWITCH +SWITCH math IN --> Switch +Switch stmt <force> --> Switch +[ Switch math ] (CASE|BREAK|DEFAULT|NI) --> Switch (CASE|BREAK|DEFAULT|NI) +Switch tagged_stmt <outdent-force> --> Switch +# Switch CASE tagged_stmt <force> --> Switch +Switch DEFAULT colon --> Switch +Switch CONTINUE --> Switch +Switch BREAK --> Switch +Switch stmt NI --> stmt +Switch math NI --> stmt + +# we need an extra indent for switch, becuase the cases will be backed out +switch math lbrace <indent> --> switchbrace +switchbrace <outdent-force> tagged_stmt --> switchbrace +# This next should never happen +switchbrace <force> stmt --> switchbrace +switchbrace <outdent-outdent-force> rbrace --> stmt + +# handle do-while (while has category for) +do lbrace --> dobrace +dobrace <force> stmt --> dobrace +dobrace <outdent-force> tagged_stmt --> dobrace +dobrace rbrace for --> math +do <indent-force> stmt <outdent-force> for --> math + +case semi --> stmt +CASE semi --> stmt +case math semi --> stmt +CASE math semi --> stmt +case colon --> tag +CASE colon --> tag +case math colon --> tag +CASE math colon --> tag +tag <force> tag --> tag +tag <indent-force> stmt --> tagged_stmt + +stmt <force> stmt --> stmt +stmt <outdent-force> tagged_stmt --> stmt +semi --> stmt + +# control sequence \8 puts things on the left margin +<force-"\\8"> sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +preproc backslash <force-"\\8\\hskip1em"-space> newline --> preproc +preproc <force-outdent> newline --> ignore_scrap +preproc !(less|lesssimp|backslash|newline) --> preproc +newline --> ignore_scrap + +less simp --> lesssimp +lesssimp dot simp --> lesssimp +<"\\LN"> lesssimp greater <"\\RN"> --> math +<"<"> lesssimp --> unop +less <"<"> --> binop +greater <">"> --> binop +dot --> binop + +macros begin +\let\LN\langle +\let\RN\rangle +macros end + +simp comma simp --> math + + + + + + diff --git a/web/spiderweb/src/kelem/ac_guide.web b/web/spiderweb/src/kelem/ac_guide.web new file mode 100644 index 0000000000..39e48c5555 --- /dev/null +++ b/web/spiderweb/src/kelem/ac_guide.web @@ -0,0 +1,292 @@ +%\font\em=cmmi9 +%\font\bf=cmbx9 +\def\LEQU{=\kern-2pt=} +@* Guide to Algol-like C. +This is a style guide for writing programs in Algol-like C. +Algol-like C (hereafter referred to as AC) is based on the syntax of the Algol +languages (Algol~60 and Algol~68). +AC is translated into C. + +Why AC? +AC was developed because Algol programs are more readable than C programs. +A compiler was not developed for this language +because there are plenty of good C compilers +and AC is not that different from C. + +Several things contribute to C being difficult to read. +(Even experienced hackers occasionally have lapses +and misinterpret code.) + +One is the use of lots of short symbols. +Curly braces, single and double operators, = and ==, +are used to make the language succinct, +but at the cost of readability. +As in LISP, finding a matching brace or parenthesis that is lines or pages +away is difficult. +Indenting helps. +Keywords look just like identifiers. + +Two of the symbols that are frequently confused are {\tt =} and {\tt ==}. +The former is assignment and the latter equality checking. +The argument for using these was put forth by Kernighan and Ritchie: +``Since assignment is about twice as frequent as equality testing in typical +C programs, it's appropriate that the operator be half as long.'' + +However, there is a 432~year precedent of using the symbol {\tt =} for equality. +The original rationale for using {\tt =} for equality +was given by Robert Recorde in~1557. +The explanation was +{\it ``... to auoide the tediouse repetition of these woordes: +is equalle to: I will sette as I doe often in woorke vse, +a paire of paralleles, or Gemowe lines of one lengthe, +thus: \LEQU, bicause noe .2.\ thynges, +can be moare equalle.''} +Granted, spelling is not the same, but = has served as equals in Mathematics +for centuries. +Fortran changed the meaning of {\tt =} to assignment and equality +was spelled {\tt .EQ.}. +Algol~60 reverted to {\tt =} for equality and used {\tt :=} for assignment. +This convention was followed by some of its successors: Algol~68, +Pascal, and Ada. +PL/I used {\tt =} for both assignment and equality so that one +could write confusing statements like +\hbox{\tt a = b = c;} +(compare {\tt b} with {\tt c} and assign the result to {\tt a}). + +Is it really worth using a notation that is contrary to that of the more +universally used mathematics, +and thus guaranteed to confuse novices and catch pros +off-guard in order to type {\tt =} instead of {\tt :=}? +I think adding a few characters to improve readability and understandability +is worth the time and effort. +There are over four centuries of mathematics using {\tt =} for equals. +Using {\tt =} to mean assignment is begging for confusing code. +Assignment is a relatively new concept and a new notation is warranted. +{\tt :=} has enough precedent to serve this purpose. + +Consequently, I wrote a pre-processor for C called ac68 that uses {\tt :=} for +assignment, = for equality, and has all the cumulative operators in the +style of Algol 68: {\tt +:=}, {\tt -:=}, {\tt *:=}, {\tt \&:=}, {\tt <<:=}, etc. +Unfortunately, the C and dbx messages refer to the operators that get generated. +Still, the code is a lot more readable. +Combined with Spidery WEB, the output is {\it very} readable. + +The following sections illustrate how to use the language constructs in AC. + +@c +@<Procedures and functions@>@/ +@<Conditional statements@>@/ +@<Loops@>@/ +@<Data types@>@/ + +@ Procedures and functions. +Procedures and functions begin with the word |PROC|, +followed by the type of the function, the name of the function and then +the list of arguments. +Procedures return the |VOID| type. +An example is the procedure |main|, which is required for all programs, +shown below. +Note that the C denotation for a pointer is replaced by the word |REF|, +which is short for {\bf REFERENCE}. +(Note that there is a delicate balance between making programs read as +English text and using cryptic symbols. +Abbreviations such as |PROC| for {\bf PROCEDURE} +and |REF| for {\bf REFERENCE} lie between being cryptic and being +English.) +|STRING| is used instead of C's {\tt char *} to denote a string. +|BEGIN| and |END| are used to bracket the procedure text. + +@<Procedures and functions@>= +PROC VOID main(argv, argc, env) +STRING REF argv; +INT argc; +STRING REF env; +BEGIN +END + +@ Conditional statements. +The conditional statements are |IF| and |SWITCH|, +shown below. + +@<Conditional statements@>= + + @<IF statements@>@/ + @<SWITCH statements@>@/ + +@ The |IF| statement has three parts --- +a condition (following the |IF|), +a then-part (following the |THEN|), +and an optional else-part (following the |ELSE|). +The |IF| statement ends with the |FI| keyword. +Statements are {\it separated} by semicolons. +An arbitrary number of statements may occur in the |THEN| +and |ELSE| parts, +thus it is not necessary to add braces when multiple statements are used. +(In essence, they are {\it always} there by virtue of these keywords, +but there is no performance penalty introduced by having them there.) + +The |FI| keyword shows the end of the |IF| statement +and helps when nested-|IF| statements are used. + +@<IF statements@>= +IF condition +THEN statement1; + statement2 +ELSE + statement3; + statement4 +FI + +IF condition +THEN + statement1; + statement2 +FI + +IF condition1 +THEN statements1 +ELSE IF condition2 + THEN statements2 + ELSE IF condition3 + THEN statements3 + ELSE statements4 + FI + FI +FI + +@ There is an alternate way of writing nested-|IF| statements. +As can be seen above, the indenting of nested-|IF|s can quickly +get out of hand. +An alternate way of writing this is with the |ELIF|-|THEN| keywords +shown below. +Note that only a single |FI| is needed to end the |ELIF|. + +@c +IF condition1 +THEN statements1 +ELIF condition2 +THEN statements2 +ELIF condition3 +THEN statements3 +ELSE statements4 +FI + +@ The |SWITCH| statement is the other type of conditional statement. +The |IF| statement evaluates nested alternatives sequentially, +the |SWITCH| statement evaluates multiple alternatives concurrently. +In the example below the |SWITCH| evaluates |expression|, +then checks whether it is equal to |a| or |b|. +If it is equal to one of these values, the corresponding statements are +executed. +If not, the |DEFAULT| statements are executed. + +@<SWITCH statements@>= +SWITCH expression IN +CASE a: statements_a + BREAK +CASE b: statements_b + BREAK +DEFAULT: statements_d + BREAK +NI + +@ There are two types of looping statements --- |FOR| and |WHILE|. + +@<Loops@>= +@<FOR loops@>@/ +@<WHILE loops@>@/ + +@ |FOR| loops have four parts --- a part that is executed at the +beginning of the loop, +a part to check for continuation conditions, +a part to specify code to be executed at the end of every iteration, +and the loop body, which is executed during every iteration of the loop +while the continuation condition is |TRUE|. +Each of the first three parts may contain multiple expressions +separated by commas and may include assignment operators. +The loop body may contain an arbitrary number of statements separated by +semicolons. + +@<FOR loops@>= +FOR a := initial_value, b := init_b +AS (a < terminal_value) AND expr_t +EXEC a INCR +DO + statement1; + statement2 +OD + +@ |WHILE| loops have two parts --- +a conditional part that is evaluated before every iteration +and a loop body that is executed during every iteration that the conditional +part is |TRUE|. +The loop body may contain an arbitrary number of statements separated by +semicolons. +The remainder of the loop body may be skipped by using the |CONTINUE| +statement. +The loop may be terminated by using the |BREAK| statement. + +@<WHILE loops@>= +WHILE condition1 +DO + statement1; + IF cond2 + THEN CONTINUE + ELIF cond3 + THEN BREAK + FI + statement2 +OD + +@ This section describes the data types. +With the exception of |BOOL| and |STRING|, +the data types shown below are as in C. +The data type names are in upper case to distinguish them from the variables, +which are typically written in lower case. +Structure declarations that are part of type definitions require two names +--- one for the name of the structure and one for the name of the type. +A useful style for declaring these is use the same name for both of these, +but change the capitalization. +It is encouraged to use understandable names, which often are made up of +multiple words. +These words can be separated by capitalizing the first letter of each word, +as in |AMultiWordIdentifier|. +This can be combined with underscores as in |A_Multi_Word_Identifier|. +(I find the latter more readable.) +The structure name is rarely used, +so I capitalize the {\it last} letter of each word, +as in |A_multI_worD_identifieR|. +I capitalize the first letter of each word in field names in structures +and capitalize every letter in new types, as in |NEW_TYPE|. + +@<Data types@>= +BEGIN +INT i; /* integer */ +BOOL b; /* Boolean */ +CHAR c; /* character */ +CHAR REF c, REF REF d; /* a pointer to characters and a pointer to pointers +to characters */ +STRING s := "a string of characters"; +FLOAT f; /* single-precision floating point */ +DOUBLE d; /* double-precision floating point */ +STRING foo := CONT CONT INCR argv; +LONG INT li; /* long integer */ +CONST INT ci; /* a constant integer */ +enum hue {red, green, blue }; /* an enumerated type */ +VOLATILE LONG INT clock; /* a volatile long integer */ +AUTO INT aa; /* an automatic integer */ +STATIC INT st_int; /* a static integer */ +REGISTER DOUBLE dr; /* a double-precision floating register */ +ENUM color {red, green, blue}; /* an enumerated type */ +EXTERN INT ei; /* an external integer */ +SHORT s; /* a short integer */ +SIGNED si; /* a signed integer */ +UNSIGNED usi; /* an unsigned integer */ +TYPEDEF STRUCT strucT_namE {INT Integer_1, Another_Integer; + STRING The_Name; + STRUCT REF strucT_namE;} Struct_Name, REF Struct_Ptr; +UNION {INT Look; CHAR For_The;} Union_Label; +END + +@ There are a few commonly used data values that have names. +|TRUE|, |FALSE|, |NORMAL|, |ERROR|, |UNDEFINED|, and |NULL|. diff --git a/web/spiderweb/src/kelem/indent-troubles b/web/spiderweb/src/kelem/indent-troubles new file mode 100644 index 0000000000..d31b05125a --- /dev/null +++ b/web/spiderweb/src/kelem/indent-troubles @@ -0,0 +1,40 @@ +From daisy!kelem@uunet.UU.NET Sun Aug 27 00:40:16 1989 +Received: from Princeton.EDU by notecnirp.Princeton.EDU (5.51/1.84) + id AA28138; Sun, 27 Aug 89 00:40:11 EDT +Received: from uunet.UU.NET by Princeton.EDU (5.58+++/2.22) + id AA03798; Sun, 27 Aug 89 00:35:15 EDT +Received: from daisy.UUCP by uunet.uu.net (5.61/1.14) with UUCP + id AA15680; Sun, 27 Aug 89 00:35:34 -0400 +Received: by daisy.UUCP (5.51/smail2.2/05-30-89BC) + id AA08954; Sat, 26 Aug 89 20:39:23 PDT +Received: from localhost by snidely.daisy.com (4.0/SMI-4.0) + id AA20954; Sat, 26 Aug 89 20:39:03 PDT +To: princeton.edu!nr@uunet.uu.net +Subject: trouble with indent in spider +Date: Sat, 26 Aug 89 20:39:01 -0700 +Message-Id: <20953.620192341@snidely> +From: daisy!kelem@uunet.UU.NET +Status: R + +I'm having trouble with indenting in spider. I've narrowed it down to one +construct --- enum (and ENUM which is the same ilk). The token lbrace +indents and the rule for the rbrace of the enum is supposed to outdent. +However, the .tex file doesn't have a \2 on the indent line. If I insert one +manually, it works properly by not indenting subsequent lines. + +I have enclosed the shar file for ac.spider and ac_guide.web (and the make). +If you create a spider language directory called ac and put these in there, +you should see the same results. The results are visible on page 6 of the +ac_guide print-out. Both the lines with enum and ENUM cause subsequent lines +to be indented. + +Any idea what's going on? I tried the debugging, but the manual wasn't clear +about where to put the @1, @2, and @0 --- in the .spider file? In the web +file? I tried both, but didn't see any traces. My other guess is that I didn't +see anything because there weren't any unreduced scraps. Still, it would be +nice to see if some other production was being used instead of the one I thought +it was supposed to use... + +Thanks for any help you can lend... +Steve Kelem +---- Cut Here and unpack ---- diff --git a/web/spiderweb/src/kelem/make b/web/spiderweb/src/kelem/make new file mode 100644 index 0000000000..415fd46ba8 --- /dev/null +++ b/web/spiderweb/src/kelem/make @@ -0,0 +1,2 @@ +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype` \ + THETANGLE=actangle THEWEAVE=acweave SPIDER=ac.spider $* diff --git a/web/spiderweb/src/kelem/test.web b/web/spiderweb/src/kelem/test.web new file mode 100644 index 0000000000..c5cd109cd1 --- /dev/null +++ b/web/spiderweb/src/kelem/test.web @@ -0,0 +1,19 @@ +%\font\em=cmmi9 +%\font\bf=cmbx9 +\def\LEQU{=\kern-2pt=} +@* Guide to Algol-like C. +This is a style guide for writing programs in Algol-like C. +Algol-like C (hereafter referred to as AC) is based on the syntax of the Algol +languages (Algol~60 and Algol~68). +AC is translated into C. + + +@<Data types@>= +@2 +BEGIN +INT i; /* integer */ +enum hue {red, green, blue }; /* an enumerated type */ +END + +@ There are a few commonly used data values that have names. +|TRUE|, |FALSE|, |NORMAL|, |ERROR|, |UNDEFINED|, and |NULL|. diff --git a/web/spiderweb/src/larch/l.spider b/web/spiderweb/src/larch/l.spider new file mode 100644 index 0000000000..3a275f2711 --- /dev/null +++ b/web/spiderweb/src/larch/l.spider @@ -0,0 +1,245 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language Larch extension larch + +comment begin <"%"> end newline +line begin <"%line"> + +at_sign @ + +default mathness yes + +ilk all_like category all +ilk by_like category by +ilk constrains_like category constrains +ilk converts_like category gclause +ilk div_like category binop +ilk fi_like category fi +ilk for_like category for +ilk gen_like category gen +ilk if_like category if +ilk implies_like translation <*-indent> +ilk imports_like category imports +ilk intro_like category intro translation <*-indent> +ilk is_like category is +ilk then_like category then +ilk trait_like category trait +ilk with_like category with + +reserved all +reserved assumes ilk imports_like +reserved by +reserved constrains +reserved converts ilk converts_like +reserved div ilk div_like +reserved else ilk then_like +reserved exempts +reserved fi +reserved for +reserved generated ilk gen_like +reserved if +reserved implies +reserved imports +reserved includes ilk imports_like +reserved introduces ilk intro_like +reserved is +reserved mod ilk div_like +reserved partitioned ilk gen_like +reserved rem ilk div_like +reserved so +reserved that +reserved then +reserved trait +reserved with + +ilk and_like category binop translation <"\\wedge"> mathness yes +ilk or_like category binop translation <"\\vee"> mathness yes +ilk not_like category unop translation <"\\neg"> mathness yes + +reserved and +reserved or +reserved not + +ilk forall_like category unop translation <"\\forall"> mathness yes +reserved forall + + +simp colon trait <indent> --> tbegin +tbegin ? <outdent-force> tbegin --> tbegin +tbegin <force> decl --> tbegin + +[ intro <outdent-force> ] constrains --> decl constrains +intro <force> decl --> intro +math colon --> mcolon +mcolon (simp|comma) --> mcolon +mcolon arrow simp --> decl + +imports simp with open --> sublist + +# following special for David +imports simp open --> imbrace +imbrace (math|comma) --> imbrace +imbrace close with open --> sublist +imbrace close --> decl +# end David + +imports simp --> decl + +sublist for --> subfor +sublist ? --> sublist +subfor comma --> sublist +subfor close --> decl +subfor ? --> subfor + + +constrains open --> conslist +conslist math comma <opt-5> --> conslist +conslist math close so that <indent> --> consintro + +consintro <force> decl --> consintro +[ consintro ] (implies|tbegin) --> decl (implies|tbegin) + +simp is gen by --> gclause +gclause open --> glist +glist math comma --> glist +glist math close comma <opt-5> --> gclause +# do the following because converts is also a gclause +glist math close <indent-force> exempts --> exemptions +glist math close --> decl + +exemptions math comma <opt-7> --> exemptions +exemptions math <outdent> --> decl + +for all open --> forlist +forlist (simp|comma|colon) --> forlist +forlist semi <opt-3> --> forlist +forlist close <indent> --> forintro + +[ forintro <outdent-force> ] (implies|tbegin|gclause) --> decl (implies|tbegin|gclause) +[ forintro <outdent> ] simp is gen by --> decl simp is gen by +forintro <force> (relation|decl) --> forintro +forintro <outdent-force> forintro --> forintro + +consintro <force> forintro --> consfor +consfor <outdent-force> forintro --> consfor + +[ consfor <outdent-outdent-force> ] (implies|tbegin|gclause) --> decl (implies|tbegin|gclause) +[ consfor <outdent> ] simp is gen by --> consintro simp is gen by +consfor <force> (relation|decl) --> consfor + +implies <force> (decl|relation) --> implies +[ implies ] tbegin --> decl tbegin + +math rel --> mathrel +mathrel math (binop|rel) --> mathrel +mathrel [ math open ] --> mathrel open +[ mathrel open math close ] open --> relation open +mathrel math --> relation +math open --> open +math binop math --> math +unop math --> math +open math comma --> open +open math close --> math +open [ relation ] --> open math +open [ math <"\\&{WEAVE\\_ERROR!}"> math ] --> open math +[ math ] math --> relation math + +if (math|relation) then --> if +if (math|relation) fi --> math + + +decl <force> (decl|relation) --> decl +relation <force> relation --> relation +relation <force> decl --> decl + +module definition decl use math + +token identifier category simp mathness yes +token number category math mathness yes +token newline category ignore_scrap mathness maybe translation <> +token pseudo_semi category ignore_scrap mathness maybe translation <> + +default mathness yes translation <*> + +# use backslash for subscripts +token \ category backslash translation <"_"> tangleto <"_"> mathness yes +math backslash <"{"> math <"}"> --> math + +token + category binop +token - category binop +token * category binop +token / category binop +token ** category binop translation <"\\mathbin{{*}{*}}"> +token . category binop + +token & category binop translation <"\\wedge"> +token | category binop translation <"\\vee"> +token ~ category unop translation <"\\neg"> + +token < category rel +token > category rel +token = category rel +token != translation <"\\I"> category rel +token <= translation <"\\L"> category rel +token >= translation <"\\G"> category rel +token => translation <"\\Rightarrow"> category rel + +token # translation <"\\#"> category simp +token ( category open +token [ category open +token [[ category open translation <"\\dsl"> +token {[ category open translation <"\\dcl"> +token { category open translation <"\\{"> +token << category open translation <"\\LN"> +token ) category close +token ] category close +token ]] category close translation <"\\dsr"> +token ]} category close translation <"\\dcr"> +token } category close translation <"\\}"> +token >> category close translation <"\\RN"> + +macros begin +\let\LN\langle +\let\RN\rangle +\def\dsl{[\![} +\def\dsr{]\!]} +\def\dcl{\{\![} +\def\dcr{]\!\}} +macros end + +token , category comma mathness yes translation <",\\,"> +token ; category semi +token : category colon +token -> translation <"\\MG"> category arrow +macros begin +\let\MG\rightarrow +macros end + + +### Hacks for David: is, when +default mathness yes +token <- category binop translation <"\\leftarrow"> +token .. category binop translation <".."> +token ... category ignore_scrap translation <"\\ldots"> +token /= translation <"\\I"> category rel +token ^ category hat translation <> mathness maybe +token :: category binop translation <":"> mathness maybe + +hat <"\\"-space> (simp|is) <"\\"-space> hat --> binop +simp <"\\"-space> hat hat --> unop + +open close --> math + +########################## +# the following must be last + +simp --> math + +# if semi is not in a for list, treat it as a binary operator +semi --> binop + + + +? ignore_scrap --> #1 + diff --git a/web/spiderweb/src/larch/lists.web b/web/spiderweb/src/larch/lists.web new file mode 100644 index 0000000000..8a1f2bca27 --- /dev/null +++ b/web/spiderweb/src/larch/lists.web @@ -0,0 +1,56 @@ +@*Theory of sequences. +The theory of sequences is built on the theory of stacks. +The stack theory provides most of the machinery needed for the elementary +operations on lists: |insert|, |head|, |tail|, and |is_empty|. +The sequence trait includes +additional machinery that allows easy specification of concatenation. +@c +sequence: trait + imports Stack_theory with [nil for empty_stack, + cons for push, first for top, rest for pop] + introduces + enter: C,E -> C % adds e to back of c + last: C -> E + prefix: C -> C % c with last deleted + #.[#]:C, Card -> E % indexed selection (starts at 1) + append: C,C -> C % concatenation + + constrains [C] so that C is generated by [new, insert] + C is generated by [new, enter] + C is partitioned by [first, rest, isEmpty] + C is partitioned by [last, prefix, isEmpty] + + for all [e:E] + last(enter(new,e)) = e + prefix(enter(new,e)) = new + + for all [c:C, e:E] + not isEmpty(enter(c,e)) + last(enter(c,e)) = e + prefix(enter(c,e)) = stk + + for all [c:C, e, e1: E] + insert(new,e) = enter(new,e) + insert(enter(c,e),e1) = enter(insert(c,e1),e) + + for all [c:C, i:Card] + c.[1] = first(c) + c.[i+1] = rest(c).[i] + + for all [c,c1:C, e:E] + append(c,new) = c + append(c,insert(c1,e)) = insert(append(c,c1), e) + + implies + converts [insert, first, last, rest, prefix], + [enter, first, last, rest, prefix], + [append], + [isEmpty], + [size], + [#.[#]] + + + exempts last(new), prefix(new), first(new), rest(new) +% for all [c:C], c(0) + +@*Index.
\ No newline at end of file diff --git a/web/spiderweb/src/larch/make b/web/spiderweb/src/larch/make new file mode 100644 index 0000000000..3eda1c7845 --- /dev/null +++ b/web/spiderweb/src/larch/make @@ -0,0 +1,2 @@ +/bin/make -f ../master/WebMakefile \ + THETANGLE=ltangle THEWEAVE=lweave SPIDER=l.spider $* diff --git a/web/spiderweb/src/master/Make.pretty b/web/spiderweb/src/master/Make.pretty new file mode 100644 index 0000000000..2b0b2b5820 --- /dev/null +++ b/web/spiderweb/src/master/Make.pretty @@ -0,0 +1,18 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory + +WEBDIR=/usr/norman/web/src/master + +.SUFFIXES: .ada .larch .pretty + +.ada.pretty: + cat $(WEBDIR)/webhead $*.ada $(WEBDIR)/webtail > $*.web + aweave $* + awk -f $(WEBDIR)/pretty.awk < $*.tex > $*.pretty + +.larch.pretty: + cat $(WEBDIR)/webhead $*.larch $(WEBDIR)/webtail > $*.web + lweave $* + awk -f $(WEBDIR)/pretty.awk < $*.tex > $*.pretty + diff --git a/web/spiderweb/src/master/Makefile b/web/spiderweb/src/master/Makefile new file mode 100644 index 0000000000..caa3debac1 --- /dev/null +++ b/web/spiderweb/src/master/Makefile @@ -0,0 +1,18 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory + +OBJECTDIRS=sun3 vax + +clean: + -rm -f *.tex *.dvi *.log *.wlog *~ *.toc + @-for i in $(OBJECTDIRS); do \ + rm -f $$i/*.o; \ + done + -rm -f *.o + +superclean: + -rm -f sun3/*.o vax/*.o *.o + -rm -f *.c + -rm -f *.tex *.dvi *.log *~ *.toc + diff --git a/web/spiderweb/src/master/WebMakefile b/web/spiderweb/src/master/WebMakefile new file mode 100644 index 0000000000..e6d4c84905 --- /dev/null +++ b/web/spiderweb/src/master/WebMakefile @@ -0,0 +1,146 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates. +# To be used for research purposes only. +# For more information, see file COPYRIGHT in the parent directory. + +HOME=/u/norman# # Make no longer inherits environment vars + +THETANGLE=tangle +THEWEAVE=weave +SPIDER=any.spider +# +DVI=dvi +CFLAGS=-DDEBUG -g -DSTAT + +# CPUTYPE is a grim hack that attempts to solve the problem of multiple +# cpus sharing a file system. In my environment I have to have different +# copies of object and executable for vax, sun3, next, iris, and other +# cpu types. If you will be using Spidery WEB in a homogenous processor +# environment, you can just set CPUTYPE to a constant, or eliminate it +# entirely. +# +# In my environment, the 'cputype' program returns a string that +# describes the current processor. That means that the easiest thing +# for you to do is to define a 'cputype' program that does something +# sensible. A shell script that says 'echo "vax"' is fine. + +CPUTYPE=`cputype` + +# Change the following three directories to match your installation +# +# the odd placement of # is to prevent any trailing spaces from slipping in + +WEBROOT=$(HOME)/pu/web/spiderweb# # root of the WEB source distribution +DEST=$(HOME)/bin/$(CPUTYPE)# # place where the executables go +MACROS=$(HOME)/lib/tex/inputs/web# # place where the macros go + +MASTER=$(WEBROOT)/src/master# # master source directory +OBDIR=$(MASTER)/$(CPUTYPE)# # common object files + +TANGLESRC=tangle +CTANGLE=ceetangle -I$(MASTER) +CWEAVE=ceeweave -I$(MASTER) +AWKTANGLE=awktangle -I$(MASTER) +COMMONOBJS=$(OBDIR)/common.o $(OBDIR)/pathopen.o +COMMONC=$(MASTER)/common.c $(MASTER)/pathopen.c +COMMONSRC=$(COMMONC) $(MASTER)/spider.awk + + + +# Our purpose is to make tangle and weave + +web: tangle weave + +tangle: $(COMMONOBJS) $(TANGLESRC).o + $(CC) $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + +weave: $(COMMONOBJS) weave.o + $(CC) $(CFLAGS) -o $(DEST)/$(THEWEAVE) $(COMMONOBJS) weave.o + + +source: $(TANGLESRC).c $(COMMONSRC) # make tangle.c and common src, then clean + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.web weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + +# Here is how we make the common stuff + +$(MASTER)/common.c: $(MASTER)/common.web # no change file + $(CTANGLE) $(MASTER)/common + +$(OBDIR)/common.o: $(MASTER)/common.c $(OBDIR) + $(CC) $(CFLAGS) -c $(MASTER)/common.c + mv common.o $(OBDIR) + + +$(MASTER)/pathopen.c: $(MASTER)/pathopen.web # no change file + $(CTANGLE) $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +$(OBDIR)/pathopen.o: $(MASTER)/pathopen.c $(OBDIR) + $(CC) $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(OBDIR) + +$(OBDIR): + if /bin/test ! -d $(OBDIR) ; then mkdir $(OBDIR) ; fi + +## Now we make the tangle and weave source locally + +$(TANGLESRC).c: $(MASTER)/$(TANGLESRC).web $(MASTER)/common.h grammar.web + -/bin/rm -f $(TANGLESRC).web + ln $(MASTER)/$(TANGLESRC).web $(TANGLESRC).web +# chmod -w $(TANGLESRC).web + $(CTANGLE) $(TANGLESRC) + +weave.c: $(MASTER)/weave.web $(MASTER)/common.h grammar.web + -/bin/rm -f weave.web + ln $(MASTER)/weave.web weave.web +# chmod -w weave.web + $(CTANGLE) weave + +## Here's where we run SPIDER to create the source + +grammar.web: $(MASTER)/cycle.awk $(MASTER)/spider.awk $(SPIDER) + echo "date" `date` | cat - $(SPIDER) | awk -f $(MASTER)/spider.awk + cat $(MASTER)/transcheck.list trans_keys.unsorted | awk -f $(MASTER)/transcheck.awk + awk -f $(MASTER)/cycle.awk < cycle.test + sort *.unsorted | awk -f $(MASTER)/nodups.awk + mv *web.tex $(MACROS) + +## We might have to make spider first. + +$(MASTER)/spider.awk: $(MASTER)/spider.web + $(AWKTANGLE) $(MASTER)/spider + mv cycle.awk nodups.awk transcheck.awk $(MASTER) + rm junk.list + + +# $(MASTER)/cycle.awk: $(MASTER)/cycle.web # making spider also makes cycle +# $(AWKTANGLE) $(MASTER)/cycle + + +# This cleanup applies to every language + +clean: + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.* weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + + + +# booting the new distribution +boot: + if [ ! -d $(OBDIR) ]; then mkdir $(OBDIR); fi + cd ../master; rm -f *.o; for i in $(COMMONC); do \ + $(CC) $(CFLAGS) -c $$i; \ + mv *.o $(OBDIR) ; \ + done; cd ../c + $(CC) $(CFLAGS) -c $(TANGLESRC).c; \ + $(CC) $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + + diff --git a/web/spiderweb/src/master/common.c b/web/spiderweb/src/master/common.c new file mode 100644 index 0000000000..62d062cf27 --- /dev/null +++ b/web/spiderweb/src/master/common.c @@ -0,0 +1,1001 @@ +/*1:*/ +#line 49 "/u/norman/pu/web/dist/src/master/common.web" + +#include<stdio.h> +#ifdef MSDOS +#define index strchr +#endif + +/*3:*/ +#line 71 "/u/norman/pu/web/dist/src/master/common.web" + +extern char the_at_sign; + + +/*:3*//*65:*/ +#line 1052 "/u/norman/pu/web/dist/src/master/common.web" +extern char C_file_extension[]; +#line 1053 "/u/norman/pu/web/dist/src/master/common.web" + +/*:65*/ +#line 55 "/u/norman/pu/web/dist/src/master/common.web" + +/*9:*/ +#line 197 "/u/norman/pu/web/dist/src/master/common.web" +char setting_up; +#line 198 "/u/norman/pu/web/dist/src/master/common.web" + +/*:9*/ +#line 56 "/u/norman/pu/web/dist/src/master/common.web" + +/*4:*/ +#line 75 "/u/norman/pu/web/dist/src/master/common.web" + +#line 76 "/u/norman/pu/web/dist/src/master/common.web" +typedef short boolean; +typedef char unsigned eight_bits; +boolean program; + +/*:4*//*6:*/ +#line 159 "/u/norman/pu/web/dist/src/master/common.web" + +typedef char ASCII; +typedef char outer_char; + +/*:6*//*7:*/ +#line 167 "/u/norman/pu/web/dist/src/master/common.web" + +#line 168 "/u/norman/pu/web/dist/src/master/common.web" +ASCII xord[127+1]; +outer_char xchr[128]; + +/*:7*//*12:*/ +#line 259 "/u/norman/pu/web/dist/src/master/common.web" + +ASCII buffer[500]; +ASCII *buffer_end= buffer+200-2; +ASCII *limit; +ASCII *loc; + +/*:12*//*14:*/ +#line 312 "/u/norman/pu/web/dist/src/master/common.web" + +int include_depth; +FILE *file[10]; +FILE *change_file; +char file_name[10][60]; + +char change_file_name[60]; +int line[10]; +int change_line; +boolean input_has_ended; +boolean changing; + +/*:14*//*26:*/ +#line 501 "/u/norman/pu/web/dist/src/master/common.web" + +typedef unsigned short sixteen_bits; +sixteen_bits module_count; +boolean changed_module[2000]; +boolean print_where= 0; + +/*:26*//*37:*/ +#line 638 "/u/norman/pu/web/dist/src/master/common.web" + +typedef struct name_info{ +ASCII *byte_start; + /*41:*/ +#line 677 "/u/norman/pu/web/dist/src/master/common.web" + +#line 678 "/u/norman/pu/web/dist/src/master/common.web" +struct name_info *link; + +/*:41*//*48:*/ +#line 767 "/u/norman/pu/web/dist/src/master/common.web" + +union{ +struct name_info *Rlink; + +eight_bits Ilk; +}dummy; + +/*:48*//*55:*/ +#line 906 "/u/norman/pu/web/dist/src/master/common.web" + +#line 907 "/u/norman/pu/web/dist/src/master/common.web" +ASCII *equiv_or_xref; + +/*:55*/ +#line 641 "/u/norman/pu/web/dist/src/master/common.web" + +}name_info; +typedef name_info *name_pointer; +ASCII byte_mem[90000]; +ASCII *byte_mem_end= byte_mem+90000-1; +name_info name_dir[4000]; +name_pointer name_dir_end= name_dir+4000-1; + +/*:37*//*39:*/ +#line 663 "/u/norman/pu/web/dist/src/master/common.web" + +name_pointer name_ptr; +ASCII *byte_ptr; + +/*:39*//*42:*/ +#line 690 "/u/norman/pu/web/dist/src/master/common.web" + +typedef name_pointer *hash_pointer; +name_pointer hash[353]; +hash_pointer hash_end= hash+353-1; +hash_pointer h; + +/*:42*//*56:*/ +#line 926 "/u/norman/pu/web/dist/src/master/common.web" + +int history= 0; + +/*:56*//*64:*/ +#line 1039 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1040 "/u/norman/pu/web/dist/src/master/common.web" +int argc; +char * *argv; +char C_file_name[60]; +char tex_file_name[60]; +int no_xref; + +/*:64*//*75:*/ +#line 1165 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1166 "/u/norman/pu/web/dist/src/master/common.web" +FILE *C_file; +FILE *tex_file; + +/*:75*/ +#line 57 "/u/norman/pu/web/dist/src/master/common.web" + +/*5:*/ +#line 86 "/u/norman/pu/web/dist/src/master/common.web" +int phase; +#line 87 "/u/norman/pu/web/dist/src/master/common.web" + +/*:5*//*15:*/ +#line 334 "/u/norman/pu/web/dist/src/master/common.web" + +ASCII change_buffer[200]; +ASCII *change_limit; + +/*:15*//*30:*/ +#line 536 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1 "pathopen.h" + +#line 187"/u/nr/web/src/master/pathopen.web" + +#line 188"/u/nr/web/src/master/pathopen.web" +void pathaddname(); +void pathaddpath(); +void pathreset(); +FILE *pathopen(); + +#line 538 "/u/norman/pu/web/dist/src/master/common.web" +/*:30*//*50:*/ +#line 792 "/u/norman/pu/web/dist/src/master/common.web" + +name_pointer install_node(); + +/*:50*/ +#line 58 "/u/norman/pu/web/dist/src/master/common.web" + +/*8:*/ +#line 183 "/u/norman/pu/web/dist/src/master/common.web" + +#line 184 "/u/norman/pu/web/dist/src/master/common.web" +common_init() +{ +strncpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ",128); +/*11:*/ +#line 238 "/u/norman/pu/web/dist/src/master/common.web" + + +/*:11*/ +#line 188 "/u/norman/pu/web/dist/src/master/common.web" +; +/*10:*/ +#line 202 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 203 "/u/norman/pu/web/dist/src/master/common.web" +int i; +for(i= 0;i<=127;i++) +xord[i]= 32; +for(i= 1;i<127;i++)xord[xchr[i]]= i; +} + +/*:10*/ +#line 189 "/u/norman/pu/web/dist/src/master/common.web" +; +/*40:*/ +#line 667 "/u/norman/pu/web/dist/src/master/common.web" + +#line 668 "/u/norman/pu/web/dist/src/master/common.web" +name_dir->byte_start= byte_ptr= byte_mem; +name_ptr= name_dir+1; +name_ptr->byte_start= byte_mem; + +/*:40*//*43:*/ +#line 698 "/u/norman/pu/web/dist/src/master/common.web" + +#line 699 "/u/norman/pu/web/dist/src/master/common.web" +for(h= hash;h<=hash_end; *h++= NULL); + +/*:43*//*49:*/ +#line 774 "/u/norman/pu/web/dist/src/master/common.web" + +#line 775 "/u/norman/pu/web/dist/src/master/common.web" +name_dir->dummy.Rlink= NULL; + +/*:49*/ +#line 190 "/u/norman/pu/web/dist/src/master/common.web" +; +setting_up= 1; +/*76:*/ +#line 1169 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1170 "/u/norman/pu/web/dist/src/master/common.web" +scan_args(); +/*28:*/ +#line 532 "/u/norman/pu/web/dist/src/master/common.web" + +#line 533 "/u/norman/pu/web/dist/src/master/common.web" +pathaddpath(getenv("WEBPATH"),':'); +/*:28*/ +#line 1171 "/u/norman/pu/web/dist/src/master/common.web" + +if(program==0){ +if((C_file= fopen(C_file_name,"w"))==NULL) +{printf("! Cannot open output file ");err_print(C_file_name);history= 3;wrap_up();}; +} +else{ +if((tex_file= fopen(tex_file_name,"w"))==NULL) +{printf("! Cannot open output file ");err_print(tex_file_name);history= 3;wrap_up();}; +} + +/*:76*/ +#line 192 "/u/norman/pu/web/dist/src/master/common.web" +; +setting_up= 0; +} + +/*:8*//*13:*/ +#line 269 "/u/norman/pu/web/dist/src/master/common.web" + +#line 270 "/u/norman/pu/web/dist/src/master/common.web" +#include<stdio.h> +input_ln(fp) +FILE *fp; +{ +register int c; +register ASCII *k; +if(feof(fp))return(0); +limit= k= buffer; +while(k<=buffer_end&&(c= getc(fp))!=EOF&&c!='\n') +if(( *(k++)= xord[c])!=32)limit= k; +if(k>buffer_end) +if((c= getc(fp))!=EOF&&c!='\n'){ +ungetc(c,fp);loc= buffer;err_print("\n! Input line too long"); + +} +if(c==EOF&&limit==buffer)return(0); + +return(1); +} + +/*:13*//*16:*/ +#line 344 "/u/norman/pu/web/dist/src/master/common.web" + +#line 345 "/u/norman/pu/web/dist/src/master/common.web" +prime_the_change_buffer() +{ +change_limit= 0; +/*17:*/ +#line 358 "/u/norman/pu/web/dist/src/master/common.web" + +#line 359 "/u/norman/pu/web/dist/src/master/common.web" +while(1){ +change_line++; +if(!input_ln(change_file))return; +if(limit<buffer+2)continue; +if(buffer[0]!=the_at_sign)continue; +/*18:*/ +#line 376 "/u/norman/pu/web/dist/src/master/common.web" + +#line 377 "/u/norman/pu/web/dist/src/master/common.web" +if(buffer[1]>=88&&buffer[1]<=90||buffer[1]==73)buffer[1]+= 122-90; + +/*:18*/ +#line 364 "/u/norman/pu/web/dist/src/master/common.web" +; +/*19:*/ +#line 381 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 382 "/u/norman/pu/web/dist/src/master/common.web" +if(buffer[1]==105){ +loc= buffer+2; +err_print("! No includes allowed in change file"); + +} +} + +/*:19*/ +#line 365 "/u/norman/pu/web/dist/src/master/common.web" +; +if(buffer[1]==120)break; +if(buffer[1]==121||buffer[1]==122){ +loc= buffer+2; +err_print("! Where is the matching @x?"); + +} +} + +/*:17*/ +#line 348 "/u/norman/pu/web/dist/src/master/common.web" +; +/*20:*/ +#line 391 "/u/norman/pu/web/dist/src/master/common.web" + +#line 392 "/u/norman/pu/web/dist/src/master/common.web" +do{ +change_line++; +if(!input_ln(change_file)){ +err_print("! Change file ended after @x"); + +return; +} +}while(limit==buffer); + +/*:20*/ +#line 349 "/u/norman/pu/web/dist/src/master/common.web" +; +/*21:*/ +#line 401 "/u/norman/pu/web/dist/src/master/common.web" + +#line 402 "/u/norman/pu/web/dist/src/master/common.web" +{ +change_limit= change_buffer-buffer+limit; +strncpy(change_buffer,buffer,limit-buffer+1); +} + +/*:21*/ +#line 350 "/u/norman/pu/web/dist/src/master/common.web" +; +} + +/*:16*//*22:*/ +#line 416 "/u/norman/pu/web/dist/src/master/common.web" + +#line 417 "/u/norman/pu/web/dist/src/master/common.web" +check_change() +{ +int n= 0; +if((change_limit-change_buffer!=limit-buffer||strncmp(buffer,change_buffer,limit-buffer)))return; +while(1){ +changing= 1;print_where= 1;change_line++; +if(!input_ln(change_file)){ +err_print("! Change file ended before @y"); + +change_limit= 0;changing= 0;print_where= 1; +return; +} +if(limit>buffer+1&&buffer[0]==the_at_sign) +/*19:*/ +#line 381 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 382 "/u/norman/pu/web/dist/src/master/common.web" +if(buffer[1]==105){ +loc= buffer+2; +err_print("! No includes allowed in change file"); + +} +} + +/*:19*/ +#line 430 "/u/norman/pu/web/dist/src/master/common.web" +; +/*23:*/ +#line 447 "/u/norman/pu/web/dist/src/master/common.web" + +#line 448 "/u/norman/pu/web/dist/src/master/common.web" +if(limit>buffer+1&&buffer[0]==the_at_sign){ +/*18:*/ +#line 376 "/u/norman/pu/web/dist/src/master/common.web" + +#line 377 "/u/norman/pu/web/dist/src/master/common.web" +if(buffer[1]>=88&&buffer[1]<=90||buffer[1]==73)buffer[1]+= 122-90; + +/*:18*/ +#line 449 "/u/norman/pu/web/dist/src/master/common.web" +; +if(buffer[1]==120||buffer[1]==122){ +loc= buffer+2;err_print("! Where is the matching @y?"); + +} +else if(buffer[1]==121){ +if(n>0){ +loc= buffer+2; +err_print("! Hmm... some of the preceding lines failed to match"); + +} +return; +} +} + +/*:23*/ +#line 432 "/u/norman/pu/web/dist/src/master/common.web" +; +/*21:*/ +#line 401 "/u/norman/pu/web/dist/src/master/common.web" + +#line 402 "/u/norman/pu/web/dist/src/master/common.web" +{ +change_limit= change_buffer-buffer+limit; +strncpy(change_buffer,buffer,limit-buffer+1); +} + +/*:21*/ +#line 433 "/u/norman/pu/web/dist/src/master/common.web" +; +changing= 0;print_where= 1;line[include_depth]++; +while(!input_ln(file[include_depth])){ +if(include_depth==0){ +err_print("! WEB file ended during a change"); + +input_has_ended= 1;return; +} +include_depth--;print_where= 1;line[include_depth]++; +} +if((change_limit-change_buffer!=limit-buffer||strncmp(buffer,change_buffer,limit-buffer)))n++; +} +} + +/*:22*//*24:*/ +#line 467 "/u/norman/pu/web/dist/src/master/common.web" + +#line 468 "/u/norman/pu/web/dist/src/master/common.web" +reset_input() +{ +limit= buffer;loc= buffer+1;buffer[0]= 32; +/*25:*/ +#line 480 "/u/norman/pu/web/dist/src/master/common.web" + +#line 481 "/u/norman/pu/web/dist/src/master/common.web" +if((file[0]= fopen(file_name[0],"r"))==NULL) +{printf("! Cannot open input file ");err_print(file_name[0]);history= 3;wrap_up();}; +if((change_file= fopen(change_file_name,"r"))==NULL) +{printf("! Cannot open change file ");err_print(change_file_name);history= 3;wrap_up();}; + +/*:25*/ +#line 471 "/u/norman/pu/web/dist/src/master/common.web" +; +line[include_depth]= 0;change_line= 0;include_depth= 0; +changing= 1;prime_the_change_buffer();changing= !changing; +limit= buffer;loc= buffer+1;buffer[0]= 32;input_has_ended= 0; +} + +/*:24*//*27:*/ +#line 507 "/u/norman/pu/web/dist/src/master/common.web" + +#line 508 "/u/norman/pu/web/dist/src/master/common.web" +get_line() +{ +restart: +if(changing)changed_module[module_count]= 1; +else/*34:*/ +#line 574 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 575 "/u/norman/pu/web/dist/src/master/common.web" +line[include_depth]++; +while(!input_ln(file[include_depth])){ +print_where= 1; +if(include_depth==0){input_has_ended= 1;break;} +else{fclose(file[include_depth]);include_depth--;line[include_depth]++;} +} +if(!input_has_ended) +if(limit==change_limit-change_buffer+buffer) +if(buffer[0]==change_buffer[0]) +if(change_limit>change_buffer)check_change(); +} + +/*:34*/ +#line 512 "/u/norman/pu/web/dist/src/master/common.web" +; +if(changing){ +/*35:*/ +#line 587 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 588 "/u/norman/pu/web/dist/src/master/common.web" +change_line++; +if(!input_ln(change_file)){ +err_print("! Change file ended without @z"); + +buffer[0]= the_at_sign;buffer[1]= 122;limit= buffer+2; +} +if(limit>buffer+1) +if(buffer[0]==the_at_sign){ +/*18:*/ +#line 376 "/u/norman/pu/web/dist/src/master/common.web" + +#line 377 "/u/norman/pu/web/dist/src/master/common.web" +if(buffer[1]>=88&&buffer[1]<=90||buffer[1]==73)buffer[1]+= 122-90; + +/*:18*/ +#line 596 "/u/norman/pu/web/dist/src/master/common.web" +; +/*19:*/ +#line 381 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 382 "/u/norman/pu/web/dist/src/master/common.web" +if(buffer[1]==105){ +loc= buffer+2; +err_print("! No includes allowed in change file"); + +} +} + +/*:19*/ +#line 597 "/u/norman/pu/web/dist/src/master/common.web" +; +if(buffer[1]==120||buffer[1]==121){ +loc= buffer+2;err_print("! Where is the matching @z?"); + +} +else if(buffer[1]==122){ +prime_the_change_buffer();changing= !changing;print_where= 1; +} +} +} + +/*:35*/ +#line 514 "/u/norman/pu/web/dist/src/master/common.web" +; +if(!changing){ +changed_module[module_count]= 1;goto restart; +} +} +loc= buffer; *limit= 32; +if( *buffer==the_at_sign&&( *(buffer+1)==105|| *(buffer+1)==73)) +/*33:*/ +#line 546 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 547 "/u/norman/pu/web/dist/src/master/common.web" +ASCII *k, *j; +loc= buffer+2; +while(loc<=limit&&( *loc==32|| *loc==9|| *loc==34))loc++; +if(loc>=limit)err_print("! Include file name not given"); + +else{ +if(++include_depth<10){ +k= file_name[include_depth];j= loc; +while( *loc!=32&& *loc!=9&& *loc!=34) *k++= xchr[ *loc++]; + *k= '\0'; +if((file[include_depth]= pathopen(file_name[include_depth],"r"))==NULL){ +loc= j; +include_depth--; +err_print("! Cannot find include file on path"); + +} +else{line[include_depth]= 0;print_where= 1;} +} +else{ +include_depth--; +err_print("! Too many nested includes"); + +} +} +goto restart; +} + +/*:33*/ +#line 521 "/u/norman/pu/web/dist/src/master/common.web" +; +return(!input_has_ended); +} + +/*:27*//*32:*/ +#line 539 "/u/norman/pu/web/dist/src/master/common.web" + +#line 540 "/u/norman/pu/web/dist/src/master/common.web" +void overflow (s) +char *s; +{{{printf("\n! Sorry, capacity exceeded: ");err_print(s);history= 3;wrap_up();};};} +/*:32*//*36:*/ +#line 611 "/u/norman/pu/web/dist/src/master/common.web" + +#line 612 "/u/norman/pu/web/dist/src/master/common.web" +check_complete(){ +if(change_limit!=0){ +strncpy(buffer,change_buffer,change_limit-change_buffer+1); +limit= change_limit-change_buffer+buffer; +changing= 1;loc= change_limit; +err_print("! Change file entry did not match"); + +} +} + +/*:36*//*57:*/ +#line 940 "/u/norman/pu/web/dist/src/master/common.web" + +#line 941 "/u/norman/pu/web/dist/src/master/common.web" +err_print(s) +char *s; +{ +ASCII *k, *l; +printf("\n%s",(s==(char *)0)?"Bad error message!!!":s); +if(setting_up){ +printf("\nError occurred while scanning arguments or opening output files. "); +}else{ +/*58:*/ +#line 963 "/u/norman/pu/web/dist/src/master/common.web" + +#line 964 "/u/norman/pu/web/dist/src/master/common.web" +if(changing)printf(". (l. %d of change file)\n",change_line); +else if(include_depth==0)printf(". (l. %d)\n",line[include_depth]); +else printf(". (l. %d of include file %s)\n",line[include_depth],file_name[include_depth]); +l= (loc>=limit?limit:loc); +if(l>buffer){ +for(k= buffer;k<l;k++) +if( *k=='\t')putchar(' '); +else putchar(xchr[ *k]); +putchar('\n'); +for(k= buffer;k<l;k++)putchar(' '); +} +for(k= l;k<limit;k++)putchar(xchr[ *k]); +if( *limit==124)putchar('|'); +putchar(' '); + +/*:58*/ +#line 949 "/u/norman/pu/web/dist/src/master/common.web" +; +} +fflush(stdout);history= 2; +} + +/*:57*//*62:*/ +#line 1009 "/u/norman/pu/web/dist/src/master/common.web" + +wrap_up(){ +putchar('\n'); +/*63:*/ +#line 1017 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1018 "/u/norman/pu/web/dist/src/master/common.web" +switch(history){ +case 0:printf("(No errors were found.)\n");break; +case 1: +printf("(Did you see the warning message above?)\n");break; +case 2: +printf("(Pardon me, but I think I spotted something wrong.)\n");break; +case 3:printf("(That was a fatal error, my friend.)\n"); +} + +/*:63*/ +#line 1012 "/u/norman/pu/web/dist/src/master/common.web" +; +if(history>1)exit(1); +else exit(0); +} + +/*:62*//*66:*/ +#line 1060 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1061 "/u/norman/pu/web/dist/src/master/common.web" +scan_args() +{ +char *dot_pos, *index(); +boolean found_web= 0,found_change= 0; +no_xref= 0; +while(--argc>0){ +if( * *(++argv)!='-'){ +if(!found_web)/*67:*/ +#line 1084 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1085 "/u/norman/pu/web/dist/src/master/common.web" +{ +if(strlen( *argv)>60-5) +/*73:*/ +#line 1156 "/u/norman/pu/web/dist/src/master/common.web" +{printf("! Filename %s too long\n");err_print( *argv);history= 3;wrap_up();}; +#line 1157 "/u/norman/pu/web/dist/src/master/common.web" + +/*:73*/ +#line 1087 "/u/norman/pu/web/dist/src/master/common.web" +; +if((dot_pos= index( *argv,'.'))==NULL) +sprintf(file_name[0],"%s.web", *argv); +else{ +sprintf(file_name[0],"%s", *argv); +/*68:*/ +#line 1100 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1101 "/u/norman/pu/web/dist/src/master/common.web" +{char *p; +p= dot_pos; +while( *++p!='\0') +if( *p=='.')dot_pos= p; +} + +/*:68*/ +#line 1092 "/u/norman/pu/web/dist/src/master/common.web" + + *dot_pos= 0; +} +sprintf(tex_file_name,"%s.tex", *argv); +sprintf(C_file_name,"%s.%s", *argv,C_file_extension); +found_web= 1; +} + +/*:67*/ +#line 1069 "/u/norman/pu/web/dist/src/master/common.web" + +else if(!found_change)/*69:*/ +#line 1107 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1108 "/u/norman/pu/web/dist/src/master/common.web" +{ +if(strlen( *argv)>60-5) +/*73:*/ +#line 1156 "/u/norman/pu/web/dist/src/master/common.web" +{printf("! Filename %s too long\n");err_print( *argv);history= 3;wrap_up();}; +#line 1157 "/u/norman/pu/web/dist/src/master/common.web" + +/*:73*/ +#line 1110 "/u/norman/pu/web/dist/src/master/common.web" +; +if((dot_pos= index( *argv,'.'))==NULL) +sprintf(change_file_name,"%s.ch", *argv); +else sprintf(change_file_name,"%s", *argv); +found_change= 1; +} + +/*:69*/ +#line 1070 "/u/norman/pu/web/dist/src/master/common.web" + +else/*72:*/ +#line 1147 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1148 "/u/norman/pu/web/dist/src/master/common.web" +{ +if(program==0) +{printf("! Usage: tangle webfile[.web] [changefile[.ch]] [-Ipathname ...]\n");err_print(0);history= 3;wrap_up();} +else +{printf("! Usage: weave webfile[.web] [changefile[.ch]] [-x] [-Ipathname ...]\n");err_print( +0);history= 3;wrap_up();}; +} + +/*:72*/ +#line 1071 "/u/norman/pu/web/dist/src/master/common.web" +; +} +else/*71:*/ +#line 1132 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1133 "/u/norman/pu/web/dist/src/master/common.web" +{ +switch(( *argv)[1]){ +case'x': +no_xref= 1; +break; +case'I': +/*29:*/ +#line 534 "/u/norman/pu/web/dist/src/master/common.web" + +#line 535 "/u/norman/pu/web/dist/src/master/common.web" +pathaddname( *argv+2); +/*:29*/ +#line 1139 "/u/norman/pu/web/dist/src/master/common.web" + +break; +default: +/*74:*/ +#line 1158 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 1159 "/u/norman/pu/web/dist/src/master/common.web" +printf("! Unknown option in argument %s\n", *argv);{if(history==0)history= 1;}; +} + +/*:74*/ +#line 1142 "/u/norman/pu/web/dist/src/master/common.web" +; +break; +} +} + +/*:71*/ +#line 1073 "/u/norman/pu/web/dist/src/master/common.web" +; +} +if(!found_web)/*72:*/ +#line 1147 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1148 "/u/norman/pu/web/dist/src/master/common.web" +{ +if(program==0) +{printf("! Usage: tangle webfile[.web] [changefile[.ch]] [-Ipathname ...]\n");err_print(0);history= 3;wrap_up();} +else +{printf("! Usage: weave webfile[.web] [changefile[.ch]] [-x] [-Ipathname ...]\n");err_print( +0);history= 3;wrap_up();}; +} + +/*:72*/ +#line 1075 "/u/norman/pu/web/dist/src/master/common.web" +; +if(!found_change)/*70:*/ +#line 1117 "/u/norman/pu/web/dist/src/master/common.web" + +#line 1118 "/u/norman/pu/web/dist/src/master/common.web" +#ifdef MSDOS +strcpy(change_file_name,"NUL"); +#else +strcpy(change_file_name,"/dev/null"); +#endif +/*:70*/ +#line 1076 "/u/norman/pu/web/dist/src/master/common.web" +; +} + +/*:66*/ +#line 59 "/u/norman/pu/web/dist/src/master/common.web" +; + +/*:1*//*44:*/ +#line 703 "/u/norman/pu/web/dist/src/master/common.web" +name_pointer +#line 704 "/u/norman/pu/web/dist/src/master/common.web" + id_lookup(first,last,t) +ASCII *first; +ASCII *last; +eight_bits t; +{ +ASCII *i= first; +int h; +int l; +name_pointer p; +if(last==NULL)for(last= first; *last!='\0';last++); +l= last-first; +/*45:*/ +#line 725 "/u/norman/pu/web/dist/src/master/common.web" + +#line 726 "/u/norman/pu/web/dist/src/master/common.web" +h= *i;while(++i<last)h= (h+h+ *i)%353; + +/*:45*/ +#line 715 "/u/norman/pu/web/dist/src/master/common.web" +; +/*46:*/ +#line 731 "/u/norman/pu/web/dist/src/master/common.web" + +#line 732 "/u/norman/pu/web/dist/src/master/common.web" +p= hash[h]; +while(p&&!names_match(p,first,l,t))p= p->link; +if(p==NULL){ +p= name_ptr; +p->link= hash[h];hash[h]= p; +} + +/*:46*/ +#line 716 "/u/norman/pu/web/dist/src/master/common.web" +; +if(p==name_ptr)/*47:*/ +#line 743 "/u/norman/pu/web/dist/src/master/common.web" +{ +#line 744 "/u/norman/pu/web/dist/src/master/common.web" +if(byte_ptr+l>byte_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("byte memory");history= 3;wrap_up();};}; +if(name_ptr>=name_dir_end){{printf("\n! Sorry, capacity exceeded: ");err_print("name");history= 3;wrap_up();};}; +strncpy(byte_ptr,first,l); +(++name_ptr)->byte_start= byte_ptr+= l; +init_p(p,t); +} + +/*:47*/ +#line 717 "/u/norman/pu/web/dist/src/master/common.web" +; +return(p); +} + +/*:44*//*51:*/ +#line 795 "/u/norman/pu/web/dist/src/master/common.web" +name_pointer +#line 796 "/u/norman/pu/web/dist/src/master/common.web" + mod_lookup(k,l) +ASCII *k; +ASCII *l; +{ +short c= 2; +name_pointer p= name_dir->dummy.Rlink; +name_pointer q= name_dir; +while(p){ +c= web_strcmp(k,l+1,p->byte_start,(p+1)->byte_start); +q= p; +switch(c){ +case 0:p= p->link;continue; +case 2:p= p->dummy.Rlink;continue; +case 1:return p; +default:err_print("! Incompatible section names");return NULL; + +} +} +return(install_node(q,c,k,l-k+1)); +} + +/*:51*//*52:*/ +#line 820 "/u/norman/pu/web/dist/src/master/common.web" + +#line 821 "/u/norman/pu/web/dist/src/master/common.web" +web_strcmp(j,j1,k,k1) +ASCII *j; +ASCII *j1; +ASCII *k; +ASCII *k1; +{ +while(k<k1&&j<j1&& *j== *k)k++,j++; +if(k==k1)if(j==j1)return 1; +else return 4; +else if(j==j1)return 3; +else if( *j< *k)return 0; +else return 2; +} + +/*:52*//*53:*/ +#line 843 "/u/norman/pu/web/dist/src/master/common.web" +name_pointer +#line 844 "/u/norman/pu/web/dist/src/master/common.web" + install_node(parent,c,j,name_len) +name_pointer parent; +int c; +ASCII *j; +int name_len; +{ +name_pointer node= name_ptr; +if(byte_ptr+name_len>byte_mem_end){{printf("\n! Sorry, capacity exceeded: ");err_print("byte memory");history= 3;wrap_up();};}; +if(name_ptr==name_dir_end){{printf("\n! Sorry, capacity exceeded: ");err_print("name");history= 3;wrap_up();};}; +if(c==0)parent->link= node;else parent->dummy.Rlink= node; +node->link= NULL;node->dummy.Rlink= NULL; +init_node(node); +strncpy(byte_ptr,j,name_len); +(++name_ptr)->byte_start= byte_ptr+= name_len; +return(node); +} + +/*:53*//*54:*/ +#line 867 "/u/norman/pu/web/dist/src/master/common.web" +name_pointer +#line 868 "/u/norman/pu/web/dist/src/master/common.web" + prefix_lookup(k,l) +ASCII *k; +ASCII *l; +{ +short c= 2; +short count= 0; +name_pointer p= name_dir->dummy.Rlink; +name_pointer q= NULL; + +name_pointer r= NULL; +while(p){ +c= web_strcmp(k,l+1,p->byte_start,(p+1)->byte_start); +switch(c){ +case 0:p= p->link;break; +case 2:p= p->dummy.Rlink;break; +default:r= p;count++;q= p->dummy.Rlink;p= p->link; +} +if(p==NULL){ +p= q;q= NULL; +} +} +if(count==0)err_print("! Name does not match"); + +if(count>1)err_print("! Ambiguous prefix"); + +return(r); +} + +/*:54*/ diff --git a/web/spiderweb/src/master/common.h b/web/spiderweb/src/master/common.h new file mode 100644 index 0000000000..fdce4ce9e2 --- /dev/null +++ b/web/spiderweb/src/master/common.h @@ -0,0 +1,146 @@ +@ Here's stuff from the file |'common.web'| that has to be included in +|'tangle.web'| and |'weave.web'|. + +General stuff: + +@d tangle = 0 +@d weave = 1 + +@<Common code for \.{WEAVE} and \.{TANGLE}@>= +typedef short boolean; +typedef char unsigned eight_bits; +extern boolean program; /* \.{WEAVE} or \.{TANGLE}? */ +extern int phase; /* which phase are we in? */ + +@ @<Include files@>= +#include <stdio.h> + +@ Code related to the character set: +@d tab_mark = 011 /* ASCII code used as tab-skip */ +@d line_feed = 012 /* ASCII code thrown away at end of line */ +@d form_feed = 014 /* ASCII code used at end of page */ +@d carriage_return = 015 /* ASCII code used at end of line */ + +@<Common code...@>= +typedef char ASCII; /* type of characters inside \.{WEB} */ +typedef char outer_char; /* type of characters outside \.{WEB} */ +extern ASCII xord[]; /* specifies conversion of input characters */ +extern outer_char xchr[]; /* specifies conversion of output characters */ +ASCII mod_text[longest_name+1]; /* name being sought for */ +ASCII *mod_text_end = mod_text+longest_name; /* end of |mod_text| */ +ASCII *id_first; /* where the current identifier begins in the buffer */ +ASCII *id_loc; /* just after the current identifier in the buffer */ + +@ Code related to input routines: +Killed |buf_size|; already in weave and tangle. + +@<Common code...@>= +extern ASCII buffer[]; /* where each line of input goes */ +extern ASCII *buffer_end; /* end of |buffer| */ +extern ASCII *loc; /* points to the next character to be read from the buffer*/ +extern ASCII *limit; /* points to the last character in the buffer */ + +@ Code related to identifier and module name storage: +Killed |max_bytes|, |max_names|, and |hash_size| --- all duplicated. + +@d length(c) = ((c+1)->byte_start-(c)->byte_start) /* the length of a name */ +@d print_id(c) = ASCII_write((c)->byte_start,length((c))) + /* print identifier or module name */ +@d llink = link /* left link in binary search tree for module names */ +@d rlink = dummy.Rlink /* right link in binary search tree for module names */ +@d ilk = dummy.Ilk /* ilk in checking identifiers */ +@d root = name_dir->rlink /* the root of the binary search tree + for module names */ + +@<Common code...@>= +typedef struct name_info { + ASCII *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 module + names */ + eight_bits Ilk; /* used by identifiers in \.{WEAVE} (and for checking + macros in \.{TANGLE}?) */ + } dummy; + ASCII *equiv_or_xref; /* info corresponding to names */ +} name_info; /* contains information about an identifier or module name */ +typedef name_info *name_pointer; /* pointer into array of |name_info|s */ +typedef name_pointer *hash_pointer; +extern ASCII byte_mem[]; /* characters of names */ +extern ASCII *byte_mem_end; /* end of |byte_mem| */ +extern name_info name_dir[]; /* information about names */ +extern name_pointer name_dir_end; /* end of |name_dir| */ +extern name_pointer name_ptr; /* first unused position in |byte_start| */ +extern ASCII *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 mod_lookup(); /* finds module name */ +extern name_pointer prefix_lookup(); /* finds module name given a prefix */ + +@ 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("\n! This can't happen: ",s) +@d fatal(s1,s2) = { + printf(s1); err_print(s2); + history=fatal_message; wrap_up(); +} +@d overflow(s) = { + fatal("\n! Sorry, capacity exceeded: ",s); +} + +@<Common...@>= +extern history; /* indicates how bad this run was */ + +@ Code related to file handling: +@f line x /* make |line| an unreserved word */ +@d max_file_name_length = 60 +@d cur_file = file[include_depth] /* current file */ +@d cur_file_name = file_name[include_depth] /* current file name */ +@d web_file_name = file_name[0] /* main source file name */ +@d cur_line = line[include_depth] /* number of current line in current file */ + +@<Common code...@>= +extern include_depth; /* current level of nesting */ +extern FILE *file[]; /* stack of non-change files */ +extern FILE *change_file; /* change file */ +extern char C_file_name[]; /* name of |C_file| */ +extern char tex_file_name[]; /* name of |tex_file| */ +extern char file_name[][max_file_name_length]; + /* stack of non-change file names */ +extern char change_file_name[]; /* name of change file */ +extern line[]; /* number of current line in the stacked files */ +extern change_line; /* number of current line in change file */ +extern boolean input_has_ended; /* if there is no more input */ +extern boolean changing; /* if the current line is from |change_file| */ + +@ Code related to module numbers: +@<Common code...@>= +typedef unsigned short sixteen_bits; +extern sixteen_bits module_count; /* the current module number */ +extern boolean changed_module[]; /* is the module changed? */ +extern boolean print_where; /* tells \.{TANGLE} to print line and file info */ + +@ Code related to command line arguments: +@<Common code...@>= +extern int argc; /* copy of |ac| parameter to |main| */ +extern char **argv; /* copy of |av| parameter to |main| */ +extern no_xref; /* should \.{WEAVE} print an index? */ + +@ Code relating to output: +@d update_terminal = fflush(stdout) /* empty the terminal output buffer */ +@d new_line = putchar('\n') @d putxchar = putchar +@d ASCII_write(a,b) = fflush(stdout), write(1,a,b) /* write on the standard output */ +@d line_write(c) = write(fileno(C_file),c) /* write on the C output file */ +@d C_printf(c,a) = fprintf(C_file,c,a) +@d C_putc(c) = putc(c,C_file) + +@<Common code...@>= +FILE *C_file; /* where output of \.{TANGLE} goes */ +FILE *tex_file; /* where output of \.{WEAVE} goes */ diff --git a/web/spiderweb/src/master/common.web b/web/spiderweb/src/master/common.web new file mode 100644 index 0000000000..5a1c3fa901 --- /dev/null +++ b/web/spiderweb/src/master/common.web @@ -0,0 +1,1198 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +% This file is part of Spidery WEB + +% This program by Norman Ramsey is based on programs Silvio Levy +% and D. E. Knuth. Silvio Levy wrote most of the code. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Dec 1987 + +% Here is TeX material that gets inserted after \input webmac + +\message{OK, entering \string\batchmode...} +\batchmode + +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps +\def\cee{C} +\def\pb{$\.|\ldots\.|$} % C brackets (|...|) +\def\v{\char'174} % vertical (|) in typewriter font +\def\ceeref{{\it The C Reference Manual}} +\mathchardef\RA="3221 % right arrow +\mathchardef\BA="3224 % double arrow + +\def\title{Spidery COMMON} +\def\contentspagenumber{1} % should be odd +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont Common Code in Spidery {\ttitlefont WEB}} + \vfill +} + + +@* Introduction. This file contains code common +to both \.{TANGLE} and \.{WEAVE}, that 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 \.{WEB} to refer to either of the two component +programs, if no confusion can arise. + +Here is the overall appearance of this file: + +@u@1 +#include <stdio.h> +#ifdef MSDOS +#define index strchr +#endif + +@<External variables@>@; +@<Global variables@>@; +@<Definitions that should agree with \.{TANGLE} and \.{WEAVE}@>@; +@<Other definitions@>@; +@<Functions@>; + +@ In certain cases \.{TANGLE} and \.{WEAVE} should do almost, but not +quite, the same thing. In these case we've written common code for +both, differentiating between the two by means of the global variable +|program|. + +@d tangle = 0 +@d weave = 1 + +@ Give us an at sign that isn't always `@@': +@d at_sign = the_at_sign +@<External...@>= +extern char the_at_sign; + + +@ @<Definitions...@>= +typedef short boolean; +typedef char unsigned eight_bits; +boolean program; /* \.{WEAVE} or \.{TANGLE}? */ + +@ \.{CWEAVE} operates in three phases: first it inputs the source +file and stores cross-reference data, then it inputs the source once again and +produces the \TeX\ output file, and finally it sorts and outputs the index. +Similarly, \.{CTANGLE} operates in two phases. +The global variable |phase| tells which phase we are in. + +@<Other...@>= int phase; /* which phase are we in? */ + +@* The character set. +One of the main goals in the design of \.{WEB} has been to make it readily +portable between a wide variety of computers. Yet \.{WEB} by its very +nature must use a greater variety of characters than most computer +programs deal with, and character encoding is one of the areas in which +existing machines differ most widely from each other. + +To resolve this problem, all input to \.{WEAVE} and \.{TANGLE} is converted +to an internal seven-bit code that is essentially standard ASCII, the +``American Standard Code for Information Interchange.'' The conversion +is done immediately when each character is read in. Conversely, +characters are converted from ASCII to the user's external +representation just before they are output. + +Such an internal code can be accessed by users of \.{WEB} by means of +constructions like \.{@@`A'}, which should be distinguished from +\.{'A'}. The former is transformed by +\.{TANGLE} into an integer that is the internal code of \.A, but +the latter, a |char| constant, is not touched by +\.{WEB}, and will be interpreted by the \cee\ complier according to +the machine's character set. (Actually, of course, it gets translated +into \.{WEB}'s internal code just like any other character in the +input file, but then it gets translated back at output time.) +@^ASCII code@> + +Here is a table of the standard visible ASCII codes (\.{ } stands for +a blank space): +$$\def\:{\char\count255\global\advance\count255 by 1} +\count255='40 +\vbox{ +\hbox{\hbox to 40pt{\it\hfill0\/\hfill}% +\hbox to 40pt{\it\hfill1\/\hfill}% +\hbox to 40pt{\it\hfill2\/\hfill}% +\hbox to 40pt{\it\hfill3\/\hfill}% +\hbox to 40pt{\it\hfill4\/\hfill}% +\hbox to 40pt{\it\hfill5\/\hfill}% +\hbox to 40pt{\it\hfill6\/\hfill}% +\hbox to 40pt{\it\hfill7\/\hfill}} +\vskip 4pt +\hrule +\def\^{\vrule height 10.5pt depth 4.5pt} +\halign{\hbox to 0pt{\hskip -24pt\O{#0}\hfill}&\^ +\hbox to 40pt{\tt\hfill#\hfill\^}& +&\hbox to 40pt{\tt\hfill#\hfill\^}\cr +04&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +05&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +06&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +07&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +10&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +11&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +12&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +13&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +14&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +15&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +16&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +17&\:&\:&\:&\:&\:&\:&\:\cr} +\hrule width 280pt}$$ + +We introduce new types to distinguish between the transliterated characters +and the characters in the outside world. Let all +``interesting'' values that a |char| variable may take lie between +|first_text_char| and |last_text_char|; for the ASCII code we can +take |first_text_char=0| and |last_text_char=@'177|. We will tell \.{WEB} +to convert all input characters in this range to its own code, and balk at +characters outside the range. We make two assumptions: +|first_text_char>=0| and |char| has room for at least eight bits. +@^system dependencies@> + +@d first_text_char = 0 /* lowest interesting value of a |char| */ +@d last_text_char = @'177 /* highest interesting value of a |char| */ + +@<Definitions...@>= +typedef char ASCII; /* type of characters inside \.{WEB} */ +typedef char outer_char; /* type of characters outside \.{WEB} */ + +@ The \.{WEAVE} and \.{TANGLE} processors convert between ASCII code and +the user's external character set by means of arrays |xord| and |xchr| +that are analogous to PASCAL's |ord| and |chr| functions. + +@<Definitions...@>= +ASCII xord[last_text_char+1]; /* specifies conversion of input characters */ +outer_char xchr[@'200]; /* specifies conversion of output characters */ + +@ Every system supporting \cee\ must be able to read and write the 95 +visible characters of standard ASCII above (although not necessarily using the +ASCII codes to represent them). Conversely, these characters, plus +the newline, are sufficient to write any \cee\ program. Other +characters are desirable mainly in strings, and they can be referred +to by means of escape sequences like \.{'\t'}. + +The basic implementation of \.{WEB}, then, only has to assign an +|xord| to these 95 characters (newlines are swallowed by the reading +routines). The easiest way to do this is to assign the characters to +their positions in |xchr| and then invert the correspondence: + +@<Functions...@>= +common_init() +{ + strncpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ",@'200); + @<System-dependent parts of character set@>; + @<Invert |xchr| to get |xord|@>; + @<Initialize pointers@>; + setting_up=1; + @<Scan arguments and open output files@>; + setting_up=0; +} + +@ We use this variable to tell us what to do in |err_print|. +@<Global var...@>=char setting_up; + +@ The following system-independent code makes the |xord| array contain +a suitable inverse to the information in |xchr|. + +@<Invert |xchr|...@>= { + int i; /* to invert the correspondence */ + for (i=first_text_char; i<=last_text_char; i++) + xord[i]=@'40; /* ASCII code for space */ + for (i=1; i<@'177; i++) xord[xchr[i]]=i; +} + +@ Some \cee\ compilers, accept an extended character +set, so that one can type things like \.^^Z\ instead of \.{!=}. +If that's the case in your system, you should change this module, +assigning positions |@'1| to |@'37| in the most convenient way; +for example, at MIT you can just say +$$\hbox{|for (i=1; i<=@'37; i++) xchr[i]=i;|}$$ +since \.{WEB}'s character set is essentially identical to MIT's, +even with respect to characters less than |@'40| (see the definitions +below). If, however, the changes do not conform with these +definitions you should change the definitions as well. +@^system dependencies@> +@^notes to myself@> + +@d and_and = @'4 /* `\.{\&\&}' */ +@d tab_mark = @'11 /* ASCII code used as tab-skip */ +@d line_feed = @'12 /* ASCII code thrown away at end of line */ +@d form_feed = @'14 /* ASCII code used at end of page */ +@d carriage_return = @'15 /* ASCII code used at end of line */ +@d gt_gt = @'20 /* `\.{>>}'; this doesn't exist in MIT */ +@d lt_lt = @'22 /* `\.{<<}'; this doesn't exist in MIT */ +@d plus_plus = @'13 /* `\.{++}'; this corresponds to MIT's up-arrow */ +@d minus_minus = @'1 /* `\.{--}'; this corresponds to MIT's down-arrow */ +@d minus_gt = @'31 /* `\.{->}' */ +@d not_eq = @'32 /* `\.{!=}' */ +@d lt_eq = @'34 /* `\.{<=}' */ +@d gt_eq = @'35 /* `\.{>=}' */ +@d eq_eq = @'36 /* `\.{==}' */ +@d or_or = @'37 /* `\.{\vert\vert}' */ + +@<System-dependent parts of character set@>= /* nothing needs to be done */ + +@* Input routines. The lowest level of input to the \.{WEB} 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 translated to |ASCII| code and 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. + +We assume that none of the |ASCII| values of |*j| for |buffer<=j<limit| +is equal to 0, |@'177|, |line_feed|, |form_feed|, or |carriage_return|. +Since |buf_size| is strictly less than |long_buf_size|, +some of \.{WEB}'s routines use the fact that it is safe to refer to +|*(limit+2)| without overstepping the bounds of the array. + +@d buf_size = 200 /* for \.{WEAVE} and \.{TANGLE} */ +@d long_buf_size = 500 /* for \.{WEAVE} */ + +@<Definitions...@>= +ASCII buffer[long_buf_size]; /* where each line of input goes */ +ASCII *buffer_end=buffer+buf_size-2; /* end of |buffer| */ +ASCII *limit; /* points to the last character in the buffer */ +ASCII *loc; /* points to the next character to be read from the buffer */ + +@ In the unlikely event that you standard I/O library does not +support |feof|, |getc| and |ungetc| you may have to change things here. +@^system dependencies@> + +@<Func...@>= +#include <stdio.h> +input_ln(fp) /* copies a line into |buffer| or returns 0 */ +FILE *fp; /* what file to read from */ +{ + register int c; /* the character read */ + register ASCII *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++) = xord[c]) != @` ') limit = k; + if (k>buffer_end) + if ((c=getc(fp))!=EOF && c!='\n') { + ungetc(c,fp); loc=buffer; err_print("\n! 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 \.{WEB} should process comes from two +streams: a |web_file|, which can contain possibly nested include +commands `|@i|', and a |change_file|, which should not 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 +form the |change_file|. + +The line number of each open file is also kept for error reporting and +for the benefit of \.{TANGLE}. + +@f line x /* make |line| an unreserved word */ +@d max_include_depth = 10 /* maximum number of source files open + simultaneously, not counting the change file */ +@d max_file_name_length = 60 +@d cur_file = file[include_depth] /* current file */ +@d cur_file_name = file_name[include_depth] /* current file name */ +@d cur_line = line[include_depth] /* number of current line in current file */ +@d web_file = file[0] /* main source file */ +@d web_file_name = file_name[0] /* main source file name */ + +@<Definitions...@>= +int include_depth; /* current level of nesting */ +FILE *file[max_include_depth]; /* stack of non-change files */ +FILE *change_file; /* change file */ +char file_name[max_include_depth][max_file_name_length]; + /* stack of non-change file names */ +char change_file_name[max_file_name_length]; /* name of change file */ +int line[max_include_depth]; /* number of current line in the stacked files */ +int change_line; /* number of current line in change file */ +boolean input_has_ended; /* if there is no more input */ +boolean changing; /* if the current line is from |change_file| */ + +@ When |changing=0|, the next line of |change_file| is kept in +|change_buffer|, for purposes of comparison with the next +line of |cur_file|. After the change file has been completely input, we +set |change_limit=change_buffer|, so that no further matches will be made. + +Here's a shorthand expression for inequality between the two lines: + +@d lines_dont_match = (change_limit-change_buffer != limit-buffer || + strncmp(buffer, change_buffer, limit-buffer)) + +@<Other...@>= +ASCII change_buffer[buf_size]; /* where next line of |change_file| is kept */ +ASCII *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==0 && !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. + +@<Func...@>= +prime_the_change_buffer() +{ + change_limit=0; /* this value will be used if the change file ends */ + @<Skip over comment lines in the change file; |return| if end of file@>; + @<Skip to the next nonblank line; |return| if end of file@>; + @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>; +} + +@ While looking for a line that begins with \.{@@x} in the change file, +we allow lines that begin with \.{@@}, as long as they don't begin with +\.{@@y} or \.{@@z} (which would probably indicate that the change file is +fouled up). + +@<Skip over comment lines in the change file...@>= +while(1) { + change_line++; + if (!input_ln(change_file)) return; + if (limit<buffer+2) continue; + if (buffer[0]!=the_at_sign) continue; + @<Lowercasify |buffer[1]|@>; + @<Check for erroneous \.{@@i}@>; + if (buffer[1]==@`x') break; + if (buffer[1]==@`y' || buffer[1]==@`z') { + loc=buffer+2; + err_print("! Where is the matching @@x?"); +@.Where is the match...@> + } +} + +@ This line of code makes |"@@X"| equivalent to |"@@x"| and so on. + +@<Lowerc...@>= +if (buffer[1]>=@`X' && buffer[1]<=@`Z' || buffer[1]==@`I') buffer[1]+=@`z'-@`Z'; + +@ We do not allow includes in a change file, so as to avoid confusion. + +@<Check for erron...@>= { + if (buffer[1]==@`i') { + loc=buffer+2; + err_print("! No includes allowed in change file"); +@.No includes allowed...@> + } +} + +@ Here we are looking at lines following the \.{@@x}. + +@<Skip to the next nonblank line...@>= +do { + change_line++; + if (!input_ln(change_file)) { + err_print("! Change file ended after @@x"); +@.Change file ended...@> + return; + } +} while (limit==buffer); + +@ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>= +{ + change_limit=change_buffer-buffer+limit; + strncpy(change_buffer,buffer,limit-buffer+1); +} + +@ The following procedure is used to see if the next change entry should +go into effect; it is called only when |changing| is 0. +The idea is to test whether or not the current +contents of |buffer| matches the current contents of |change_buffer|. +If not, there's nothing more to do; but if so, a change is called for: +All of the text down to the \.{@@y} is supposed to match. An error +message is issued if any discrepancy is found. Then the procedure +prepares to read the next line from |change_file|. + +@<Func...@>= +check_change() /* switches to |change_file| if the buffers match */ +{ + int n=0; /* the number of discrepancies found */ + if (lines_dont_match) return; + while (1) { + changing=1; print_where=1; change_line++; + if (!input_ln(change_file)) { + err_print("! Change file ended before @@y"); +@.Change file ended...@> + change_limit=0; changing=0; print_where=1; + return; + } + if (limit>buffer+1 && buffer[0]==the_at_sign) + @<Check for erron...@>; + @<If the current line starts with \.{@@y}, + report any discrepancies and |return|@>;@/ + @<Move |buffer| and |limit|...@>;@/ + changing=0; print_where=1; cur_line++; + while (!input_ln(cur_file)) { /* pop the stack or quit */ + if (include_depth==0) { + err_print("! WEB file ended during a change"); +@.WEB file ended...@> + input_has_ended=1; return; + } + include_depth--; print_where=1; cur_line++; + } + if (lines_dont_match) n++; + } +} + +@ @<If the current line starts with \.{@@y}...@>= +if (limit>buffer+1 && buffer[0]==the_at_sign) { + @<Lowerc...@>; + if (buffer[1]==@`x' || buffer[1]==@`z') { + loc=buffer+2; err_print("! Where is the matching @@y?"); +@.Where is the match...@> + } + else if (buffer[1]==@`y') { + if (n>0) { + loc=buffer+2; + err_print("! Hmm... some of the preceding lines failed to match"); +@.Hmm... some of the preceding...@> + } + return; + } +} + +@ The |reset_input| procedure, which gets \.{CWEAVE} ready to read the +user's \.{WEB} input, is used at the beginning of phases one and two. + +@<Func...@>= +reset_input() +{ + limit=buffer; loc=buffer+1; buffer[0]=@` '; + @<Open input files@>; + cur_line=0; change_line=0; include_depth=0; + 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@> +For the input files, we {\em don't} look on the search path. +@<Open input files@>= +if ((web_file=fopen(web_file_name,"r"))==NULL) + fatal("! Cannot open input file ", web_file_name); +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 \.{TANGLE} to print this +information in the \cee\ file by means of the |print_where| flag. + +@d max_modules = 2000 /* number of identifiers, strings, module names; + must be less than 10240 */ + + + +@<Defin...@>= +typedef unsigned short sixteen_bits; +sixteen_bits module_count; /* the current module number */ +boolean changed_module[max_modules]; /* is the module changed? */ +boolean print_where=0; /* tells \.{TANGLE} to print line and file info */ + +@ @<Fun...@>= +get_line() /* inputs the next line */ +{ + restart: + if (changing) changed_module[module_count]=1; + else @<Read from |cur_file| and maybe turn on |changing|@>; + if (changing) { + @<Read from |change_file| and maybe turn off |changing|@>; + if (! changing) { + changed_module[module_count]=1; goto restart; + } + } + loc=buffer; *limit=@` '; + if (*buffer==the_at_sign && (*(buffer+1)==@`i' || *(buffer+1)==@`I')) + @<Push stack and go to |restart|@>; + return (!input_has_ended); +} + +@ When a \.{@@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 \.{"..."}; +\.{WEB} will look for include files in standard directories using +the |pathopen| module. +That is set up at the beginning using the {\tt -I} arguments +and the {\tt WEBPATH} environment variable. +@<Add environment variable |"WEBPATH"| to search path@>= + pathaddpath(getenv("WEBPATH"),':'); +@ @<Add path name from {\tt -I} to search path@>= + pathaddname(*argv+2); +@ @<Other...@>= +@i pathopen.h +@ We need to define an |overflow| {\em function} for |pathopen| to call. +@ @<Functions@>= +void @= overflow @>(s) + char *s; +{ overflow(s);} +@ The included file name should only contain visible ASCII characters, +since the characters are translated into ASCII and back again. + +@<Push stack and...@>= { + ASCII *k, *j; + loc=buffer+2; + while (loc<=limit && (*loc==@` '||*loc==@`\t'||*loc==@`"')) loc++; + if (loc>=limit) err_print("! Include file name not given"); +@.Include file name not given@> + else { + if (++include_depth<max_include_depth) { + k=cur_file_name; j=loc; + while (*loc!=@` '&&*loc!=@`\t'&&*loc!=@`"') *k++=xchr[*loc++]; + *k='\0'; + if ((cur_file=pathopen(cur_file_name,"r"))==NULL) { + loc=j; + include_depth--; + err_print("! Cannot find include file on path"); +@.Cannot find include file on path@> + } + else {cur_line=0; print_where=1;} + } + else { + include_depth--; + err_print("! Too many nested includes"); +@.Too many nested includes@> + } + } + goto restart; +} + +@ @<Read from |cur_file|...@>= { + cur_line++; + while (!input_ln(cur_file)) { /* pop the stack or quit */ + print_where=1; + if (include_depth==0) {input_has_ended=1; break;} + else {fclose(cur_file); include_depth--; cur_line++;} + } + if (!input_has_ended) + if (limit==change_limit-change_buffer+buffer) + if (buffer[0]==change_buffer[0]) + if (change_limit>change_buffer) check_change(); +} + +@ @<Read from |change_file|...@>= { + change_line++; + if (!input_ln(change_file)) { + err_print("! Change file ended without @@z"); +@.Change file ended...@> + buffer[0]=the_at_sign; buffer[1]=@`z'; limit=buffer+2; + } + if (limit>buffer+1) /* check if the change has ended */ + if (buffer[0]==the_at_sign) { + @<Lowerc...@>; + @<Check for erron...@>; + 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|. + +@<Funct...@>= +check_complete(){ + if (change_limit!=0) { /* |changing| is 0 */ + strncpy(buffer,change_buffer,change_limit-change_buffer+1); + limit=change_limit-change_buffer+buffer; + changing=1; loc=change_limit; + err_print("! Change file entry did not match"); + @.Change file entry did not match@> + } +} + +@* Storage of identifiers and module names. +Both \.{WEAVE} and \.{TANGLE} store identifiers, module names and +other strings in a large array of |ASCII|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|. + +This module has to go after the module that defines the types of the +other elements, so it has a special name. + +@d max_bytes = 90000 /* the number of bytes in identifiers, + index entries, and module names */ +@d max_names = 4000 /* number of identifiers, strings, module names; + must be less than 10240 */ + +@<Definitions that...@>= +typedef struct name_info { + ASCII *byte_start; /* beginning of the name in |byte_mem| */ + ===> @<More elements of |name_info| structure@>@; +} name_info; /* contains information about an identifier or module name */ +typedef name_info *name_pointer; /* pointer into array of |name_info|s */ +ASCII byte_mem[max_bytes]; /* characters of names */ +ASCII *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|, 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) = ASCII_write((c)->byte_start,length((c))) + /* print identifier or module name */ + +@ The first unused position in |byte_mem| and |name_dir| is +kept in |byte_ptr| and |name_ptr|, respectively. Thus we +usually have |name_ptr->byte_start=byte_ptr|, and certainly +we want to keep |name_ptr<=name_dir_end| and |byte_ptr<=byte_mem_end|. + +@<Defini...@>= +name_pointer name_ptr; /* first unused position in |byte_start| */ +ASCII *byte_ptr; /* first unused position in |byte_mem| */ + +@ @<Init...@>= +name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */ +name_ptr=name_dir+1; /* |name_dir[0]| will not be used */ +name_ptr->byte_start=byte_mem; /* this makes name 0 of length zero */ + +@ The names of identifiers are found by computing a hash address |h| and +then looking at strings of bytes signified by the |name_pointer|s +|hash[h]|, |hash[h]->link|, |hash[h]->link->link|, \dots, +until either finding the desired name or encountering the null pointer. + +@<More elements of |name...@>= +struct name_info *link; + +@ The hash table itself +consists of |hash_size| entries of type |name_pointer|, and is +updated by the |id_lookup| procedure, which finds a given identifier +and returns the appropriate |name_pointer|. The matching is done by the +function |names_match|, which is slightly different in +\.{WEAVE} and \.{TANGLE}. If there is no match for the identifier, +it is inserted into the table. + +@d hash_size = 353 /* should be prime */ + +@<Defini...@>= +typedef name_pointer *hash_pointer; +name_pointer hash[hash_size]; /* heads of hash lists */ +hash_pointer hash_end = hash+hash_size-1; /* end of |hash| */ +hash_pointer h; /* index into hash-head array */ + +@ Initially all the hash lists are empty. + +@<Init...@>= +for (h=hash; h<=hash_end; *h++=NULL) ; + +@ Here is the main procedure for finding identifiers: + +@u name_pointer +id_lookup(first,last,t) /* looks up a string in the identifier table */ +ASCII *first; /* first character of string */ +ASCII *last; /* last character of string plus one */ +eight_bits t; /* the |ilk|; used by \.{WEAVE} and by \.{TANGLE} for macros */ +{ + ASCII *i=first; /* position in |buffer| */ + int h; /* hash code */ + int l; /* length of the given identifier */ + name_pointer p; /* where the identifier is being sought */ + if (last==NULL) for (last=first; *last!='\0'; last++); + l=last-first; /* compute the length */ + @<Compute the hash code |h|@>; + @<Compute the name location |p|@>; + if (p==name_ptr) @<Enter a new name into the table at position |p|@>; + return(p); +} + +@ A simple hash code is used: If the sequence of +ASCII codes is $c_1c_2\ldots c_n$, its hash value will be +$$(2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\,\bmod\,|hash_size|.$$ + +@<Compute the hash...@>= +h=*i; while (++i<last) h=(h+h+*i) % hash_size; + +@ If the identifier is new, it will be placed in position |p=name_ptr|, +otherwise |p| will point to its existing location. + +@<Compute the name location...@>= +p=hash[h]; +while (p && !names_match(p,first,l,t)) p=p->link; +if (p==NULL) { + p=name_ptr; /* the current identifier is new */ + p->link=hash[h]; hash[h]=p; /* insert |p| at beginning of hash list */ +} + +@ The information associated with a new identifier must be initialized +in a slightly different way in \.{WEAVE} than in \.{TANGLE}; hence the +|init_p| procedure. + +@<Enter a new name...@>= { + if (byte_ptr+l>byte_mem_end) overflow("byte memory"); + if (name_ptr>=name_dir_end) overflow("name"); + strncpy(byte_ptr,first,l); + (++name_ptr)->byte_start=byte_ptr+=l; + init_p(p,t); /* set ilk */ +} + +@ The names of modules are stored in |byte_mem| together +with the identifier names, but a hash table is not used for them because +\.{TANGLE} needs to be able to recognize a module name when given a prefix of +that name. A conventional binary seach tree is used to retrieve module 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 module names, we declare it as a |union|. + +@d llink = link /* left link in binary search tree for module names */ +@d rlink = dummy.Rlink /* right link in binary search tree for module names */ +@d root = name_dir->rlink /* the root of the binary search tree + for module names */ + +@<More elements of |name...@>= +union { + struct name_info *Rlink; /* right link in binary search tree for module + names */ + eight_bits Ilk; /* used by identifiers in \.{WEAVE} only */ +} dummy; + +@ @<Init...@>= +root=NULL; /* the binary search tree starts out with nothing in it */ + +@ The |mod_lookup| procedure finds a module name in the +search tree, after inserting it if necessary, and returns a pointer to +where it was found. + +According to the rules of \.{WEB}, no module name should be a proper +prefix of another, so a ``clean'' comparison should occur between any +two names. The result of |mod_lookup| is |NULL| if this prefix condition +is violated. An error message is printed when such violations are detected. + +@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 */ + +@<Other...@>= +name_pointer install_node(); + +@ @u name_pointer +mod_lookup(k,l) /* finds module name */ +ASCII *k; /* first character of name */ +ASCII *l; /* last character of name */ +{ + short c = greater; /* comparison between two names */ + name_pointer p = root; /* current node of the search tree */ + name_pointer q = name_dir; /* father of node |p| */ + while (p) { + c=web_strcmp(k,l+1,p->byte_start,(p+1)->byte_start); + q=p; + switch(c) { + case less: p=p->llink; continue; + case greater: p=p->rlink; continue; + case equal: return p; + default: err_print("! Incompatible section names"); return NULL; +@.Incompatible section names@> + } + } + return(install_node(q,c,k,l-k+1)); +} + +@ This function is like |strcmp|, but it does not assume the strings +are null-terminated. + +@u +web_strcmp(j,j1,k,k1) /* fuller comparison than |strcmp| */ +ASCII *j; /* beginning of first string */ +ASCII *j1; /* end of first string plus one */ +ASCII *k; /* beginning of second string */ +ASCII *k1; /* end of second string plus one */ +{ + while (k<k1 && j<j1 && *j==*k) k++, j++; + if (k==k1) if (j==j1) return equal; + else return extension; + else if (j==j1) return prefix; + else if (*j<*k) return less; + else return greater; +} + +@ The reason we initialized |c| to |greater| is so that +|name_pointer| will make |name_dir->rlink| point to the root of the tree +when |q=name_dir|, that is, the first time it is called. + +The information associated with a new node must be initialized +in a slightly different way in \.{WEAVE} than in \.{TANGLE}; hence the +|init_node| procedure. + +@u name_pointer +install_node(parent,c,j,name_len) /* install a new node in the tree */ +name_pointer parent; /* parent of new node */ +int c; /* right or left? */ +ASCII *j; /* where replacement text starts */ +int name_len; /* length of replacement text */ +{ + name_pointer node=name_ptr; /* new node */ + if (byte_ptr+name_len>byte_mem_end) overflow("byte memory"); + if (name_ptr==name_dir_end) overflow("name"); + if (c==less) parent->llink=node; else parent->rlink=node; + node->llink=NULL; node->rlink=NULL; + init_node(node); + strncpy(byte_ptr,j,name_len); + (++name_ptr)->byte_start=byte_ptr+=name_len; + return(node); +} + +@ The |prefix_lookup| procedure is supposed to find exactly one module +name that has $|k|\ldots|l|$ as a prefix. Actually the algorithm +silently accepts also the situation that some module name is a prefix of +$|k|\ldots|l|$, because the user who painstakingly typed in more than +necessary probably doesn't want to be told about the wasted effort. + +@u name_pointer +prefix_lookup(k,l) /* finds module name given a prefix */ +ASCII *k; /* first char of prefix */ +ASCII *l; /* last char of prefix */ +{ + short c = greater; /* comparison between two names */ + short count = 0; /* the number of hits */ + name_pointer p = root; /* current node of the search tree */ + name_pointer q = NULL; + /* another place to resume the search after one is done */ + name_pointer r = NULL; /* extension found */ + while (p) { + c=web_strcmp(k,l+1,p->byte_start,(p+1)->byte_start); + switch(c) { + case less: p=p->llink; break; + case greater: p=p->rlink; break; + default: r=p; count++; q=p->rlink; p=p->llink; + } + if (p==NULL) { + p=q; q=NULL; + } + } + if (count==0) err_print("! Name does not match"); +@.Name does not match@> + if (count>1) err_print("! Ambiguous prefix"); +@.Ambiguous prefix@> + return(r); /* the result will be |NULL| if there was no match */ +} + +@ The last component of |name_info| is different for \.{TANGLE} and +\.{WEAVE}. In \.{TANGLE}, if |p| is a pointer to a module name, +|p->equiv| is a pointer to its replacement text, an element of the +array |text_info|. In \.{WEAVE}, 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 \.{TANGLE} and \.{WEAVE} +source files, respectively; here we just declare a common field +|equiv_or_xref| as a pointer to an |ASCII|. + +@<More elements of |name...@>= +ASCII *equiv_or_xref; /* info corresponding to names */ + +@* Reporting errors to the user. +A global variable called |history| will contain one of four values +at the end of every run: |spotless| means that no unusual messages were +printed; |harmless_message| means that a message of possible interest +was printed but no serious errors were detected; |error_message| means that +at least one error was found; |fatal_message| means that the program +terminated abnormally. The value of |history| does not influence the +behavior of the program; it is simply computed for the convenience +of systems that might want to use such information. + +@d spotless = 0 /* |history| value for normal jobs */ +@d harmless_message = 1 /* |history| value when non-serious info was printed */ +@d error_message = 2 /* |history| value when an error was noted */ +@d fatal_message = 3 /* |history| value when we had to stop prematurely */ +@d mark_harmless = {if (history==spotless) history=harmless_message;} +@d mark_error = history=error_message + +@<Definit...@>= +int history=spotless; /* indicates how bad this run was */ + +@ The command `|err_print("! Error message")|' will report a syntax error to +the user, by printing the error message at the beginning of a new line and +then giving an indication of where the error was spotted in the source file. +Note that no period follows the error message, since the error routine +will automatically supply a period. + +The actual error indications are provided by a procedure called |error|. +However, error messages are not actually reported during phase one, +since errors detected on the first pass will be detected again +during the second. + +@<Functions...@>= +err_print(s) /* prints `\..' and location of error message */ +char *s; +{ + ASCII *k,*l; /* pointers into |buffer| */ + printf("\n%s",(s==(char *)0) ? "Bad error message!!!" : s); + if (setting_up) { +printf("\nError occurred while scanning arguments or opening output files. "); + } else { + @<Print error location based on input buffer@>; + } + fflush(stdout); mark_error; +} + +@ The error locations can be indicated by using the global variables +|loc|, |cur_line|, |cur_file_name| and |changing|, +which tell respectively the first +unlooked-at position in |buffer|, the current line number, the current +file, and whether the current line is from |change_file| or |cur_file|. +This routine should be modified on systems whose standard text editor +has special line-numbering conventions. +@^system dependencies@> + +@<Print error location based on input buffer@>= +if (changing) printf(". (l. %d of change file)\n", change_line); +else if (include_depth==0) printf(". (l. %d)\n", cur_line); + else printf(". (l. %d of include file %s)\n", cur_line, cur_file_name); +l= (loc>=limit? limit: loc); +if (l>buffer) { + for (k=buffer; k<l; k++) + if (*k=='\t') putchar(' '); + else putchar(xchr[*k]); /* print the characters already read */ + putchar('\n'); + for (k=buffer; k<l; k++) putchar(' '); /* space out the next line */ +} +for (k=l; k<limit; k++) putchar(xchr[*k]); /* print the part not yet read */ +if (*limit==@`|') putchar('|'); /* end of \cee\ text in module names */ +putchar(' '); /* to separate the message from future asterisks */ + +@ When no recovery from some error has been provided, we have to wrap +up and quit as graciously as possible. This is done by calling the +function |wrap_up| at the end of the code. + +@d fatal(s1,s2) = { + printf(s1); err_print(s2); + history=fatal_message; wrap_up(); +} + +@ Sometimes the program's behavior is far different from what it should be, +and \.{WEB} prints an error message that is really for the \.{WEB} +maintenance person, not the user. In such cases the program says +|confusion("indication of where we are")|. + +@d confusion(s) = fatal("\n! This can't happen: ",s) +@.This can't happen@> + +@ An overflow stop occurs if \.{WEB}'s tables aren't large enough. + +@d overflow(s) = { + fatal("\n! Sorry, capacity exceeded: ",s); +} +@.Sorry, x capacity exceeded@> + +@ 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@> + +@<Func...@>= +wrap_up() { + putchar('\n'); + @<Print the job |history|@>; + if (history > harmless_message) exit(1); + else exit(0); +} + +@ @<Print the job |history|@>= +switch (history) { +case spotless: 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 */ + +@* Command line arguments. +The user calls \.{CWEAVE} and \.{CTANGLE} with arguments on the command line. +These are either file names or flags (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. + +The only flag that affects \.{CWEAVE} is |"-x"|, whose status is kept in +|no_xref|; it means the cross-referencing information---the index, the +module name list, and the table of contents---is to be suppressed. +No flags affect \.{CTANGLE}. + +@<Defin...@>= +int argc; /* copy of |ac| parameter to |main| */ +char **argv; /* copy of |av| parameter to |main| */ +char C_file_name[max_file_name_length]; /* name of |C_file| */ +char tex_file_name[max_file_name_length]; /* name of |tex_file| */ +int no_xref; /* should \.{WEAVE} print an index? */ + +@ We now must look at the command line arguments and set the file names +accordingly. At least one file name must be present: the \.{WEB} +file. It may have an extension, or it may omit it to get |".web"| +added. The \TeX\ output file name is formed by replacing the \.{WEB} +file name extension by |".tex"|, and the \cee\ file name by replacing +the extension by |C_file_extension| +@<External...@>=extern char C_file_extension[]; + +@ If there is another 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@> + +@<Function...@>= +scan_args() +{ + char *dot_pos, *index(); /* position of |'.'| in the argument */ + boolean found_web=0,found_change=0; /* have these names have been seen? */ + no_xref=0; + while (--argc > 0) { + if (**(++argv)!='-') { + if (!found_web) @<Make + |web_file_name|, |tex_file_name| and |C_file_name|@>@; + else if (!found_change) @<Make |change_file_name| from |fname|@>@; + else @<Print usage error message and quit@>; + } + else @<Handle flag argument@>; + } + if (!found_web) @<Print usage error message and quit@>; + if (!found_change) @<Set up null change file@>; +} + +@ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it, +otherwise add |".web"|. The other file names come from adding things +after the dot. We must check that there is enough room in +|web_file_name| and the other arrays for the argument. + +@<Make |web_file_name|...@>= +{ + if (strlen(*argv) > max_file_name_length-5) + @<Complain about argument length@>; + if ((dot_pos=index(*argv,'.'))==NULL) + sprintf(web_file_name,"%s.web",*argv); + else { + sprintf(web_file_name,"%s",*argv); + @<Advance |dot_pos| to the last |'.'| in |*argv|@> + *dot_pos=0; /* string now ends where the dot was */ + } + sprintf(tex_file_name,"%s.tex",*argv); + sprintf(C_file_name,"%s.%s",*argv,C_file_extension); + found_web=1; +} + +@ @<Advance |dot_pos| to the last |'.'| in |*argv|@>= +{ char *p; + p=dot_pos; + while (*++p != '\0') + if (*p=='.') dot_pos=p; +} + +@ @<Make |change_file_name|...@>= +{ + if (strlen(*argv) > max_file_name_length-5) + @<Complain about argument length@>; + if ((dot_pos=index(*argv,'.'))==NULL) + sprintf(change_file_name,"%s.ch",*argv); + else sprintf(change_file_name,"%s",*argv); + found_change=1; +} + +@ @<Set up null...@>= +#ifdef MSDOS +strcpy(change_file_name,"NUL"); +#else +strcpy(change_file_name,"/dev/null"); +#endif +@ +We have two possible flags: +\medskip +\halign{\tabskip=1em\tt#\hfil&#\hfil\cr +\omit{\bf Argument}\hfil&\omit\bf Function\hfil\cr +-x&Turns off \.{WEAVE} cross-reference.\cr +-I<pathname>&% +Adds {\tt <pathname>} to the directories searched for included files.\cr +} +@<Handle flag...@>= +{ + switch((*argv)[1]) { + case 'x': + no_xref=1; + break; + case 'I': + @<Add path name from {\tt -I} to search path@>@; + break; + default: + @<Complain about unknown option@>; + break; + } +} + +@ @<Print usage error message and quit@>= +{ +if (program==tangle) +fatal("! Usage: tangle webfile[.web] [changefile[.ch]] [-Ipathname ...]\n",0)@; +else +fatal("! Usage: weave webfile[.web] [changefile[.ch]] [-x] [-Ipathname ...]\n", + 0); +} + +@ @<Complain about arg...@>= fatal("! Filename %s too long\n", *argv); + +@ @<Complain about unk...@>= { +printf("! Unknown option in argument %s\n", *argv); mark_harmless; +} + +@* Output. Here is the code that opens the output file: +@^system dependencies@> + +@<Defin...@>= +FILE *C_file; /* where output of \.{TANGLE} goes */ +FILE *tex_file; /* where output of \.{WEAVE} goes */ + +@ @<Scan arguments and open output files@>= +scan_args(); +@<Add environment variable |"WEBPATH"| to search path@>@; +if (program==tangle) { + 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); +} + +@ 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 \.{WEB}'s code into the external character code, +and |printf| when we just want to print strings. +@^system dependencies@> +@d new_line = putchar('\n') @d putxchar = putchar +@d ASCII_write(a,b) = fflush(stdout), write(1,a,b) /* write on the standard output */ +@d line_write(c) = write(fileno(C_file),c) /* write on the C output file */ +@d C_printf(c,a) = fprintf(C_file,c,a) +@d C_putc(c) = putc(c,C_file) + +@* Index. diff --git a/web/spiderweb/src/master/cycle.awk b/web/spiderweb/src/master/cycle.awk new file mode 100644 index 0000000000..602544b18a --- /dev/null +++ b/web/spiderweb/src/master/cycle.awk @@ -0,0 +1,86 @@ +##157: + +#line 22 "cycle.web" + +#line 23 "cycle.web" +NF==4&&$3=="-->"{ +incoming[$4]+=1 +if(incoming[$2]==""){ +incoming[$2]=0 +} +successors[$2]=successors[$2]" "$4 +outgoing_edges[$2]=outgoing_edges[$2]$0"\n" +next +} +!/^ *$/{ +print"What's all this?",$0 +exit 1 +} +END{ +##158: + +#line 57 "cycle.web" + +#line 58 "cycle.web" +for(node in incoming){ +if(incoming[node]==0){ +work[high++]=node +} +} + +##:158 + +#line 38 "cycle.web" + +n=0 +while(n<high){ +##159: + +#line 64 "cycle.web" + +#line 65 "cycle.web" +thisnode=work[n] +temp=successors[thisnode] +m=split(temp,newnodes," ") +for(j=1;j<=m;j++){ +thisnode=newnodes[j] +incoming[thisnode]-=1 +if(incoming[thisnode]==0){ +work[high++]=thisnode +} +} + +##:159 + +#line 42 "cycle.web" + +n++ +} +for(node in incoming){ +if(incoming[node]!=0){ +##160: + +#line 76 "cycle.web" + +#line 77 "cycle.web" +if(cycle==0){ +print"There is a potential cycle here somewhere -- check the context" +cycle=1 +} +printf"%s",outgoing_edges[node] +#line 2527 "/u/norman/pu/web/dist/src/master/spider.web" +##:160 + +#line 47 "cycle.web" + +} +} +if(cycle==0){ +print"There can't possibly be a cycle in the graph" +}else{ +exit 0 +} +} + +##:157 + diff --git a/web/spiderweb/src/master/cycle.web b/web/spiderweb/src/master/cycle.web new file mode 100644 index 0000000000..fed5efc20a --- /dev/null +++ b/web/spiderweb/src/master/cycle.web @@ -0,0 +1,81 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +#*Detecting cycles in a directed graph of productions. +{\tt SPIDER} writes a list of possibly cyclic productions on +{\tt cycle.test}. The program {\tt cycle.awk} reads those and +reports on whether there can be a cycle in the graph. +If there were a cycle, it might lead to an infinite loop in \.{WEAVE}. +One should inspect contexts to see if that could really happen. + +# Input is a list of edges in the form +$$\hbox{\tt name leftnode --> rightnode}$$ +We detect a cycle if one exists. + +# We will use the following strategy: assemble all the edges, then +read through them to label each node with the number of incoming edges +and then the names of the successor nodes. +We will then put nodes with no incoming edges on the work list, and +remove them one by one, decrementing the incoming counts of their successors. +If anything is left, there must be a cycle. +#(cycle.awk#>= +NF==4 && $3=="-->" { + incoming[$4]+=1 + if (incoming[$2]=="") { + incoming[$2]=0 + } + successors[$2]=successors[$2] " " $4 + outgoing_edges[$2]=outgoing_edges[$2] $0 "\n" + next + } +#=!/^ *$/#> { + print "What's all this?", $0 + exit 1 + } +END { + #<Put all nodes with no incoming edges in |work[n]|, where + |0 <= n < high|#> + n=0 + while (n<high) { + #<For each successor of |work[n]|, decrement the + incoming edge count and add to |work[]| if zero#> + n++ + } + for (node in incoming) { + if (incoming[node]!=0) { + #<Announce a cycle and set |cycle=1|#> + } + } + if (cycle==0) { + print "There can't possibly be a cycle in the graph" + } else { + exit 0 ## no error until we check context + } + } + +# #<Put all nodes with no incoming edges in...#>= +for (node in incoming) { + if (incoming[node]==0) { + work[high++]=node + } + } + +# #<For each successor...#>= +thisnode=work[n] +temp=successors[thisnode] +m = split(temp,newnodes," ") +for (j=1; j<=m; j++) { + thisnode=newnodes[j] + incoming[thisnode]-=1 + if (incoming[thisnode]==0) { + work[high++]=thisnode + } + } + +# #<Announce a cycle...#>= +if (cycle==0) { + print "There is a potential cycle here somewhere -- check the context" + cycle=1 + } +printf "%s", outgoing_edges[node] diff --git a/web/spiderweb/src/master/junk.list b/web/spiderweb/src/master/junk.list new file mode 100644 index 0000000000..0d21e78e20 --- /dev/null +++ b/web/spiderweb/src/master/junk.list @@ -0,0 +1,22 @@ +##163: + +#line 2555 "spider.web" + +#line 2556 "spider.web" +good translations +break_space +force +big_force +opt +backup +big_cancel +cancel +indent +outdent +math_rel +math_bin +math_op +test translations + +##:163 + diff --git a/web/spiderweb/src/master/multitang.ch b/web/spiderweb/src/master/multitang.ch new file mode 100644 index 0000000000..349a54d866 --- /dev/null +++ b/web/spiderweb/src/master/multitang.ch @@ -0,0 +1,107 @@ +@x 423 +output: +@y +output. +We have made some modifications to \.{TANGLE} so it will write output +on multiple files. +We do this very simply: if a module name is introduced by \.{@@(} +instead of \.{@@<}, we treat it as the name of a file. +All these special modules are saved on a stack, |output_files|. +We write them out after we've done the unnamed module. +@z +@x 425 +@c +@y +@d max_files 256 +@<Glob...@>= +name_pointer output_files[max_files]; +name_pointer *cur_file, *end_output_files; +char cur_module_char; /* is it |'<'| or |'('| */ +char output_file_name[longest_name]; /* name of the file */ + +@ We make |end_output_files| point jsut beyond the end of +|output_files|. +|cur_file| starts out there. Every time we see a new file, we +decrement |cur_file| and then write it in. +@<Set initial...@>= +cur_file=end_output_files=output_files+max_files; + +@ @<Add |cur_module| to the output file stack, or complain we're out +of room@>= +{ +if (cur_file>output_files) + *--curfile=cur_module; +else { + overflow("output files"); +} +} + +@ Here is the output switch, then... + +@c +@z +@x 434 + printf("\nWriting the output file"); update_terminal; +@y + printf("\nWriting the output files: (%s)",C_file_name); update_terminal; +@z +@x 438 + printf("\nDone."); +@y + @<Write all the named output files@> + printf("\nDone."); +@z +@x 442 +@ First we go through the list of replacement texts and copy the ones +@y +@ To write the named output files, we proceed as for the unnamed +module. +The only subtlety is that we have to open each one. +@<Write all the named output files@>= +for (;cur_file<end_output_files; cur_file++) { + strncpy(output_file_name,(*curfile)->byte_start, longest_name); + output_file_name[length(*curfile)]='\0'; + fclose(C_file); + C_file=fopen(output_file_name,"w"); + if (C_file <=0) { + fatal("! Cannot open output file:",output_file_name) + } else { + printf("(%s)",output_file_name); update_terminal; + } + stack_ptr=stack+1; + cur_name= (*cur_file); + cur_repl= cur_name->equiv_or_xref; + cur_byte=cur_repl->tok_start; + cur_end=(cur_repl+1)->tok_start; + /* cur_mod= it */; + while (stack_ptr > stack) get_output(); + flush_buffer(); +} + + + +@ First we go through the list of replacement texts and copy the ones +@z +@x 575 + ccode['&']=join; ccode['<']=module_name; +@y + ccode['&']=join; + ccode['<']=ccode['(']=module_name; +@z +@x 778 + case module_name: @<Scan the module name and make |cur_module| + point to it@>; +@y + case module_name: + cur_module_char=*(loc-1); + @<Scan the module name and make |cur_module| point to it@>; +@z +@x 803 + return(module_name); +@y + if (cur_module_char=='(') { + @<Add |cur_module| to the output file stack, or complain we're out + of room@> + } + return(module_name); +@z diff --git a/web/spiderweb/src/master/newdefs.awk b/web/spiderweb/src/master/newdefs.awk new file mode 100644 index 0000000000..1432a2e60f --- /dev/null +++ b/web/spiderweb/src/master/newdefs.awk @@ -0,0 +1,11 @@ +## Used to convert old Levy CWEB style definitions to Spidery WEB definitions +/#d|@d/ { + for (i=1; i<NF; i++) { + if ($i=="#d"||$i=="@d") { + $(i+1) = $(i+1) " =" + } + } + print + next +} +{print} diff --git a/web/spiderweb/src/master/nodups.awk b/web/spiderweb/src/master/nodups.awk new file mode 100644 index 0000000000..e22f1d3f65 --- /dev/null +++ b/web/spiderweb/src/master/nodups.awk @@ -0,0 +1,13 @@ +##161: + +#line 2529 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2530 "/u/norman/pu/web/dist/src/master/spider.web" +{if($0==last){ +print"Error: duplicate name",$0,"on lines",NR-1"-"NR +exit-1 +} +last=$0 +} +##:161 + diff --git a/web/spiderweb/src/master/pathopen.c b/web/spiderweb/src/master/pathopen.c new file mode 100644 index 0000000000..626a7117c5 --- /dev/null +++ b/web/spiderweb/src/master/pathopen.c @@ -0,0 +1,122 @@ +/*4:*/ +#line 88 "/u/norman/pu/web/dist/src/master/pathopen.web" + +/*9:*/ +#line 171 "/u/norman/pu/web/dist/src/master/pathopen.web" +#include<stdio.h> + +/*:9*/ +#line 89 "/u/norman/pu/web/dist/src/master/pathopen.web" + + +static int nextpath= 0; +static char pathtexts[1024]; +static char *searchpath[64]= {pathtexts}; +static char *maxpathtexts= pathtexts+1024; + +void pathreset() +{ +nextpath= 0; +searchpath[nextpath]= pathtexts; +} + +/*:4*//*5:*/ +#line 103 "/u/norman/pu/web/dist/src/master/pathopen.web" + +void pathaddname(name) +char *name; +{char *t= searchpath[nextpath]; +if(name==NULL)return; +if(nextpath>=64)overflow("paths"); +while( *name){ +if(t>=maxpathtexts)overflow("path texts"); + *t++= *name++; +} +/*6:*/ +#line 118 "/u/norman/pu/web/dist/src/master/pathopen.web" + +if(t==searchpath[nextpath])nextpath--; +else if(t==searchpath[nextpath]+1&& + *searchpath[nextpath]=='/') +t--; + +/*:6*/ +#line 114 "/u/norman/pu/web/dist/src/master/pathopen.web" + +searchpath[++nextpath]= t; +} + +/*:5*//*7:*/ +#line 125 "/u/norman/pu/web/dist/src/master/pathopen.web" + +#line 126 "/u/norman/pu/web/dist/src/master/pathopen.web" +void pathaddpath(path,path_separator) +char *path; +char path_separator; +{ +char *t= searchpath[nextpath]; +if(path!=NULL){ +while( *path){ +if(nextpath>=64)overflow("paths"); +while( *path!=path_separator&& *path!='\0'){ +if(t>=maxpathtexts)overflow("path texts"); + *t++= *path++; +} +/*6:*/ +#line 118 "/u/norman/pu/web/dist/src/master/pathopen.web" + +if(t==searchpath[nextpath])nextpath--; +else if(t==searchpath[nextpath]+1&& + *searchpath[nextpath]=='/') +t--; + +/*:6*/ +#line 138 "/u/norman/pu/web/dist/src/master/pathopen.web" + +searchpath[++nextpath]= t; +if( *path)path++; +} +} +} + +/*:7*//*8:*/ +#line 151 "/u/norman/pu/web/dist/src/master/pathopen.web" + +FILE *pathopen(name) +char *name; +{ +FILE *fp; +char pathname[1024]; +char *s, *t; +int i; + +if(( *(name)=='/')) +return fopen(name,"r"); +else{ +if((fp= fopen(name,"r"))!=NULL)return fp; +for(i= 0;i<nextpath;i++){ +/*10:*/ +#line 173 "/u/norman/pu/web/dist/src/master/pathopen.web" + +#line 174 "/u/norman/pu/web/dist/src/master/pathopen.web" +for(s= pathname,t= searchpath[i];t<searchpath[i+1];){ + *s++= *t++; +if(s>pathname+1024)overflow("path name length"); +} + *s++= '/'; +if(s>pathname+1024)overflow("path name length"); +t= name; +while( *s++= *t++) +if(s>pathname+1024)overflow("path name length"); +if((fp= fopen(pathname,"r"))!=NULL)return fp; + + +/*:10*/ +#line 165 "/u/norman/pu/web/dist/src/master/pathopen.web" + +} +} +return NULL; +} + +/*:8*/ diff --git a/web/spiderweb/src/master/pathopen.h b/web/spiderweb/src/master/pathopen.h new file mode 100644 index 0000000000..7fbb7cf479 --- /dev/null +++ b/web/spiderweb/src/master/pathopen.h @@ -0,0 +1,9 @@ +/*11:*/ +#line 187 "/u/norman/pu/web/dist/src/master/pathopen.web" + +#line 188 "/u/norman/pu/web/dist/src/master/pathopen.web" +void pathaddname(); +void pathaddpath(); +void pathreset(); +FILE *pathopen(); +/*:11*/ diff --git a/web/spiderweb/src/master/pathopen.web b/web/spiderweb/src/master/pathopen.web new file mode 100644 index 0000000000..6e374eacc5 --- /dev/null +++ b/web/spiderweb/src/master/pathopen.web @@ -0,0 +1,192 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +\def\title{Finding a file on a path} +@*Introduction. +This module is intended to make it easy for applications to open +a file that is not necessarily in the current directory, +but is somewhere on a search path. +The notion is to specify the path ahead of time, so that +calls to |fopen(n,"r")| can be replaced with calls to |pathopen(n)|. +{\em No ASCII conversions are done; everything is in the character set of the +local machine.} + +@ The functions we export are: +\medskip +\noindent{\tabskip=0ptplus1fil +\halign to \hsize{\vrule height 10pt depth3.5pt width0pt + \hfil#\tabskip=2em&\vtop{\hsize=4in + \noindent\ignorespaces#\par} + \tabskip=0ptplus1fil\cr +\omit\hfil\strut{\bf Function name and signature}& +\omit\bf What it does\hfil\cr +\noalign{\smallskip} +|pathreset()|& +Initializes the system to search the empty path. +This initialization is performed statically, so programs needn't call +|pathreset|, but then they may not be serially reusable. +\cr +|pathaddname(char *)|& +Adds the name to the search path (FIFO). +If the first argument is |NULL| or points to the empty string, +|pathaddname| is a no-op. +\cr +|pathaddpath(char *, char)|& +Adds the given path to the search path (FIFO). +The second argument is the character that is used to separate names on +the path, e.g. |pathaddpath(getenv("PATH"),':')|. +If the first argument is |NULL| or points to the empty string, +|pathaddpath| is a no-op. +\cr +|FILE *pathopen(char *)|& +Attempts to open (for read) +the given name, first in the current directory, then, +if the name is not absolute (i.e. on UNIX doesn't begin with |'/'|), +tries to open the name in each directory on the search path. +If some |fopen| succeeds, it returns a pointer to a stream, otherwise it +returns |NULL|. +\cr +}} + +@ We expect to be able to import: +\medskip +\noindent{\tabskip=0ptplus1fil +\halign to \hsize{\vrule height 10pt depth3.5pt width0pt + \hfil#\tabskip=2em&\vtop{\hsize=4in + \noindent\ignorespaces#\par} + \tabskip=0ptplus1fil\cr +\omit\hfil\strut{\bf Function name and signature}& +\omit\bf What it does\hfil\cr +\noalign{\smallskip} +|overflow(char *)|& +The |pathopen| routines will call |overflow| if they run out of space, +e.g.~|overflow("path texts")|. +\cr +}} + +@ Here we set up the search path. +It is a list of directories; if |pathopen| is handed a relative file name, +it will look for it first in the current directory, and then in each +directory on the search path. +We allow up to |maxpaths| directories to be on the path, +and we set aside |pathtextlength| bytes for the names of those directories. +We perform the initialization statically, so we don't {\em have} to call +|pathreset|. + +We use Knuth's technique for storing the names: all the bytes are stored +in |pathtexts|. +Pointers to the directories are stored in |searchpath|; the name of +the |i|th directory is found in $|*(searchpath[i])|\ldots|*(seachpath[i+1])|$, +where we start counting |i| from zero. +|nextpath| contains the number directories already stored, and +|searchpath[nextpath]| points to the first free byte in |pathtexts|. +This is all a little odd for those used to C's null-terminated strings, but +it becomes second nature after a while. +@d maxpaths = 64 +@d pathtextlength = 1024 +@u +@<Included files@>@; + +static int nextpath=0; +static char pathtexts[pathtextlength]; +static char *searchpath[maxpaths]={pathtexts}; +static char *maxpathtexts = pathtexts+pathtextlength; + +void pathreset() +{ + nextpath=0; + searchpath[nextpath]=pathtexts; +} + +@ Here's how we add a name to the path +@u +void pathaddname(name) + char *name; +{ char *t=searchpath[nextpath]; + if (name==NULL) return; + if (nextpath>=maxpaths) overflow ("paths"); + while (*name) { + if (t>=maxpathtexts) overflow("path texts"); + *t++=*name++; + } + @<If path is null, decrement |nextpath| to cancel addition, + and if path is root, make it null@>@; + searchpath[++nextpath]=t; +} + +@ @<If path is null...@>= +if (t==searchpath[nextpath]) nextpath--; +else if (t==searchpath[nextpath]+1 && + *searchpath[nextpath]==directory_separator) /* path is root */ + t--; + +@ Adding a path is slightly more complicated. +@u +void pathaddpath(path,path_separator) + char *path; + char path_separator; +{ + char *t=searchpath[nextpath]; + if (path!=NULL) { + while (*path) { + if (nextpath>=maxpaths) overflow ("paths"); + while(*path!=path_separator && *path!='\0') { + if (t>=maxpathtexts) overflow("path texts"); + *t++=*path++; + } + @<If path is null...@>@; + searchpath[++nextpath]=t; + if (*path) path++; /* skip separator */ + } + } +} + +@ Now we define the function that attempts to open a file, searching +on the path. +We need to know whether a file name is absolute: +@d directory_separator = '/' /* not converted to ASCII */ +@d absolute(n) = (*(n)==directory_separator) +@d maxpathnamelength = 1024 /* longest path name we can create */ +@u +FILE *pathopen(name) + char *name; +{ + FILE *fp; /* the stream we try to get */ + char pathname[maxpathnamelength]; /* used to create pathnames */ + char *s, *t; /* used to copy prefixes */ + int i; /* used to search pathnames */ + + if (absolute(name)) + return fopen(name,"r"); + else { + if ((fp=fopen(name,"r"))!=NULL) return fp; + for (i=0; i<nextpath; i++) { + @<Try to open on path |i|, returning if not |NULL|@>@; + } + } + return NULL; +} + +@ @<Included...@>=#include <stdio.h> + +@ @<Try to open on path |i|...@>= +for(s=pathname,t=searchpath[i]; t<searchpath[i+1];) { + *s++ = *t++; + if (s>pathname+maxpathnamelength) overflow("path name length"); +} +*s++=directory_separator; +if (s>pathname+maxpathnamelength) overflow("path name length"); +t=name; +while(*s++=*t++) + if (s>pathname+maxpathnamelength) overflow("path name length"); +if ((fp=fopen(pathname,"r"))!=NULL) return fp; + + +@ As a final service, we write declarations on file {\tt pathopen.h} +@(pathopen.h@>= +void pathaddname(); +void pathaddpath(); +void pathreset(); +FILE *pathopen(); +@* Index. diff --git a/web/spiderweb/src/master/pretty.awk b/web/spiderweb/src/master/pretty.awk new file mode 100644 index 0000000000..39ec7a1a38 --- /dev/null +++ b/web/spiderweb/src/master/pretty.awk @@ -0,0 +1,2 @@ +/^\\Y/,/\\par$/ {print; next} +{next} diff --git a/web/spiderweb/src/master/spider.awk b/web/spiderweb/src/master/spider.awk new file mode 100644 index 0000000000..d8d0d74a10 --- /dev/null +++ b/web/spiderweb/src/master/spider.awk @@ -0,0 +1,4799 @@ +##3: + +#line 53 "/u/norman/pu/web/dist/src/master/spider.web" + +BEGIN{ +##9: + +#line 181 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 182 "/u/norman/pu/web/dist/src/master/spider.web" +logfile="spider.slog" + +##:9 +##10: + +#line 185 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 186 "/u/norman/pu/web/dist/src/master/spider.web" +translationfile="trans_keys.unsorted" + +##:10 +##11: + +#line 190 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 191 "/u/norman/pu/web/dist/src/master/spider.web" +scrapfile="scraps.web" +print"@*Scrap code generated by {\\tt SPIDER}.">scrapfile +ttokfile="outtoks.web" +print"@*Token code generated by {\\tt SPIDER}.">ttokfile +##:11 +##12: + +#line 197 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 198 "/u/norman/pu/web/dist/src/master/spider.web" +reserved="scraps.web" + +##:12 +##13: + +#line 202 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 203 "/u/norman/pu/web/dist/src/master/spider.web" +tokennamefile="names.unsorted" +##:13 +##14: + +#line 206 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 207 "/u/norman/pu/web/dist/src/master/spider.web" +ilkfile="names.unsorted" +##:14 +##15: + +#line 210 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 211 "/u/norman/pu/web/dist/src/master/spider.web" +categoryfile="names.unsorted" +##:15 +##16: + +#line 213 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 214 "/u/norman/pu/web/dist/src/master/spider.web" +grammarfile="grammar.web" +print"@*Grammar code generated by {\\tt SPIDER}.">grammarfile +##:16 +##17: + +#line 219 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 220 "/u/norman/pu/web/dist/src/master/spider.web" +tlang="outtoks.web" +wlang="scraps.web" + +##:17 +##18: + +#line 225 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 226 "/u/norman/pu/web/dist/src/master/spider.web" +productions="productions.list" + +##:18 +##19: + +#line 229 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 230 "/u/norman/pu/web/dist/src/master/spider.web" +cycles="cycle.test" + + + +##:19 +##37: + +#line 525 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 526 "/u/norman/pu/web/dist/src/master/spider.web" +default_translation="<*>" +default_mathness="maybe" + + +##:37 +##46: + +#line 727 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 728 "/u/norman/pu/web/dist/src/master/spider.web" +highesttoken=200 +tokennumber=highesttoken + +##:46 +##61: + +#line 943 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 944 "/u/norman/pu/web/dist/src/master/spider.web" +tokennumbers["identifier"]=tokennumber;tokennumber-- +tokenname["identifier"]="identifier" + +##:61 +##63: + +#line 969 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 970 "/u/norman/pu/web/dist/src/master/spider.web" +tokennumbers["constant"]=tokennumber;tokennumber-- +tokenname["constant"]="constant" +tokennumbers["string"]=tokennumber;tokennumber-- +tokenname["string"]="string" + + +##:63 +##138: + +#line 2246 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2247 "/u/norman/pu/web/dist/src/master/spider.web" +at_sign="@@" + + +##:138 +##146: + +#line 2397 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2398 "/u/norman/pu/web/dist/src/master/spider.web" +texof["\\"]="\\BS" +texof["{"]="\\{" +texof["}"]="\\{" +texof["$"]="\\$" +texof["&"]="\\amp" +texof["#"]="\\#" +texof["^"]="\\H" +texof["_"]="\\_" +texof["~"]="\\TI" +texof["%"]="\\%" + +##:146 +##150: + +#line 2475 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2476 "/u/norman/pu/web/dist/src/master/spider.web" +sharp_line_open="\"#line\"" +sharp_line_close="\"\"" + +##:150 +##152: + +#line 2495 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2496 "/u/norman/pu/web/dist/src/master/spider.web" +month["Jan"]="January" +month["Feb"]="February" +month["Mar"]="March" +month["Apr"]="April" +month["May"]="May" +month["Jun"]="June" +month["Jul"]="July" +month["Aug"]="August" +month["Sep"]="September" +month["Oct"]="October" +month["Nov"]="November" +month["Dec"]="December" + +##:152 + +#line 55 "/u/norman/pu/web/dist/src/master/spider.web" + +exitcode=0 +} + +##6: + +#line 100 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 101 "/u/norman/pu/web/dist/src/master/spider.web" +/^#|^ *$/{ + +print $0>logfile +next +} + +##:6 + +#line 59 "/u/norman/pu/web/dist/src/master/spider.web" + +##35: + +#line 498 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 499 "/u/norman/pu/web/dist/src/master/spider.web" +/^default /{ +print"Setting defaults...">logfile +start_place=2 +##36: + +#line 518 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 519 "/u/norman/pu/web/dist/src/master/spider.web" +this_translation=default_translation +this_mathness=default_mathness +this_name="" +this_category="" +this_tangleto="" +##:36 + +#line 503 "/u/norman/pu/web/dist/src/master/spider.web" + +##29: + +#line 434 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 435 "/u/norman/pu/web/dist/src/master/spider.web" +for(i=start_place;i<NF;){ +if($i=="tangleto"){ +i++ +this_tangleto=$i +i++ +}else if($i=="translation"){ +i++ +this_translation=$i +i++ +}else if($i=="mathness"){ +i++ +this_mathness=$i +i++ +}else if($i=="category"){ +i++ +this_category=$i +categories[$i]=1 +i++ +}else if($i=="name"){ +i++ +this_name="SP_"$i +i++ +}else{ +print"Error: unrecognized token description",$i,"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 459 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 462 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:29 + +#line 506 "/u/norman/pu/web/dist/src/master/spider.web" + +##30: + +#line 466 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 467 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_name!=""){ +print"Error: name doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 469 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:30 + +#line 507 "/u/norman/pu/web/dist/src/master/spider.web" + +##32: + +#line 476 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 477 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_category!=""){ +print"Error: category doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 479 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:32 + +#line 508 "/u/norman/pu/web/dist/src/master/spider.web" + +default_translation=this_translation +default_mathness=this_mathness +print"\tdefault translation is",default_translation>logfile +print"\tdefault mathness is",default_mathness>logfile +next +} + +##:35 +##39: + +#line 570 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 571 "/u/norman/pu/web/dist/src/master/spider.web" +/^token /{ +print"Token",$2>logfile +if($2=="identifier"){ +##40: + +#line 595 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 596 "/u/norman/pu/web/dist/src/master/spider.web" +##36: + +#line 518 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 519 "/u/norman/pu/web/dist/src/master/spider.web" +this_translation=default_translation +this_mathness=default_mathness +this_name="" +this_category="" +this_tangleto="" +##:36 + +#line 597 "/u/norman/pu/web/dist/src/master/spider.web" + +this_translation="" +start_place=3 +##29: + +#line 434 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 435 "/u/norman/pu/web/dist/src/master/spider.web" +for(i=start_place;i<NF;){ +if($i=="tangleto"){ +i++ +this_tangleto=$i +i++ +}else if($i=="translation"){ +i++ +this_translation=$i +i++ +}else if($i=="mathness"){ +i++ +this_mathness=$i +i++ +}else if($i=="category"){ +i++ +this_category=$i +categories[$i]=1 +i++ +}else if($i=="name"){ +i++ +this_name="SP_"$i +i++ +}else{ +print"Error: unrecognized token description",$i,"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 459 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 462 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:29 + +#line 602 "/u/norman/pu/web/dist/src/master/spider.web" + +##30: + +#line 466 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 467 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_name!=""){ +print"Error: name doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 469 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:30 + +#line 603 "/u/norman/pu/web/dist/src/master/spider.web" + +##31: + +#line 471 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 472 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_tangleto!=""){ +print"Error: tangleto doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 474 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:31 + +#line 604 "/u/norman/pu/web/dist/src/master/spider.web" + +##34: + +#line 486 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 487 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_category==""){ +print"Error: you must give a category on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 489 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:34 + +#line 605 "/u/norman/pu/web/dist/src/master/spider.web" + +##33: + +#line 481 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 482 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_translation!=""){ +print"Error: translation doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 484 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:33 + +#line 606 "/u/norman/pu/web/dist/src/master/spider.web" + +id_category=this_category +id_mathness=this_mathness + +##:40 + +#line 574 "/u/norman/pu/web/dist/src/master/spider.web" + +}else if($2=="number"){ +##41: + +#line 611 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 612 "/u/norman/pu/web/dist/src/master/spider.web" +print"Warning: numeric constants and strings are",\ +"identified in this WEAVE." +print"Warning: numeric constants and strings are",\ +"identified in this WEAVE.">logfile +##36: + +#line 518 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 519 "/u/norman/pu/web/dist/src/master/spider.web" +this_translation=default_translation +this_mathness=default_mathness +this_name="" +this_category="" +this_tangleto="" +##:36 + +#line 617 "/u/norman/pu/web/dist/src/master/spider.web" + +this_translation="" +start_place=3 +##29: + +#line 434 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 435 "/u/norman/pu/web/dist/src/master/spider.web" +for(i=start_place;i<NF;){ +if($i=="tangleto"){ +i++ +this_tangleto=$i +i++ +}else if($i=="translation"){ +i++ +this_translation=$i +i++ +}else if($i=="mathness"){ +i++ +this_mathness=$i +i++ +}else if($i=="category"){ +i++ +this_category=$i +categories[$i]=1 +i++ +}else if($i=="name"){ +i++ +this_name="SP_"$i +i++ +}else{ +print"Error: unrecognized token description",$i,"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 459 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 462 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:29 + +#line 622 "/u/norman/pu/web/dist/src/master/spider.web" + +##30: + +#line 466 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 467 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_name!=""){ +print"Error: name doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 469 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:30 + +#line 623 "/u/norman/pu/web/dist/src/master/spider.web" + +##31: + +#line 471 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 472 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_tangleto!=""){ +print"Error: tangleto doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 474 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:31 + +#line 624 "/u/norman/pu/web/dist/src/master/spider.web" + +##34: + +#line 486 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 487 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_category==""){ +print"Error: you must give a category on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 489 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:34 + +#line 625 "/u/norman/pu/web/dist/src/master/spider.web" + +##33: + +#line 481 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 482 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_translation!=""){ +print"Error: translation doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 484 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:33 + +#line 626 "/u/norman/pu/web/dist/src/master/spider.web" + +number_category=this_category +number_mathness=this_mathness + +##:41 + +#line 576 "/u/norman/pu/web/dist/src/master/spider.web" + +}else if($2=="newline"){ +##42: + +#line 631 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 632 "/u/norman/pu/web/dist/src/master/spider.web" +##36: + +#line 518 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 519 "/u/norman/pu/web/dist/src/master/spider.web" +this_translation=default_translation +this_mathness=default_mathness +this_name="" +this_category="" +this_tangleto="" +##:36 + +#line 633 "/u/norman/pu/web/dist/src/master/spider.web" + +start_place=3 +##29: + +#line 434 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 435 "/u/norman/pu/web/dist/src/master/spider.web" +for(i=start_place;i<NF;){ +if($i=="tangleto"){ +i++ +this_tangleto=$i +i++ +}else if($i=="translation"){ +i++ +this_translation=$i +i++ +}else if($i=="mathness"){ +i++ +this_mathness=$i +i++ +}else if($i=="category"){ +i++ +this_category=$i +categories[$i]=1 +i++ +}else if($i=="name"){ +i++ +this_name="SP_"$i +i++ +}else{ +print"Error: unrecognized token description",$i,"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 459 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 462 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:29 + +#line 637 "/u/norman/pu/web/dist/src/master/spider.web" + +##30: + +#line 466 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 467 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_name!=""){ +print"Error: name doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 469 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:30 + +#line 638 "/u/norman/pu/web/dist/src/master/spider.web" + +##31: + +#line 471 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 472 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_tangleto!=""){ +print"Error: tangleto doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 474 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:31 + +#line 639 "/u/norman/pu/web/dist/src/master/spider.web" + +##34: + +#line 486 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 487 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_category==""){ +print"Error: you must give a category on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 489 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:34 + +#line 640 "/u/norman/pu/web/dist/src/master/spider.web" + +newline_category=this_category +newline_mathness=this_mathness +newline_translation=this_translation + +##:42 + +#line 578 "/u/norman/pu/web/dist/src/master/spider.web" + +}else if($2=="pseudo_semi"){ +##43: + +#line 646 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 647 "/u/norman/pu/web/dist/src/master/spider.web" +##36: + +#line 518 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 519 "/u/norman/pu/web/dist/src/master/spider.web" +this_translation=default_translation +this_mathness=default_mathness +this_name="" +this_category="" +this_tangleto="" +##:36 + +#line 648 "/u/norman/pu/web/dist/src/master/spider.web" + +start_place=3 +##29: + +#line 434 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 435 "/u/norman/pu/web/dist/src/master/spider.web" +for(i=start_place;i<NF;){ +if($i=="tangleto"){ +i++ +this_tangleto=$i +i++ +}else if($i=="translation"){ +i++ +this_translation=$i +i++ +}else if($i=="mathness"){ +i++ +this_mathness=$i +i++ +}else if($i=="category"){ +i++ +this_category=$i +categories[$i]=1 +i++ +}else if($i=="name"){ +i++ +this_name="SP_"$i +i++ +}else{ +print"Error: unrecognized token description",$i,"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 459 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 462 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:29 + +#line 652 "/u/norman/pu/web/dist/src/master/spider.web" + +##30: + +#line 466 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 467 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_name!=""){ +print"Error: name doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 469 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:30 + +#line 653 "/u/norman/pu/web/dist/src/master/spider.web" + +##31: + +#line 471 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 472 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_tangleto!=""){ +print"Error: tangleto doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 474 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:31 + +#line 654 "/u/norman/pu/web/dist/src/master/spider.web" + +##34: + +#line 486 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 487 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_category==""){ +print"Error: you must give a category on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 489 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:34 + +#line 655 "/u/norman/pu/web/dist/src/master/spider.web" + +pseudo_semi_category=this_category +pseudo_semi_mathness=this_mathness +pseudo_semi_translation=this_translation + +##:43 + +#line 580 "/u/norman/pu/web/dist/src/master/spider.web" + +}else if($2~/[a-zA-ZA-Z0-9]+/){ + +print"Error: unknown token species:",$2 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 584 "/u/norman/pu/web/dist/src/master/spider.web" + +}else{ +##44: + +#line 677 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 678 "/u/norman/pu/web/dist/src/master/spider.web" +this_string=$2 +##45: + +#line 700 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 701 "/u/norman/pu/web/dist/src/master/spider.web" +old_string=this_string +this_string="" + + +idx=index(old_string,"{space}") +while(idx!=0){ +temp=substr(old_string,1,idx-1) +this_string=this_string temp" " +old_string=substr(old_string,idx+7) +idx=index(old_string,"{space}") +} +this_string=this_string old_string + +##:45 + +#line 679 "/u/norman/pu/web/dist/src/master/spider.web" + + +$2=this_string + +##49: + +#line 767 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 768 "/u/norman/pu/web/dist/src/master/spider.web" +if($2=="@"){ +$2="@@" +tokenname[$2]="'@@'" +tokenlength[$2]=1 +}else if($2=="'"||$2=="\\"){ +$2="\\"$2 +tokenname[$2]="'"$2"'" +tokenlength[$2]=1 +}else if(length($2)>1){ +##50: + +#line 793 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 794 "/u/norman/pu/web/dist/src/master/spider.web" +tokenname[$2]="SP_gen_token_"tokennumber +tokennumbers[$2]=tokennumber +tokennumber-- + +temp=sprintf("strncmp(\"%s\",loc-1,%d)==0",$2,length($2)) +tokentest[$2]=temp +tokenlength[$2]=length($2) + + +##:50 + +#line 777 "/u/norman/pu/web/dist/src/master/spider.web" + +}else{ +temp=sprintf("'%s'",$2) +tokenname[$2]=temp +tokenlength[$2]=1 +} + +##:49 + +#line 684 "/u/norman/pu/web/dist/src/master/spider.web" + +if(tokens[$2]!=""){ +print"Warning: token",$2,"defined twice" +} +tokens[$2]=1 +##51: + +#line 804 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 805 "/u/norman/pu/web/dist/src/master/spider.web" +##36: + +#line 518 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 519 "/u/norman/pu/web/dist/src/master/spider.web" +this_translation=default_translation +this_mathness=default_mathness +this_name="" +this_category="" +this_tangleto="" +##:36 + +#line 806 "/u/norman/pu/web/dist/src/master/spider.web" + +this_name=tokenname[$2] +start_place=3 +##29: + +#line 434 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 435 "/u/norman/pu/web/dist/src/master/spider.web" +for(i=start_place;i<NF;){ +if($i=="tangleto"){ +i++ +this_tangleto=$i +i++ +}else if($i=="translation"){ +i++ +this_translation=$i +i++ +}else if($i=="mathness"){ +i++ +this_mathness=$i +i++ +}else if($i=="category"){ +i++ +this_category=$i +categories[$i]=1 +i++ +}else if($i=="name"){ +i++ +this_name="SP_"$i +i++ +}else{ +print"Error: unrecognized token description",$i,"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 459 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 462 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:29 + +#line 811 "/u/norman/pu/web/dist/src/master/spider.web" + +##34: + +#line 486 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 487 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_category==""){ +print"Error: you must give a category on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 489 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:34 + +#line 812 "/u/norman/pu/web/dist/src/master/spider.web" + +tokencategory[$2]=this_category +tokenmathness[$2]=this_mathness +tokentranslation[$2]=this_translation +tokenname[$2]=this_name +tokentangleto[$2]=this_tangleto + +##:51 + +#line 689 "/u/norman/pu/web/dist/src/master/spider.web" + +##53: + +#line 828 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 829 "/u/norman/pu/web/dist/src/master/spider.web" +if(tokenlength[$2]>1&&tokennumbers[$2]==""){ +print"This can't happen: token",$2,"is long",\ +"but has no number" +exitcode=-1 +} + + +##:53 + +#line 690 "/u/norman/pu/web/dist/src/master/spider.web" + +##52: + +#line 821 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 822 "/u/norman/pu/web/dist/src/master/spider.web" +temp=tokenlength[$2] +if(temp>maxtokenlength){ +maxtokenlength=temp +} + +##:52 + +#line 691 "/u/norman/pu/web/dist/src/master/spider.web" + + + +##:44 + +#line 586 "/u/norman/pu/web/dist/src/master/spider.web" + +} +categories[this_category]=1 + +next +} + +##:39 +##75: + +#line 1183 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1184 "/u/norman/pu/web/dist/src/master/spider.web" +/^ilk /{ +print"Ilk",$2>logfile +##36: + +#line 518 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 519 "/u/norman/pu/web/dist/src/master/spider.web" +this_translation=default_translation +this_mathness=default_mathness +this_name="" +this_category="" +this_tangleto="" +##:36 + +#line 1187 "/u/norman/pu/web/dist/src/master/spider.web" + +##76: + +#line 1206 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1207 "/u/norman/pu/web/dist/src/master/spider.web" +if($2~/^[a-zA-Z_]+_like$/&&$0!~/ category /){ + +this_category=substr($2,1,length($2)-5) +categories[this_category]=1 +} + +##:76 + +#line 1188 "/u/norman/pu/web/dist/src/master/spider.web" + +this_name="" +start_place=3 +##29: + +#line 434 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 435 "/u/norman/pu/web/dist/src/master/spider.web" +for(i=start_place;i<NF;){ +if($i=="tangleto"){ +i++ +this_tangleto=$i +i++ +}else if($i=="translation"){ +i++ +this_translation=$i +i++ +}else if($i=="mathness"){ +i++ +this_mathness=$i +i++ +}else if($i=="category"){ +i++ +this_category=$i +categories[$i]=1 +i++ +}else if($i=="name"){ +i++ +this_name="SP_"$i +i++ +}else{ +print"Error: unrecognized token description",$i,"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 459 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 462 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:29 + +#line 1193 "/u/norman/pu/web/dist/src/master/spider.web" + +##34: + +#line 486 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 487 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_category==""){ +print"Error: you must give a category on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 489 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:34 + +#line 1194 "/u/norman/pu/web/dist/src/master/spider.web" + +##30: + +#line 466 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 467 "/u/norman/pu/web/dist/src/master/spider.web" +if(this_name!=""){ +print"Error: name doesn't apply on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 469 "/u/norman/pu/web/dist/src/master/spider.web" + +} +##:30 + +#line 1195 "/u/norman/pu/web/dist/src/master/spider.web" + +ilk_category[$2]=this_category +ilk_mathness[$2]=this_mathness +ilk_translation[$2]=this_translation +next +} + + +##:75 +##77: + +#line 1220 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1221 "/u/norman/pu/web/dist/src/master/spider.web" +/^reserved /{ +print"Reserved word",$2>logfile +if($0!~/ ilk /){ +##78: + +#line 1246 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1247 "/u/norman/pu/web/dist/src/master/spider.web" +temp=$2"_like" +reservedilk[$2]=temp +if(ilk_translation[temp]==""){ +ilk_translation[temp]=default_translation +} +has_reserved[temp]=1 +if(ilk_mathness[temp]==""){ +ilk_mathness[temp]=default_mathness +} + +if(ilk_category[temp]==""){ +ilk_category[temp]=$2 +categories[$2]=1 +} +ilk_is_made_up[temp]=1 + + + +##:78 + +#line 1224 "/u/norman/pu/web/dist/src/master/spider.web" + +} +for(i=3;i<=NF;){ +if($i=="ilk"){ +i++ +reservedilk[$2]=$i +has_reserved[$i]=1 +i++ +}else{ +print"Error: bad reserved word attribute:",$i,\ +"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1235 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 1238 "/u/norman/pu/web/dist/src/master/spider.web" + +next +} + +##:77 +##129: + +#line 2071 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2072 "/u/norman/pu/web/dist/src/master/spider.web" +/^language /{ +language=$2 +extension=language +for(i=3;i<NF;){ +if($i=="extension"){ +i++ +extension=$i +i++ +}else if($i=="version"){ +i++ +version=$i +i++ +}else{ +print"Error: unknown language property",$i,\ +"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2087 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 2090 "/u/norman/pu/web/dist/src/master/spider.web" + +##131: + +#line 2125 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2126 "/u/norman/pu/web/dist/src/master/spider.web" +macrofile=extension"web.tex" +print"\\input webkernel.tex">macrofile + + +##:131 + +#line 2091 "/u/norman/pu/web/dist/src/master/spider.web" + +next +} + +##:129 +##132: + +#line 2132 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2133 "/u/norman/pu/web/dist/src/master/spider.web" +/^macros begin$/,/^macros end$/{ +if(begunmacs==0){ +begunmacs=1 +next +} +if($0~/^macros end$/){ +begunmacs=0 +next +} +if(macrofile==""){ +if(complained==0){ +print"Error: you must give \"language\"",\ +"before \"macros\"" +complained=1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2147 "/u/norman/pu/web/dist/src/master/spider.web" + +} +}else{ +print $0>macrofile +} +next +} + + + +##:132 +##133: + +#line 2163 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2164 "/u/norman/pu/web/dist/src/master/spider.web" +/^module /{ +for(i=2;i<NF;){ +if($i=="definition"){ +i++ +mod_def_cat=$i +categories[$i]=1 +print"Module definition category set to",$i>logfile +i++ +}else if($i=="use"){ +i++ +mod_use_cat=$i +categories[$i]=1 +print"Module use category set to",$i>logfile +i++ +}else{ +print"Error: unknown module property",$i,\ +"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2181 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 2184 "/u/norman/pu/web/dist/src/master/spider.web" + +next +} + +##:133 +##135: + +#line 2213 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2214 "/u/norman/pu/web/dist/src/master/spider.web" +/^at_sign /{ +if(NF==2&&length($2)==1){ +if($2=="@"){ +at_sign="@@" +}else{ +at_sign=$2 +} +}else{ +print"Error: I can't understand",$0 +print" Give me an at sign of length 1" +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2224 "/u/norman/pu/web/dist/src/master/spider.web" + +} +next +} + +##:135 +##139: + +#line 2254 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2255 "/u/norman/pu/web/dist/src/master/spider.web" +/^comment /{ +print $0>logfile +for(i=2;i<NF;){ +if($i=="begin"){ +i++ +if($i~/^<.*>$/){ +transstring=$i +wherestring="in \"comment begin\" on line "NR-1 +##27: + +#line 389 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 390 "/u/norman/pu/web/dist/src/master/spider.web" +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 395 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +print"Digit not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^[a-zA-Z_]+$/){ +print"Key word not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=substr(alternate,2,length(alternate)-2) +outstring=outstring temp +}else if(alternate~/^\*$/){ +print"<*> not allowed in restricted translation",wherestring +exitcode=-1 +}else{ +print"Bogus restricted translation",wherestring +exitcode=-1 +} +} +outstring="\""outstring"\"" + + + +##:27 + +#line 2264 "/u/norman/pu/web/dist/src/master/spider.web" + +begin_comment_string=outstring +i++ +}else{ +print"Error: \"comment begin\" must have a restricted translation" +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2269 "/u/norman/pu/web/dist/src/master/spider.web" + +} +}else if($i=="end"){ +i++ +if($i=="newline"){ +comments_end_with_newline=1 +end_comment_string="\"\\n\"" +}else if($i~/^<.*>$/){ +comments_end_with_newline=0 +transstring=$i +wherestring="in \"comment end\" on line "NR-1 +##27: + +#line 389 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 390 "/u/norman/pu/web/dist/src/master/spider.web" +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 395 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +print"Digit not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^[a-zA-Z_]+$/){ +print"Key word not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=substr(alternate,2,length(alternate)-2) +outstring=outstring temp +}else if(alternate~/^\*$/){ +print"<*> not allowed in restricted translation",wherestring +exitcode=-1 +}else{ +print"Bogus restricted translation",wherestring +exitcode=-1 +} +} +outstring="\""outstring"\"" + + + +##:27 + +#line 2282 "/u/norman/pu/web/dist/src/master/spider.web" + +end_comment_string=outstring +}else{ +print"Error: \"comment end\" must have a restricted translation" +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2286 "/u/norman/pu/web/dist/src/master/spider.web" + +} +i++ +}else{ +print"Error: bad comment attribute:",$i +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2291 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 2294 "/u/norman/pu/web/dist/src/master/spider.web" + +##145: + +#line 2376 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2377 "/u/norman/pu/web/dist/src/master/spider.web" +if(macrofile!=""){ +this_string=substr(begin_comment_string,2,length(begin_comment_string)-2) +##147: + +#line 2410 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2411 "/u/norman/pu/web/dist/src/master/spider.web" +tex_string="" +while(length(this_string)>0){ +c=substr(this_string,1,1) +this_string=substr(this_string,2) +cprime=texof[c] +if(cprime==""){ +tex_string=tex_string c +}else{ +tex_string=tex_string cprime +} +} + +##:147 + +#line 2379 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"\\def\\commentbegin{%s}\n",tex_string>macrofile +if(comments_end_with_newline==0){ +this_string=substr(end_comment_string,2,length(end_comment_string)-2) +##147: + +#line 2410 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2411 "/u/norman/pu/web/dist/src/master/spider.web" +tex_string="" +while(length(this_string)>0){ +c=substr(this_string,1,1) +this_string=substr(this_string,2) +cprime=texof[c] +if(cprime==""){ +tex_string=tex_string c +}else{ +tex_string=tex_string cprime +} +} + +##:147 + +#line 2383 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"\\def\\commentend{%s}\n",tex_string>macrofile +}else{ +print"\\def\\commentend{\\relax}">macrofile +} +}else{ +print"Error: I can't write comment info to the macro file---" +print" you haven't given me any \"language\" information" +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2391 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + + +##:145 + +#line 2295 "/u/norman/pu/web/dist/src/master/spider.web" + +next +} + +##:139 +##148: + +#line 2428 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2429 "/u/norman/pu/web/dist/src/master/spider.web" +/^line /{ +print $0>logfile +for(i=2;i<NF;){ +if($i=="begin"){ +i++ +if($i~/^<.*>$/){ +transstring=$i +wherestring="in \"line begin\" on line "NR-1 +##27: + +#line 389 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 390 "/u/norman/pu/web/dist/src/master/spider.web" +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 395 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +print"Digit not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^[a-zA-Z_]+$/){ +print"Key word not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=substr(alternate,2,length(alternate)-2) +outstring=outstring temp +}else if(alternate~/^\*$/){ +print"<*> not allowed in restricted translation",wherestring +exitcode=-1 +}else{ +print"Bogus restricted translation",wherestring +exitcode=-1 +} +} +outstring="\""outstring"\"" + + + +##:27 + +#line 2438 "/u/norman/pu/web/dist/src/master/spider.web" + +sharp_line_open=outstring +i++ +}else{ +print"Error: \"line begin\" must have a restricted translation" +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2443 "/u/norman/pu/web/dist/src/master/spider.web" + +} +}else if($i=="end"){ +i++ +if($i~/^<.*>$/){ +transstring=$i +wherestring="in \"line end\" on line "NR-1 +##27: + +#line 389 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 390 "/u/norman/pu/web/dist/src/master/spider.web" +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 395 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +print"Digit not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^[a-zA-Z_]+$/){ +print"Key word not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=substr(alternate,2,length(alternate)-2) +outstring=outstring temp +}else if(alternate~/^\*$/){ +print"<*> not allowed in restricted translation",wherestring +exitcode=-1 +}else{ +print"Bogus restricted translation",wherestring +exitcode=-1 +} +} +outstring="\""outstring"\"" + + + +##:27 + +#line 2452 "/u/norman/pu/web/dist/src/master/spider.web" + +sharp_line_close=outstring +}else{ +print"Error: \"line end\" must have a restricted translation" +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2456 "/u/norman/pu/web/dist/src/master/spider.web" + +} +i++ +}else{ +print"Error: bad line attribute:",$i,"on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 2461 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +##5: + +#line 91 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 92 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: leftover fields",$i,"... on line",NR-1 +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 94 "/u/norman/pu/web/dist/src/master/spider.web" + +} + + +##:5 + +#line 2464 "/u/norman/pu/web/dist/src/master/spider.web" + +next +} + +##:148 +##151: + +#line 2481 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2482 "/u/norman/pu/web/dist/src/master/spider.web" +/^date /{ + +mo=month[$3] +day=$4 +year=$7 +time=$5 +##153: + +#line 2510 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2511 "/u/norman/pu/web/dist/src/master/spider.web" +hour=substr(time,1,2) +if(hour>=12) +ampm="PM" +else +ampm="AM" + +if(hour==0){ +hour=12 +}else if(hour>12){ +hour=hour-12 +} +minute=substr(time,4,2) + + +##:153 + +#line 2488 "/u/norman/pu/web/dist/src/master/spider.web" + +date=sprintf("(generated at %d:%s %s on %s %d, %d)",\ +hour,minute,ampm,mo,day,year) +next +} + +##:151 + +#line 60 "/u/norman/pu/web/dist/src/master/spider.web" + +##88: + +#line 1442 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1443 "/u/norman/pu/web/dist/src/master/spider.web" +/-->/{ +##89: + +#line 1471 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1472 "/u/norman/pu/web/dist/src/master/spider.web" +lowpos=0;highpos=0;pos=1 +prodnum=prodnum+1 +inputline[prodnum]=$0 +print"Parsing production",prodnum,$0>logfile + + +##:89 + +#line 1444 "/u/norman/pu/web/dist/src/master/spider.web" + +##90: + +#line 1492 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1493 "/u/norman/pu/web/dist/src/master/spider.web" +trans[pos]="" +for(i=1;i<=NF;i++){ +if($i~/<.*>/){ +##92: + +#line 1525 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1526 "/u/norman/pu/web/dist/src/master/spider.web" +transstring=$i +selfstring="" +wherestring=sprintf("in production on line %d",NR-1) +append_keyword="app" +##24: + +#line 336 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 342 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +temp=sprintf("\tapp_str(\"%s\");\n",alternate) +outstring=outstring temp +}else if(alternate~/^[a-zA-Z_]+$/){ +translation_keywords[alternate]=1 +temp=sprintf("\t%s(%s);\n",append_keyword,alternate) + +outstring=outstring temp +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=sprintf("\tapp_str(%s);\n",alternate) +outstring=outstring temp +}else if(alternate~/^\*$/){ +##26: + +#line 377 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 378 "/u/norman/pu/web/dist/src/master/spider.web" +if(selfstring==""){ +print"Translation \"<*>\" makes no sense",wherestring +exitcode=-1 +} + +##:26 + +#line 355 "/u/norman/pu/web/dist/src/master/spider.web" + +outstring=outstring selfstring +}else{ +print"Bogus translation",wherestring +exitcode=-1 +} +} + +##:24 + +#line 1531 "/u/norman/pu/web/dist/src/master/spider.web" + +trans[pos]=trans[pos]outstring + +##:92 + +#line 1496 "/u/norman/pu/web/dist/src/master/spider.web" + +}else if($i~/^!?[a-zA-Z_]+(\*\*?)?$/){ +##93: + +#line 1543 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1544 "/u/norman/pu/web/dist/src/master/spider.web" +field[pos]=$i +##96: + +#line 1606 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1607 "/u/norman/pu/web/dist/src/master/spider.web" +temp=substr($i,1,1) +if(temp=="!"){ +negation=1 +$i=substr($i,2) +}else{ +negation=0 +} + +##:96 + +#line 1545 "/u/norman/pu/web/dist/src/master/spider.web" + +##98: + +#line 1638 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1639 "/u/norman/pu/web/dist/src/master/spider.web" +if($i~/^([a-zA-Z_]+|\(([a-zA-Z_]+\|)*[a-zA-Z_]+\))\*\*$/){ +temp=sprintf("\tmake_underlined(pp+%d);\n",pos-1) +trans[pos]=trans[pos]temp +$i=substr($i,1,length($i)-2) +}else if($i~/^([a-zA-Z_]+|\(([a-zA-Z_]+\|)*[a-zA-Z_]+\))\*$/){ +temp=sprintf("\tmake_underlined(pp+%d);\n",pos-1) +trans[pos]=trans[pos]temp +$i=substr($i,1,length($i)-1) +}else if($i~/\*$/){ +print"Error: can't remove stars in production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1649 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:98 + +#line 1547 "/u/norman/pu/web/dist/src/master/spider.web" + +cat=$i +categories[cat]=1 +if(negation==0){ +test[pos]=sprintf("(pp+%d)->cat==SP_%s",pos-1,cat) +}else{ +test[pos]=sprintf("((pp+%d)->cat!=SP_%s && (pp+%d)->cat != 0)",\ +pos-1,cat,pos-1) +} +##95: + +#line 1597 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1598 "/u/norman/pu/web/dist/src/master/spider.web" +if(pos>highestpos[cat]){ +highestpos[cat]=pos +} + +##:95 + +#line 1556 "/u/norman/pu/web/dist/src/master/spider.web" + +##97: + +#line 1619 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1620 "/u/norman/pu/web/dist/src/master/spider.web" +pos=pos+1 +trans[pos]="" + +##:97 + +#line 1557 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:93 + +#line 1498 "/u/norman/pu/web/dist/src/master/spider.web" + +}else if($i~/^!?\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/){ +##94: + +#line 1567 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1568 "/u/norman/pu/web/dist/src/master/spider.web" +field[pos]=$i +##96: + +#line 1606 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1607 "/u/norman/pu/web/dist/src/master/spider.web" +temp=substr($i,1,1) +if(temp=="!"){ +negation=1 +$i=substr($i,2) +}else{ +negation=0 +} + +##:96 + +#line 1569 "/u/norman/pu/web/dist/src/master/spider.web" + +if(negation==0){ +test[pos]="(" +}else{ +temp=sprintf("(pp+%d)->cat==0",pos-1) +test[pos]="!("temp"||" +} +##98: + +#line 1638 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1639 "/u/norman/pu/web/dist/src/master/spider.web" +if($i~/^([a-zA-Z_]+|\(([a-zA-Z_]+\|)*[a-zA-Z_]+\))\*\*$/){ +temp=sprintf("\tmake_underlined(pp+%d);\n",pos-1) +trans[pos]=trans[pos]temp +$i=substr($i,1,length($i)-2) +}else if($i~/^([a-zA-Z_]+|\(([a-zA-Z_]+\|)*[a-zA-Z_]+\))\*$/){ +temp=sprintf("\tmake_underlined(pp+%d);\n",pos-1) +trans[pos]=trans[pos]temp +$i=substr($i,1,length($i)-1) +}else if($i~/\*$/){ +print"Error: can't remove stars in production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1649 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:98 + +#line 1577 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=substr($i,2,length($i)-2) +m=split(temp,tok,"|") +for(j=1;j<=m;j++){ +cat=tok[j] +categories[cat]=1 +##95: + +#line 1597 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1598 "/u/norman/pu/web/dist/src/master/spider.web" +if(pos>highestpos[cat]){ +highestpos[cat]=pos +} + +##:95 + +#line 1584 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=sprintf("(pp+%d)->cat==SP_%s",pos-1,cat) +test[pos]=test[pos]temp +if(j!=m) +test[pos]=test[pos]"||\n" +} +test[pos]=test[pos]")" +##97: + +#line 1619 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1620 "/u/norman/pu/web/dist/src/master/spider.web" +pos=pos+1 +trans[pos]="" + +##:97 + +#line 1591 "/u/norman/pu/web/dist/src/master/spider.web" + + + +##:94 + +#line 1500 "/u/norman/pu/web/dist/src/master/spider.web" + +}else if($i=="?"){ +##99: + +#line 1654 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1655 "/u/norman/pu/web/dist/src/master/spider.web" +field[pos]=$i +test[pos]=sprintf("(pp+%d)->cat!=0",pos-1) +highwildcard=pos +##97: + +#line 1619 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1620 "/u/norman/pu/web/dist/src/master/spider.web" +pos=pos+1 +trans[pos]="" + +##:97 + +#line 1658 "/u/norman/pu/web/dist/src/master/spider.web" + + + + +##:99 + +#line 1502 "/u/norman/pu/web/dist/src/master/spider.web" + +}else if($i=="["){ +lowpos=pos +}else if($i=="]"){ +highpos=pos +}else if($i=="-->"){ +break +}else{ +print"Error: bad field is",$i,"in production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1511 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} +i++ + + +##:90 + +#line 1445 "/u/norman/pu/web/dist/src/master/spider.web" + +##100: + +#line 1679 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1680 "/u/norman/pu/web/dist/src/master/spider.web" +arrowpos=pos +if(lowpos==0&&highpos==0){ +lowpos=1 +highpos=arrowpos + +}else if(lowpos==0||highpos==0){ +print"Error: square brackets don't balance in",\ +"production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1688 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:100 + +#line 1446 "/u/norman/pu/web/dist/src/master/spider.web" + +##101: + +#line 1693 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1694 "/u/norman/pu/web/dist/src/master/spider.web" +if(arrowpos-1>highestposoverall){ +highestposoverall=arrowpos-1 +} + +##:101 + +#line 1447 "/u/norman/pu/web/dist/src/master/spider.web" + +##102: + +#line 1708 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1709 "/u/norman/pu/web/dist/src/master/spider.web" +for(hup=arrowpos-1;field[hup]=="?";){ +hup-- +} +for(;hup>highestunknownpos;hup--){ +temp=field[hup] +temp=substr(temp,1,1) +if(temp=="?"||temp=="!"){ +highestunknownpos=hup +break +} +} + +##:102 + +#line 1448 "/u/norman/pu/web/dist/src/master/spider.web" + +##103: + +#line 1722 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1723 "/u/norman/pu/web/dist/src/master/spider.web" +for(pos=1;pos<lowpos;pos++){ +##105: + +#line 1733 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1734 "/u/norman/pu/web/dist/src/master/spider.web" +if(i>NF||$i!=field[pos]){ +print"Error: token mismatch is: found",$i,\ +"sought",field[pos],"on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1737 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:105 + +#line 1724 "/u/norman/pu/web/dist/src/master/spider.web" + +i++ +} + +##:103 + +#line 1449 "/u/norman/pu/web/dist/src/master/spider.web" + +##106: + +#line 1746 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1747 "/u/norman/pu/web/dist/src/master/spider.web" + +if(i>NF){ +print"Error: no target category in production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1750 "/u/norman/pu/web/dist/src/master/spider.web" + +} +if($i~/#[0-9]+/){ +$i=substr($i,2) +##117: + +#line 1867 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1868 "/u/norman/pu/web/dist/src/master/spider.web" +if((0+$i)<1||(0+$i)>=0+arrowpos){ +print"Error: can't take token number",$i,"of",arrowpos-1,\ +"tokens","in production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1871 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:117 + +#line 1754 "/u/norman/pu/web/dist/src/master/spider.web" + +targetcategory[prodnum]="Unnamed category" +temp=sprintf("(pp+%d)->cat",$i-1) +unnamed_cat[prodnum]=temp +}else if($i~/[a-zA-Z][a-zA-Z_]*/){ +targetcategory[prodnum]=$i +categories[$i]=1 +}else{ +print"Error: unrecognizable target token",$i,\ +"in production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1764 "/u/norman/pu/web/dist/src/master/spider.web" + +} +i++ + +##:106 + +#line 1450 "/u/norman/pu/web/dist/src/master/spider.web" + +##104: + +#line 1728 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1729 "/u/norman/pu/web/dist/src/master/spider.web" +for(pos=highpos;pos<arrowpos;pos++){ +##105: + +#line 1733 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1734 "/u/norman/pu/web/dist/src/master/spider.web" +if(i>NF||$i!=field[pos]){ +print"Error: token mismatch is: found",$i,\ +"sought",field[pos],"on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1737 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:105 + +#line 1730 "/u/norman/pu/web/dist/src/master/spider.web" + +i++ +} +##:104 + +#line 1451 "/u/norman/pu/web/dist/src/master/spider.web" + +##107: + +#line 1769 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1770 "/u/norman/pu/web/dist/src/master/spider.web" +if(i<=NF){ +print"Error: used only "i-1" of "NF" tokens",\ +"in production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1773 "/u/norman/pu/web/dist/src/master/spider.web" + +} + +##:107 + +#line 1452 "/u/norman/pu/web/dist/src/master/spider.web" + +##108: + +#line 1779 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1780 "/u/norman/pu/web/dist/src/master/spider.web" +prodtest[prodnum]="" +for(pos=1;pos<arrowpos;pos++){ +if(pos>1){ +prodtest[prodnum]=prodtest[prodnum]" &&\n\t\t" +} +prodtest[prodnum]=prodtest[prodnum]test[pos] +} + +##:108 + +#line 1454 "/u/norman/pu/web/dist/src/master/spider.web" + +##109: + +#line 1789 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1790 "/u/norman/pu/web/dist/src/master/spider.web" +prodtrans[prodnum]="" +for(pos=lowpos;pos<highpos;pos++){ +prodtrans[prodnum]=prodtrans[prodnum]trans[pos] + +temp=sprintf("\tapp1(pp+%d);\n",pos-1) +prodtrans[prodnum]=prodtrans[prodnum]temp +##114: + +#line 1830 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1831 "/u/norman/pu/web/dist/src/master/spider.web" +temp=field[pos] +tempa=substr(temp,1,1) +if(tempa!="!"){ +if(temp~/^\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/){ + +##115: + +#line 1853 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1854 "/u/norman/pu/web/dist/src/master/spider.web" +while(temp~/\*$/){ +temp=substr(temp,1,length(temp)-1) +} + +##:115 + +#line 1836 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=substr(temp,2,length(temp)-2) +m=split(temp,tok,"|") +for(j=1;j<=m;j++){ +alternate=tok[j] +reduced[alternate]=1 +} +}else if(temp~/^[a-zA-Z_]+(\*\*?)?$/){ +##115: + +#line 1853 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1854 "/u/norman/pu/web/dist/src/master/spider.web" +while(temp~/\*$/){ +temp=substr(temp,1,length(temp)-1) +} + +##:115 + +#line 1844 "/u/norman/pu/web/dist/src/master/spider.web" + +reduced[temp]=1 +}else if(temp!="?"){ +print"Confusion: unintelligible field[pos]:",temp,\ +"in production on line",NR-1 +##91: + +#line 1519 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1520 "/u/norman/pu/web/dist/src/master/spider.web" +prodnum-- +##4: + +#line 79 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 80 "/u/norman/pu/web/dist/src/master/spider.web" +exitcode=-1 +next + + +##:4 + +#line 1521 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:91 + +#line 1849 "/u/norman/pu/web/dist/src/master/spider.web" + +} +} + +##:114 + +#line 1798 "/u/norman/pu/web/dist/src/master/spider.web" + +} +prodtrans[prodnum]=prodtrans[prodnum]trans[highpos] + +##:109 + +#line 1456 "/u/norman/pu/web/dist/src/master/spider.web" + +##110: + +#line 1803 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1804 "/u/norman/pu/web/dist/src/master/spider.web" +ppstart[prodnum]=lowpos-1 +tokensreduced[prodnum]=highpos-lowpos + +##:110 + +#line 1458 "/u/norman/pu/web/dist/src/master/spider.web" + +##111: + +#line 1808 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1809 "/u/norman/pu/web/dist/src/master/spider.web" +if(highpos-lowpos==1){ +printf"%d: %s --> %s\n",prodnum,field[lowpos],\ +targetcategory[prodnum]>cycles +wrotecycles=1 +} + +##:111 + +#line 1460 "/u/norman/pu/web/dist/src/master/spider.web" + +next +} + +##:88 + +#line 61 "/u/norman/pu/web/dist/src/master/spider.web" + +##7: + +#line 108 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 109 "/u/norman/pu/web/dist/src/master/spider.web" +{ +print"Warning: I don't know what to do with this line:" +print" ",$0 +print"Warning: I don't know what to do with this line:">logfile +print" ",$0>logfile +} + + +##:7 + +#line 62 "/u/norman/pu/web/dist/src/master/spider.web" + + +END{ +##54: + +#line 847 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 848 "/u/norman/pu/web/dist/src/master/spider.web" +tempfile=scrapfile +##55: + +#line 854 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 855 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Here we input tokens of more than one character">tempfile +print"@<Compress two-symbol operator@>=">tempfile +##56: + +#line 863 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 864 "/u/norman/pu/web/dist/src/master/spider.web" +for(len=maxtokenlength;len>=2;len--){ +printf"if (loc+%d<=limit) {\n",len-1>tempfile +##57: + +#line 871 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 872 "/u/norman/pu/web/dist/src/master/spider.web" +notfirst=0 +for(t in tokentest){ +if(tokenlength[t]==len){ +printf"\t">tempfile +if(notfirst==1){ +printf"else ">tempfile +} +notfirst=1 +printf"if (%s) {\n",tokentest[t]>tempfile +printf"\t\tloc += %d;\n",len-1>tempfile +printf"\t\treturn %s;\n\t\t}\n",tokenname[t]>tempfile +} +} + + +##:57 + +#line 866 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"\t}\n">tempfile +} +##58: + +#line 887 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 888 "/u/norman/pu/web/dist/src/master/spider.web" +for(t in tokentest){ +if(tokenlength[t]==1){ +print"This can't happen: token",t,"is of length 1 but",\ +"it has a test" +exitcode=-1 +} +} + + + +##:58 + +#line 869 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:56 + +#line 858 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:55 + +#line 849 "/u/norman/pu/web/dist/src/master/spider.web" + +tempfile=ttokfile +##55: + +#line 854 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 855 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Here we input tokens of more than one character">tempfile +print"@<Compress two-symbol operator@>=">tempfile +##56: + +#line 863 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 864 "/u/norman/pu/web/dist/src/master/spider.web" +for(len=maxtokenlength;len>=2;len--){ +printf"if (loc+%d<=limit) {\n",len-1>tempfile +##57: + +#line 871 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 872 "/u/norman/pu/web/dist/src/master/spider.web" +notfirst=0 +for(t in tokentest){ +if(tokenlength[t]==len){ +printf"\t">tempfile +if(notfirst==1){ +printf"else ">tempfile +} +notfirst=1 +printf"if (%s) {\n",tokentest[t]>tempfile +printf"\t\tloc += %d;\n",len-1>tempfile +printf"\t\treturn %s;\n\t\t}\n",tokenname[t]>tempfile +} +} + + +##:57 + +#line 866 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"\t}\n">tempfile +} +##58: + +#line 887 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 888 "/u/norman/pu/web/dist/src/master/spider.web" +for(t in tokentest){ +if(tokenlength[t]==1){ +print"This can't happen: token",t,"is of length 1 but",\ +"it has a test" +exitcode=-1 +} +} + + + +##:58 + +#line 869 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:56 + +#line 858 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:55 + +#line 851 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:54 +##59: + +#line 904 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 905 "/u/norman/pu/web/dist/src/master/spider.web" +print"Writing out predefined scraps">logfile +##60: + +#line 917 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 918 "/u/norman/pu/web/dist/src/master/spider.web" +if(id_category!=""){ +print"@ @<Append an identifier scrap@>=">scrapfile +print"p=id_lookup(id_first, id_loc,normal);">scrapfile +print"if (p->ilk==normal) {">scrapfile +print" small_app(id_flag+p-name_dir);">scrapfile +printf" app_scrap(SP_%s,%s_math);",\ +id_category,id_mathness>scrapfile +appended[id_category]=1 +print" /* not a reserved word */">scrapfile +print"}">scrapfile +print"else if reserved(p) {">scrapfile +print"@<Decide on reserved word scraps@>;">scrapfile +print"}">scrapfile +print"else {">scrapfile +print" err_print(\"! Identifier with unmentioned ilk\");">scrapfile +print"@.Identifier with unmentioned ilk@>">scrapfile +print"}">scrapfile +}else{ +print"Error: I don't know what to do with an identifier" +print" Please give me a \"token identifier ...\"" +exitcode=-1 +} + +##:60 + +#line 906 "/u/norman/pu/web/dist/src/master/spider.web" + +##62: + +#line 948 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 949 "/u/norman/pu/web/dist/src/master/spider.web" +print"Warning: TeX strings have the same category as ",\ +"numeric constants in this WEAVE." +print"Warning: TeX strings have the same category as ",\ +"numeric constants in this WEAVE.">logfile +if(number_category!=""){ +print"@ For some reason strings, constants,",\ +" and \TeX\ strings are identified.">scrapfile +print"That has to be fixed.">scrapfile +print"@<Do the |app_scrap| for a string or constant@>=">scrapfile +printf"app_scrap(SP_%s,%s_math);\n",number_category,\ +number_mathness>scrapfile +appended[number_category]=1 +}else{ +print"Error: I don't know what to do with a numeric constant" +print" Please give me a \"token number ...\"" +exitcode=-1 +} + + +##:62 + +#line 907 "/u/norman/pu/web/dist/src/master/spider.web" + +##64: + +#line 977 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 978 "/u/norman/pu/web/dist/src/master/spider.web" +if(newline_category!=""){ +print"@ @<Append a newline scrap@>=">scrapfile +transstring=newline_translation +selfstring="small_app(next_control);" +wherestring="in translation of token newline" +append_keyword="small_app" +##24: + +#line 336 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 342 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +temp=sprintf("\tapp_str(\"%s\");\n",alternate) +outstring=outstring temp +}else if(alternate~/^[a-zA-Z_]+$/){ +translation_keywords[alternate]=1 +temp=sprintf("\t%s(%s);\n",append_keyword,alternate) + +outstring=outstring temp +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=sprintf("\tapp_str(%s);\n",alternate) +outstring=outstring temp +}else if(alternate~/^\*$/){ +##26: + +#line 377 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 378 "/u/norman/pu/web/dist/src/master/spider.web" +if(selfstring==""){ +print"Translation \"<*>\" makes no sense",wherestring +exitcode=-1 +} + +##:26 + +#line 355 "/u/norman/pu/web/dist/src/master/spider.web" + +outstring=outstring selfstring +}else{ +print"Bogus translation",wherestring +exitcode=-1 +} +} + +##:24 + +#line 985 "/u/norman/pu/web/dist/src/master/spider.web" + +print outstring>scrapfile +printf" app_scrap(SP_%s,%s_math);\n",newline_category,\ +newline_mathness>scrapfile +appended[newline_category]=1 +}else{ +print"Error: I don't know what to do with a newline" +print" Please give me a \"token newline ...\"" +exitcode=-1 +} + +##:64 + +#line 908 "/u/norman/pu/web/dist/src/master/spider.web" + +##65: + +#line 997 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 998 "/u/norman/pu/web/dist/src/master/spider.web" +if(pseudo_semi_category!=""){ +print"@ @<Append a |pseudo_semi| scrap@>=">scrapfile +transstring=pseudo_semi_translation +selfstring="small_app(next_control);" +wherestring="in translation of token pseudo_semi" +append_keyword="small_app" +##24: + +#line 336 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 342 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +temp=sprintf("\tapp_str(\"%s\");\n",alternate) +outstring=outstring temp +}else if(alternate~/^[a-zA-Z_]+$/){ +translation_keywords[alternate]=1 +temp=sprintf("\t%s(%s);\n",append_keyword,alternate) + +outstring=outstring temp +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=sprintf("\tapp_str(%s);\n",alternate) +outstring=outstring temp +}else if(alternate~/^\*$/){ +##26: + +#line 377 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 378 "/u/norman/pu/web/dist/src/master/spider.web" +if(selfstring==""){ +print"Translation \"<*>\" makes no sense",wherestring +exitcode=-1 +} + +##:26 + +#line 355 "/u/norman/pu/web/dist/src/master/spider.web" + +outstring=outstring selfstring +}else{ +print"Bogus translation",wherestring +exitcode=-1 +} +} + +##:24 + +#line 1005 "/u/norman/pu/web/dist/src/master/spider.web" + +print outstring>scrapfile +printf" app_scrap(SP_%s,%s_math);\n",pseudo_semi_category,\ +pseudo_semi_mathness>scrapfile +appended[pseudo_semi_category]=1 +}else{ +printf"Error: I don't know what to do with a pseudo_semi (%s;)",\ +substr(at_sign,1,1) +print" Please give me a \"token pseudo_semi ...\"" +exitcode=-1 +} + +##:65 + +#line 909 "/u/norman/pu/web/dist/src/master/spider.web" + +print"Writing out token scraps">logfile +##66: + +#line 1018 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1019 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ @<Cases for ordinary tokens@>=">scrapfile +for(t in tokens){ +temp=tokenname[t] +printf"case %s:\n",temp>scrapfile +transstring=tokentranslation[t] +selfstring="small_app(next_control);" +wherestring=sprintf("in translation of token %s",t) +append_keyword="small_app" +##24: + +#line 336 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 342 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +temp=sprintf("\tapp_str(\"%s\");\n",alternate) +outstring=outstring temp +}else if(alternate~/^[a-zA-Z_]+$/){ +translation_keywords[alternate]=1 +temp=sprintf("\t%s(%s);\n",append_keyword,alternate) + +outstring=outstring temp +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=sprintf("\tapp_str(%s);\n",alternate) +outstring=outstring temp +}else if(alternate~/^\*$/){ +##26: + +#line 377 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 378 "/u/norman/pu/web/dist/src/master/spider.web" +if(selfstring==""){ +print"Translation \"<*>\" makes no sense",wherestring +exitcode=-1 +} + +##:26 + +#line 355 "/u/norman/pu/web/dist/src/master/spider.web" + +outstring=outstring selfstring +}else{ +print"Bogus translation",wherestring +exitcode=-1 +} +} + +##:24 + +#line 1028 "/u/norman/pu/web/dist/src/master/spider.web" + +print outstring>scrapfile +printf"\tapp_scrap(SP_%s,%s_math);\n",tokencategory[t],\ +tokenmathness[t]>scrapfile +temp=tokencategory[t] +appended[temp]=1 + +print"\tbreak;">scrapfile +} + +##:66 + +#line 911 "/u/norman/pu/web/dist/src/master/spider.web" + + + + + +##:59 +##67: + +#line 1047 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1048 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ @<Cases for tokens to be output@>=">ttokfile +for(t in tokennumbers){ +##69: + +#line 1099 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1100 "/u/norman/pu/web/dist/src/master/spider.web" +if(t=="string"||t=="constant"||t=="identifier") +continue + + + +##:69 + +#line 1050 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"case %s:\n",tokenname[t]>ttokfile +this_tangleto=tokentangleto[t] +if(this_tangleto==""){ +printf"\tC_printf(\"%%s\",\"%s\");\n",t>ttokfile +}else{ +printf"\tif (out_state==verbatim) {\n">ttokfile +printf"\t\tC_printf(\"%%s\",\"%s\");\n",t>ttokfile +printf"\t} else {\n">ttokfile +##70: + +#line 1106 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1107 "/u/norman/pu/web/dist/src/master/spider.web" +oldwherestring=wherestring +wherestring="for tangleto "wherestring + +transstring=this_tangleto +##27: + +#line 389 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 390 "/u/norman/pu/web/dist/src/master/spider.web" +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 395 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +print"Digit not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^[a-zA-Z_]+$/){ +print"Key word not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=substr(alternate,2,length(alternate)-2) +outstring=outstring temp +}else if(alternate~/^\*$/){ +print"<*> not allowed in restricted translation",wherestring +exitcode=-1 +}else{ +print"Bogus restricted translation",wherestring +exitcode=-1 +} +} +outstring="\""outstring"\"" + + + +##:27 + +#line 1112 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"\tC_printf(\"%%s\",%s);\n",outstring>ttokfile + +wherestring=oldwherestring + + + +##:70 + +#line 1059 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"\t}\n">ttokfile +} +print"\tif (out_state!=verbatim) out_state=misc;">ttokfile +print"break;">ttokfile +} + +##:67 +##68: + +#line 1068 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1069 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ @<Cases for tokens to be output@>=">ttokfile +for(t in tokentangleto){ +##69: + +#line 1099 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1100 "/u/norman/pu/web/dist/src/master/spider.web" +if(t=="string"||t=="constant"||t=="identifier") +continue + + + +##:69 + +#line 1071 "/u/norman/pu/web/dist/src/master/spider.web" + +if(tokennumbers[t]!=""||tokentangleto[t]=="") +continue +if(t=="@"){ +thistangletokname="@@" +}else if(t=="\\"||t=="'"){ +thistangletokname="\\"t +}else{ +thistangletokname=t +} +printf"case '%s':\n",thistangletokname>ttokfile +this_tangleto=tokentangleto[t] +if(this_tangleto==""){ +print"This can't happen -- null tangleto for",t,wherestring +exitcode=-1 +}else{ +printf"\tif (out_state==verbatim) {\n">ttokfile +printf"\t\tC_printf(\"%%s\",\"%s\");\n",t>ttokfile +printf"\t} else {\n">ttokfile +##70: + +#line 1106 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1107 "/u/norman/pu/web/dist/src/master/spider.web" +oldwherestring=wherestring +wherestring="for tangleto "wherestring + +transstring=this_tangleto +##27: + +#line 389 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 390 "/u/norman/pu/web/dist/src/master/spider.web" +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 395 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +print"Digit not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^[a-zA-Z_]+$/){ +print"Key word not allowed in restricted translation",wherestring +exitcode=-1 +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=substr(alternate,2,length(alternate)-2) +outstring=outstring temp +}else if(alternate~/^\*$/){ +print"<*> not allowed in restricted translation",wherestring +exitcode=-1 +}else{ +print"Bogus restricted translation",wherestring +exitcode=-1 +} +} +outstring="\""outstring"\"" + + + +##:27 + +#line 1112 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"\tC_printf(\"%%s\",%s);\n",outstring>ttokfile + +wherestring=oldwherestring + + + +##:70 + +#line 1090 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"\t}\n">ttokfile +} +print"\tif (out_state!=verbatim) out_state=misc;">ttokfile +print"break;">ttokfile +} +##:68 +##71: + +#line 1123 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1124 "/u/norman/pu/web/dist/src/master/spider.web" +tempfile=scrapfile +##72: + +#line 1131 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1132 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Here are the definitions of the token names">tempfile +for(t in tokennumbers){ +temp=tokennumbers[t] +if(temp==0) +continue +if(tempfile==ttokfile){ +##69: + +#line 1099 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1100 "/u/norman/pu/web/dist/src/master/spider.web" +if(t=="string"||t=="constant"||t=="identifier") +continue + + + +##:69 + +#line 1139 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=temp+31+3-highesttoken + +} +printf"@d %s = %s\n",tokenname[t],temp>tempfile +} + + +##:72 + +#line 1125 "/u/norman/pu/web/dist/src/master/spider.web" + +tempfile=ttokfile +##72: + +#line 1131 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1132 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Here are the definitions of the token names">tempfile +for(t in tokennumbers){ +temp=tokennumbers[t] +if(temp==0) +continue +if(tempfile==ttokfile){ +##69: + +#line 1099 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1100 "/u/norman/pu/web/dist/src/master/spider.web" +if(t=="string"||t=="constant"||t=="identifier") +continue + + + +##:69 + +#line 1139 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=temp+31+3-highesttoken + +} +printf"@d %s = %s\n",tokenname[t],temp>tempfile +} + + +##:72 + +#line 1127 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:71 +##79: + +#line 1268 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1269 "/u/norman/pu/web/dist/src/master/spider.web" +print"Writing out reserved words and ilks">logfile +ilkno=64 +print"@ Here is a list of all the ilks">reserved +for(i in ilk_translation){ +printf"@d SP_%s = %d\n",i,ilkno>reserved +ilkno++ +} + +##:79 +##80: + +#line 1279 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1280 "/u/norman/pu/web/dist/src/master/spider.web" +print" ">reserved +print"@ Here are the scraps we get from the reserved words">reserved +print"@d the_word = res_flag+p-name_dir">reserved +print"@<Decide on reserved word scraps@>=">reserved +print"switch (p->ilk) {">reserved +for(t in ilk_translation){ +printf"\tcase SP_%s: \n\t\t",t>reserved +transstring=ilk_translation[t] +selfstring="small_app(the_word);" +wherestring=sprintf("in translation of ilk %s",t) +append_keyword="small_app" +##24: + +#line 336 "/u/norman/pu/web/dist/src/master/spider.web" + +temp=substr(transstring,2,length(transstring)-2) +trcnt=split(temp,trtok,"-") +outstring="" +for(tridx=1;tridx<=trcnt;tridx++){ +alternate=trtok[tridx] +##25: + +#line 366 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 367 "/u/norman/pu/web/dist/src/master/spider.web" +if(alternate=="space"){ +alternate="\" \"" +}else if(alternate=="dash"){ +alternate="\"-\"" +} + + +##:25 + +#line 342 "/u/norman/pu/web/dist/src/master/spider.web" + +if(alternate~/^[0-9]$/){ +temp=sprintf("\tapp_str(\"%s\");\n",alternate) +outstring=outstring temp +}else if(alternate~/^[a-zA-Z_]+$/){ +translation_keywords[alternate]=1 +temp=sprintf("\t%s(%s);\n",append_keyword,alternate) + +outstring=outstring temp +}else if(alternate~/^\"([^"]*\\\")*[^"]*\"$/){ +temp=sprintf("\tapp_str(%s);\n",alternate) +outstring=outstring temp +}else if(alternate~/^\*$/){ +##26: + +#line 377 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 378 "/u/norman/pu/web/dist/src/master/spider.web" +if(selfstring==""){ +print"Translation \"<*>\" makes no sense",wherestring +exitcode=-1 +} + +##:26 + +#line 355 "/u/norman/pu/web/dist/src/master/spider.web" + +outstring=outstring selfstring +}else{ +print"Bogus translation",wherestring +exitcode=-1 +} +} + +##:24 + +#line 1293 "/u/norman/pu/web/dist/src/master/spider.web" + +if(trcnt>0) +has_translation[t]=1 +print outstring>reserved +printf"\tapp_scrap(SP_%s,%s_math);\n",ilk_category[t],\ +ilk_mathness[t]>reserved +temp=ilk_category[t] +appended[temp]=1 + +printf"\t\tbreak;\n">reserved +} +print"}">reserved + + +##:80 +##81: + +#line 1309 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1310 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ @<Store all the reserved words@>=">reserved +for(i in reservedilk){ +printf"id_lookup(\"%s\",NULL,SP_%s);\n",i,reservedilk[i]>reserved +} + +##:81 +##118: + +#line 1876 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1877 "/u/norman/pu/web/dist/src/master/spider.web" +print"Writing out category codes">logfile +print"@ Here is a list of category codes scraps can have">grammarfile +i=1 +for(t in categories){ +printf"@d SP_%s = %d\n",t,i>grammarfile +i++ +} +print"@c">grammarfile +##:118 +##119: + +#line 1887 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1888 "/u/norman/pu/web/dist/src/master/spider.web" +print"#ifdef DEBUG">grammarfile +print"#define PRINT_CAT(A,B) case A: printf(B); break">grammarfile +print"print_cat(c) /* symbolic printout of a category */">grammarfile +print"eight_bits c;">grammarfile +print"{">grammarfile +print" switch(c) {">grammarfile +for(t in categories){ +printf"PRINT_CAT(SP_%s,\"%s\");\n",t,t>grammarfile +} +print" case 0: printf(\"zero\"); break;">grammarfile +print" default: printf(\"UNKNOWN\"); break;">grammarfile +print" }">grammarfile +print"}">grammarfile +print"#endif DEBUG">grammarfile +print" ">grammarfile + +##:119 +##123: + +#line 1947 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1948 "/u/norman/pu/web/dist/src/master/spider.web" +print"Writing out grammar">logfile +print"@ Here is where we define |highestposoverall| and where we">grammarfile +print"check the productions.">grammarfile +print"@d highestposoverall =",highestposoverall>grammarfile +print"@<Test for all of the productions@>=">grammarfile +for(n=1;n<=prodnum;n++){ +if(n%5==0) +print"@ @<Test for all of the productions@>="\ +>grammarfile +##126: + +#line 2011 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2012 "/u/norman/pu/web/dist/src/master/spider.web" +this_string=inputline[n] +tempi=index(this_string,"|") +while(tempi!=0){ +tempa=substr(this_string,1,tempi-1) +tempb=substr(this_string,tempi+1) +this_string=tempa"\\vert "tempb +tempi=index(this_string,"|") +} +templ="";tempr=this_string +tempi=index(tempr,"_") +while(tempi!=0){ +tempa=substr(tempr,1,tempi-1) +tempr=substr(tempr,tempi+1) +templ=templ tempa"\\_" +tempi=index(tempr,"_") +} +this_string=templ tempr +templ="";tempr=this_string +tempi=index(tempr,"#") +while(tempi!=0){ +tempa=substr(tempr,1,tempi-1) +tempr=substr(tempr,tempi+1) +templ=templ tempa"\\#" +tempi=index(tempr,"#") +} +this_string=templ tempr + + +##:126 + +#line 1957 "/u/norman/pu/web/dist/src/master/spider.web" + +##127: + +#line 2041 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2042 "/u/norman/pu/web/dist/src/master/spider.web" +toolong=this_string;this_string="" +while(length(toolong)>60){ +idx=59 +idchar=substr(toolong,idx,1) +while(idx>1&&idchar!=" "){ +idx-- +idchar=substr(toolong,idx,1) +} +if(idx==1) +idx=59 +temp=substr(toolong,1,idx-1) +toolong=substr(toolong,idx+1) +this_string=this_string temp"\n" +} +this_string=this_string toolong + + + +##:127 + +#line 1958 "/u/norman/pu/web/dist/src/master/spider.web" + +printf"if (%s) {\n\t/* %d: {\\tt %s} */\n%s",\ +prodtest[n],n,this_string,prodtrans[n]>grammarfile +##124: + +#line 1970 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1971 "/u/norman/pu/web/dist/src/master/spider.web" +ttk=targetcategory[n] +if(ttk=="Unnamed category"){ + +printf"\treduce(pp+%d,%d,%s,%d,%d);\n",ppstart[n],\ +tokensreduced[n],unnamed_cat[n],\ +1-highestposoverall,n>grammarfile +}else{ +appended[ttk]=1 + +reduction=highestpos[ttk] +if(reduction<highestunknownpos){ +reduction=highestunknownpos +} +printf"\treduce(pp+%d,%d,SP_%s,%d,%d);\n",ppstart[n],\ +tokensreduced[n],targetcategory[n],\ +1-reduction,n>grammarfile +} + +##:124 + +#line 1962 "/u/norman/pu/web/dist/src/master/spider.web" + +print"\tgoto end_prods;">grammarfile +printf"} ">grammarfile +} +printf"\n">grammarfile +print"end_prods:">grammarfile + +##:123 +##130: + +#line 2095 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2096 "/u/norman/pu/web/dist/src/master/spider.web" +if(language!=""){ +print"@ Here is the language-dependent stuff">tlang +if(version!="") +version=", Version "version +printf"@d banner = \"This is %s TANGLE%s %s\\n\"\n",language,\ +version,date>tlang +printf"@<Global...@>=char C_file_extension[]=\"%s\";\n",extension \ +>tlang + +print"@ Here is the language-dependent stuff">wlang +if(version!="") +version=", Version "version +printf"@d banner = \"This is %s WEAVE%s %s\\n\"\n",language,\ +version,date>wlang +print"@<Set |out_ptr| and do a |tex_printf| to read the macros@>="\ +>wlang +printf"*out_ptr='x'; tex_printf(\"\\\\input %sweb.te\");\n",\ +extension>wlang +printf"@ @<Global...@>=char C_file_extension[]=\"%s\";\n",extension \ +>wlang +}else{ +print"Error: you haven't given me any \"language\" information" +exitcode=-1 +} + +##:130 +##134: + +#line 2189 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2190 "/u/norman/pu/web/dist/src/master/spider.web" +if(mod_def_cat!=""){ +print"@ @<Call |app_scrap| for a module definition@>=">scrapfile +printf"app_scrap(SP_%s,no_math);\n",mod_def_cat>scrapfile +appended[mod_def_cat]=1 +}else{ +print"Error: I don't know what to do with a module definition" +print" Give me a \"module definition ...\"" +exitcode=-1 +} +if(mod_use_cat!=""){ +print"@ @<Call |app_scrap| for a module use@>=">scrapfile +printf"app_scrap(SP_%s,maybe_math);\n",mod_use_cat>scrapfile +appended[mod_use_cat]=1 +}else{ +print"Error: I don't know what to do with a module use" +print" Give me a \"module use ...\"" +exitcode=-1 +} + + +##:134 +##136: + +#line 2230 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2231 "/u/norman/pu/web/dist/src/master/spider.web" +tempfile=grammarfile +##137: + +#line 2237 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2238 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Here is the |at_sign| for the new web">tempfile +printf"@d at_sign = @`%s'\n",at_sign>tempfile +print" ">tempfile +print"@ Here is |the_at_sign| left for common">tempfile +print"@<Global...@>=char the_at_sign = at_sign;">tempfile +print" ">tempfile + +##:137 + +#line 2232 "/u/norman/pu/web/dist/src/master/spider.web" + +tempfile=ttokfile +##137: + +#line 2237 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2238 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Here is the |at_sign| for the new web">tempfile +printf"@d at_sign = @`%s'\n",at_sign>tempfile +print" ">tempfile +print"@ Here is |the_at_sign| left for common">tempfile +print"@<Global...@>=char the_at_sign = at_sign;">tempfile +print" ">tempfile + +##:137 + +#line 2234 "/u/norman/pu/web/dist/src/master/spider.web" + + +##:136 +##140: + +#line 2304 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2305 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Here we recognize the comment start seqence">ttokfile +print"@<See a comment starting at |loc| and skip it@>=">ttokfile +printf"{int len; len=strlen(%s);\n",begin_comment_string>ttokfile +printf"if (loc+len<=limit && !strncmp(loc,%s,len)) {\n",\ +begin_comment_string>ttokfile +print"\tloc += len; /* a new thing */">ttokfile +print"\tskip_comment(); /* scan to end of comment or newline */">ttokfile +print"\tif (comment_continues || comments_end_with_newline)">ttokfile +print"\t\treturn('\\n');">ttokfile +print"\telse continue;\n}\n}">ttokfile + + +##:140 +##141: + +#line 2318 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2319 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ @<See a comment starting at |loc-1| and return |begin_comment|@>="\ +>scrapfile +printf"{int len; len=strlen(%s);\n",begin_comment_string>scrapfile +printf"if (loc+len-1<=limit && !strncmp(loc-1,%s,len)) {\n",\ +begin_comment_string>scrapfile +print"\tloc += len-1;">scrapfile +print"\t return (begin_comment); /* scan to end of comment or newline */">scrapfile +print"}\n}">scrapfile + + + + +##:141 +##142: + +#line 2332 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2333 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Here we deal with recognizing the end of comments">ttokfile +printf"@d comments_end_with_newline = %d\n",comments_end_with_newline>ttokfile +print"@<Recognize comment end starting at |loc-1|@>=">ttokfile +if(comments_end_with_newline!=1){ +printf"{int len; len=strlen(%s);\n",end_comment_string>ttokfile +printf"if (loc+len-1<=limit && !strncmp(loc-1,%s,len)) {\n",\ +end_comment_string>ttokfile +print"loc += len-1; return(comment_continues=0); }}">ttokfile +}else{ +print"/* This code will never be executed */ ">ttokfile +} + +##:142 +##143: + +#line 2348 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2349 "/u/norman/pu/web/dist/src/master/spider.web" +printf"@ Here we recognize end of comments">scrapfile +printf"@d comments_end_with_newline = %d\n",comments_end_with_newline>scrapfile +print"@<Check for end of comment@>=">scrapfile +printf"{int len; len=strlen(%s);\n",end_comment_string>scrapfile +printf"if (loc+len-1<=limit && !strncmp(loc-1,%s,len)) {\n",\ +end_comment_string>scrapfile +print" loc++; if(bal==1) {if (phase==2) app_tok('}'); return(0);}">scrapfile +print" else {">scrapfile +print" err_print(\"! Braces don't balance in comment\");">scrapfile +print"@.Braces don't balance in comment@>">scrapfile +print" @<Clear |bal| and |return|@>;">scrapfile +print" }">scrapfile +print"}">scrapfile +print"}">scrapfile + + +##:143 +##144: + +#line 2367 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2368 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Important tokens:">ttokfile +printf"@d begin_comment_string = %s\n",begin_comment_string>ttokfile +printf"@d end_comment_string = %s\n",end_comment_string>ttokfile + +##:144 +##149: + +#line 2469 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2470 "/u/norman/pu/web/dist/src/master/spider.web" +print"@ Important tokens:">ttokfile +printf"@d sharp_line_open = %s\n",sharp_line_open>ttokfile +printf"@d sharp_line_close = %s\n",sharp_line_close>ttokfile + +##:149 + +#line 65 "/u/norman/pu/web/dist/src/master/spider.web" + +print"Writing out lists">logfile +##21: + +#line 304 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 305 "/u/norman/pu/web/dist/src/master/spider.web" +for(t in translation_keywords){ +print t>translationfile +} + +##:21 +##73: + +#line 1149 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1150 "/u/norman/pu/web/dist/src/master/spider.web" +for(t in tokenname){ +temp=tokenname[t] +if(substr(temp,1,1)!="'"){ +##74: + +#line 1158 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1159 "/u/norman/pu/web/dist/src/master/spider.web" +tempa=substr(temp,1,3) +if(tempa=="SP_"){ +temp=substr(temp,4) +} + + +##:74 + +#line 1153 "/u/norman/pu/web/dist/src/master/spider.web" + +print temp>tokennamefile +} +} + +##:73 +##83: + +#line 1330 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1331 "/u/norman/pu/web/dist/src/master/spider.web" +for(i in ilk_translation){ +print i>ilkfile +} + +##:83 +##113: + +#line 1817 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1818 "/u/norman/pu/web/dist/src/master/spider.web" +if(wrotecycles==0){ +print"0: dummy --> nodummy">cycles +} + +##:113 +##120: + +#line 1905 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1906 "/u/norman/pu/web/dist/src/master/spider.web" +for(c in categories){ +print c>categoryfile +} + +##:120 +##122: + +#line 1929 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1930 "/u/norman/pu/web/dist/src/master/spider.web" +for(n=1;n<=prodnum;n++){ +printf"%2d: %s\n",n,inputline[n]>productions +} + +##:122 + +#line 67 "/u/norman/pu/web/dist/src/master/spider.web" + +##22: + +#line 309 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 310 "/u/norman/pu/web/dist/src/master/spider.web" +for(t in translation_keywords){ +num_of_translation_keywords++ +} +printf"You used %d translation keywords.\n",\ +num_of_translation_keywords>logfile +printf"You used %d translation keywords.\n",num_of_translation_keywords + +##:22 +##84: + +#line 1335 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1336 "/u/norman/pu/web/dist/src/master/spider.web" +for(i in ilk_translation)number_of_ilks++ +for(i in reservedilk)number_of_reserved_words++ +printf"You defined %d reserved words of %d ilks.\n",\ +number_of_reserved_words,number_of_ilks +printf"You defined %d reserved words of %d ilks.\n",\ +number_of_reserved_words,number_of_ilks>logfile + +##:84 +##121: + +#line 1910 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1911 "/u/norman/pu/web/dist/src/master/spider.web" +for(c in categories){ +number_of_categories++ +} +printf"You used %d different categories in %d productions.\n",\ +number_of_categories,prodnum +printf"You used %d different categories in %d productions.\n",\ +number_of_categories,prodnum>logfile +printf"The biggest production had %d scraps on its left-hand side.\n",\ +highestposoverall +printf"The biggest production had %d scraps on its left-hand side.\n",\ +highestposoverall>logfile + + +##:121 + +#line 68 "/u/norman/pu/web/dist/src/master/spider.web" + +##47: + +#line 734 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 735 "/u/norman/pu/web/dist/src/master/spider.web" +if(tokennumber<127){ +print"Error: too many token names for WEAVE --- over by",\ +127-tokennumber +exitcode=-1 +} +##:47 +##48: + +#line 743 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 744 "/u/norman/pu/web/dist/src/master/spider.web" +if(highesttoken-tokennumber>31-(11-1)+3){\ + +print"Error: too many token names for TANGLE --- over by",\ +highesttoken-tokennumber-(31-(11-1)+3) +exitcode=-1 +} + + + +##:48 +##82: + +#line 1318 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1319 "/u/norman/pu/web/dist/src/master/spider.web" +for(i in ilk_translation){ +if(has_reserved[i]!=1){ +print"Error: there is no reserved word of ilk",i +exitcode=-1 +} +if(has_translation[i]!=1){ +print"Error: ilk",i,"has no translation" +exitcode=-1 +} +} + +##:82 +##116: + +#line 1858 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1859 "/u/norman/pu/web/dist/src/master/spider.web" +for(c in categories){ +if(reduced[c]!=1){ +print"Warning: category",c,"never reduced" +} +} + + +##:116 +##125: + +#line 1992 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 1993 "/u/norman/pu/web/dist/src/master/spider.web" +for(c in categories){ +if(appended[c]!=1){ +if(c=="ignore_scrap"){ +print"Warning: category",c,"never appended" +}else{ +print"Error: category",c,"never appended" +exitcode=-1 +} +} +} + + + +##:125 + +#line 69 "/u/norman/pu/web/dist/src/master/spider.web" + +if(exitcode!=0){ +exit exitcode +} +} + +##:3 + diff --git a/web/spiderweb/src/master/spider.web b/web/spiderweb/src/master/spider.web new file mode 100644 index 0000000000..0aca8a4232 --- /dev/null +++ b/web/spiderweb/src/master/spider.web @@ -0,0 +1,2580 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +\message{OK, entering \string\batchmode...} +\batchmode + +\let\RA\rightarrow + +\def\vert{{\tt\char'174}} +\def\pb{$\.|\ldots\.|$} % C brackets (|...|) + +\def\title{SPIDER} + +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont SPIDER} processor} + \vfill} + + +\def\syntax##1{\leavevmode\hbox{$\langle\hbox{\sl ##1\/}\rangle$}} +\def\produces{\leavevmode\hbox{${}::={}$}} +\def\opt##1{$[$##1$]$} + +#*={\tt SPIDER} proper. +#*Introduction. +This is an AWK program designed to read a description of a programming +language and to write out the language-dependent parts of WEB. +In the main, +the description of a programming language is + a list of all the tokens of the language +(together with various facts about them) and a grammar for prettyprinting +code fragments written in that language. +The ``Spider User's Guide'' describes how to use {\tt SPIDER} to construct +a {\tt WEB} system for the ALGOL-like language of your choice. +({\tt SPIDER} may be able to handle LISP and Miranda and other strange +languages; the experiment hasn't been tried. +The unusual lexical requirements of FORTRAN are probably beyond it, at +least until the lexical analysis is modernized.) + +# The outline of the program is fairly straightforward. +We use |exitcode| throughout to monitor error status. +If we were more Knuthlike, we would have a |history| variable with values of +|spotless|, and so on. +This will have to wait until we get macros back into \.{TANGLE}. + +We put the pattern-action statement for productions last, because in +case of a conflict like \.{token~-->~...}, we want the interpretation +as {\tt token} to win out over +the interpretation as a prodution. + +#u#1 +BEGIN { +#<Set initial values#> +exitcode=0 +} +#@ +#<Ignore comments and blank lines#> +#<Pattern-action statements#> +#<Production pattern-action statement#> +#<Default action for patterns we don't recognize#> +#@ +END { +#<Write out all of the WEB code#> +print "Writing out lists" > logfile +#<Write lists of everything#> +#<Write statistics for this \.{SPIDER}#> +#<Check for errors at the very end#> +if (exitcode != 0) { + exit exitcode + } +} + +# There are a couple of actions we may want to perform with just +about any command. +If a command fails, we move on to the next, but we remember the fault +so we can complain at the end. +#<Punt this command#>= + exitcode=-1 + next + + +# Throughout \.{SPIDER} we always use the variable |i| to step through the +fields of a command, so that |$i| is always the next field of interest. +When we thinik we have finished a command, +we will always want to check to make sure there are no unexamined +fields left over. +For error messages, the line number is really |NR-1|, since we put an +extra line at the beginning with the date. +#<Check that we used everything#>= + if (i<=NF) { + print "Error: leftover fields", $i, "... on line", NR-1 + #<Punt...#> + } + + +# To \.{SPIDER}, any line beginning with |"## "| is a comment. +\.{SPIDER} also ignores blank lines. +#<Ignore comments...#>= +#=/^##|^ *$/#> { + ## comments, blank lines + print $0 > logfile + next + } + +# But, if \.{SPIDER} encounters a line we don't recognize, it complains. +#<Default act...#>= + { + print "Warning: I don't know what to do with this line:" + print " ", $0 + print "Warning: I don't know what to do with this line:" > logfile + print " ", $0 > logfile +} + + +#*1Files written by {\tt SPIDER}. + {\tt SPIDER} writes output to a number of files. +Because 4.3~BSD AWK is limited in the number of files it can write at +one time, there is substantial overlap. +Here is a table: +\noindent\halign{\vrule height10pt depth3.5pt width0pt +\it##\hfil\tabskip=1em&\tt##\hfil&\tabskip=0pt + \hsize=4in\vtop{\noindent##\strut\par}\cr +\noalign{\medskip} +\bf Internal Name&\bf External Name&\omit\bf Description\hfil\cr +\noalign{\smallskip} +categoryfile&names.unsorted& +names of categories, to be checked for duplicates by {\tt nodups.awk} +\cr +cycles&cycle.test& +potential cycles, to be checked by {\tt cycle.web} +\cr +grammarfile&grammar.web& +grammar; included in {\tt weave.web} +\cr +ilkfile&names.unsorted& +names of ilks, to be checked for duplicates by {\tt nodups.awk} +\cr +logfile&spider.slog& +log file, to be consulted when things go wrong +\cr +macrofile&*web.tex& +language specific macro file, {\tt\string\input} by all \TeX{} + files created by {\tt weave.web} +\cr +productions&productions.list& +list of the productions (numbered) used in debugging \.{WEAVE} +\cr +reserved&scraps.web& +code for converting the reserved word to scraps. +{\tt scraps.web} is included by {\tt weave.web} +\cr +scrapfile&scraps.web& +code for converting tokens to scraps. +{\tt scraps.web} is included by {\tt weave.web} +\cr +tlang&outtoks.web& +Information about what language we're webbing. +{\tt outtoks.web} is included by {\tt tangle.web}. +\cr +tokennamefile&names.unsorted& +list of names of all the tokens, to be checked by {\tt nodups.awk} +\cr +translationfile&trans\_keys.unsorted& +list of names of all the translation keywords. +Checked for duplicates by {\tt nodups.awk}, and also for recognizability +by {\tt transcheck.awk}. +\cr +ttokfile&outtoks.web& +This is the tokenization code for {\tt TANGLE}. +\cr +wlang&scraps.web& +Information about what language we're webbing, +{\tt scraps.web} is included by {\tt weave.web}. +\cr +} + +# Every action writes information to a log file. +This log file can be used to check up on what happened. +#<Set initial...#>= + logfile = "spider.slog" + +# Here we write the names of the key words used in translations. +#<Set initi...#>= + translationfile = "trans_keys.unsorted" + +# We write tokens out to two files: |scrapfile| for \.{WEAVE}, and +|ttokfile| for \.{TANGLE}. +#<Set init...#>= + scrapfile = "scraps.web" + print "@*Scrap code generated by {\\tt SPIDER}." > scrapfile + ttokfile = "outtoks.web" + print "@*Token code generated by {\\tt SPIDER}." > ttokfile +# The reserved word stuff gets a file of its own, or it would in an ideal +world. +#<Set init...#>= + reserved = "scraps.web" ## use same file; not enough files + +# We'll also end up writing a list of token names, for name checking +purposes. +#<Set initial...#>= + tokennamefile = "names.unsorted" ## cut down on number of output files +# We also write out every ilk, so we'll be able to look for name +clashes with translations and so on. +#<Set init...#>= + ilkfile = "names.unsorted" ## cut down on number of output files +# We also write all the category names to a separate file, so we can +check for duplicates later. +#<Set init...#>= + categoryfile = "names.unsorted" ## cut down on number of output files +# We use a special file to write grammar information: +#<Set init...#>= + grammarfile = "grammar.web" + print "@*Grammar code generated by {\\tt SPIDER}." > grammarfile +# We use the language information to write banners and macro information. +We combine this with other stuff because AWK can't handle more than +10 output files. +#<Set initial...#>= + tlang = "outtoks.web" ## same as ttokfile + wlang = "scraps.web" ## same as scrapfile + +# We will write a list of the successfully parsed productions to a +separate file. +#<Set init...#>= + productions = "productions.list" + +# These productions will get fed to {\tt cycle.awk}, which looks for cycles. +#<Set initial...#>= + cycles = "cycle.test" + + + +#*Processing translations. +Translations tell \.{WEAVE} or \.{TANGLE} what to write out in +particular circumstances (e.g.~after scanning a particular token, or +when firing some production). +They are described at some length in the ``\.{SPIDER} User's Guide.'' +Translations are enclosed in angle brackets and separated by dashes. +They can contain key words, digits, the self marker~`{\tt*}', +or quoted strings. +Since we can't put a space or dash into strings, we allow the use of +key words |space| and |dash| to stand for those symbols. +#^space#> +#^dash#> + +Other key words are interpreted by \.{WEAVE} as prettyprinting instructions: + +\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 |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| or |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\hang |math_rel|, |math_bin|, and |math_op| will be translated into +\.{\\mathrel\{}, \.{\\mathbin\{}, and \.{\\mathop\{}, respectively. + + +\yskip\noindent All of these tokens are removed from the \TeX\ output that +comes from programming language text between \pb\ signs; |break_space| +and |force| and +|big_force| become single spaces in this mode. +%The translation of other +%program texts results in \TeX\ +%control sequences \.{\\1}, \.{\\2}, +%\.{\\3}, \.{\\4}, \.{\\5}, \.{\\6}, +%\.{\\7} corresponding respectively to +%|indent|, |outdent|, |opt|, +%|backup|, |break_space|, |force|, and +%|big_force|. 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). + +%Some 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 module names, where +%|n| is the module number. + +# We write out the names of all the key words used translations, +so we can check that +\.{WEAVE} can be expected to recognize them. +This helps us catch the problem early if a translation given is +not one of the above +(as opposed to, say, having the C~compiler fail to compile \.{WEAVE}). +#<Write lists...#>= + for (t in translation_keywords) { + print t > translationfile + } + +# #<Write stat...#>= +for (t in translation_keywords) { + num_of_translation_keywords++ + } +printf "You used %d translation keywords.\n", \ + num_of_translation_keywords > logfile +printf "You used %d translation keywords.\n", num_of_translation_keywords + +# If the macro facility worked right, +we would use the following patterns to recognize items as they occur: +#d cat_pattern = #=/[a-zA-Z][a-zA-Z_]*/#> +#d trans_pattern = #=/<(([0-9]|[a-zA-Z][a-zA-Z_]*|"([^"]*\\")*[^"]*"|\*)-)*#>#& + #=([0-9]|[a-zA-Z][a-zA-Z_]*|"([^"]*\\")*[^"]*"|\*)>/#> + +# Here's where we swallow a translation and spit out the \.{WEAVE} code +to handle that translation. +Since AWK has no functions, we define this as a module. + +When we're appending a key word {\it in the process of creating a +scrap from a token}, we use |small_app| in preference to |app|, +because |app|'s cleverness about mathness and dollar signs only works when +reducing existing scraps, not when creating scraps from tokens. +We'll expect the variable |append_keyword| to be set to either +|"small_app"| or |"app"|. + + +#<Take translation from |transstring| and write corresponding \.{WEAVE} code to +|outstring|, using |selfstring| as translation of |"<*>"|#>= +temp = substr(transstring,2,length(transstring)-2) ## kills awk bug +trcnt = split(temp,trtok,"-") +outstring = "" +for (tridx=1;tridx<=trcnt;tridx++) { + alternate=trtok[tridx] + #<Convert |"space"| and |"dash"|#> + if (alternate ~ #=/^[0-9]$/#>) { ## digit + temp = sprintf("\tapp_str(\"%s\");\n",alternate) + outstring=outstring temp + } else if (alternate ~ #=/^[a-zA-Z_]+$/#>) { ## key word + translation_keywords[alternate]=1 ## remember + temp = sprintf("\t%s(%s);\n",append_keyword,alternate) +##Call |app| or |small_app| depending whether we're reducing or creating scraps + outstring=outstring temp + } else if (alternate ~ #=/^\"([^"]*\\\")*[^"]*\"$/#>) { ## string + temp = sprintf("\tapp_str(%s);\n",alternate) + outstring=outstring temp + } else if (alternate ~ #=/^\*$/#>) { ## self marker + #<If |selfstring==""|, complain loudly#> + outstring=outstring selfstring + } else { + print "Bogus translation", wherestring + exitcode = -1 + } +} + +# Here we convert the key words |space| and |dash| to strings. +We quote the strings, to be sure that they are handled by the string +mechanism. +#<Convert |"space"|...#>= + if (alternate=="space") { + alternate="\" \"" + } else if (alternate=="dash") { + alternate="\"-\"" + } + + +# There are some places (notably in productions) where the translation +|"<*>"| makes no sense. +In this case the caller sets |selfstring=""|, and we complain. +#<If |selfstring==""|, complain...#>= +if (selfstring=="") { + print "Translation \"<*>\" makes no sense", wherestring + exitcode = -1 + } + +# There are times when we may want to convert a translation directly +into a quoted string, usually for \.{TANGLE}'s benefit. +Here, the only things allowed are quoted strings and |space| and |dash|. +We peel off quote marks and concatenate things together, and then we +put the quote marks back on at the end. +#<Convert restricted translation in |transstring| + to quoted string in |outstring|#>= +temp = substr(transstring,2,length(transstring)-2) ## kills awk bug +trcnt = split(temp,trtok,"-") +outstring = "" +for (tridx=1;tridx<=trcnt;tridx++) { + alternate=trtok[tridx] + #<Convert |"space"| and |"dash"|#> + if (alternate ~ #=/^[0-9]$/#>) { ## digit + print "Digit not allowed in restricted translation", wherestring + exitcode = -1 + } else if (alternate ~ #=/^[a-zA-Z_]+$/#>) { ## key word + print "Key word not allowed in restricted translation", wherestring + exitcode = -1 + } else if (alternate ~ #=/^\"([^"]*\\\")*[^"]*\"$/#>) { ## string + temp = substr(alternate,2,length(alternate)-2) ## strip quotes + outstring=outstring temp + } else if (alternate ~ #=/^\*$/#>) { ## self marker + print "<*> not allowed in restricted translation", wherestring + exitcode = -1 + } else { + print "Bogus restricted translation", wherestring + exitcode = -1 + } +} +outstring = "\"" outstring "\"" ## put quotes back on |outstring| + + + +#*Tokens. + +Tokens are pretty complicated. +Each token has a string by which we recognize it in the input. +This string is what immediately follows the |token| command. +Then, there's another string that tells \.{TANGLE} how to write out +the token. +Finally, it has a category and a translation (so we can make a scrap out +of it), and a mathness (to tell us whether it has to be in math +mode, horizontal mode, or either). +The +\.{translation} and \.{mathness} have defaults. + +#*2Scanning for token descriptions. +This module is used everywhere we must scan a line for token descriptions. +#<Scan this line from |start_place| to finish, looking for + \.{translation}$\ldots$ and putting results in + |this_translation|$\ldots$#>= +for (i=start_place;i<NF;) { + if ($i=="tangleto") { ## for \.{TANGLE} + i++ + this_tangleto=$i + i++ + } else if ($i=="translation") { ## for \.{WEAVE} + i++ + this_translation=$i + i++ + } else if ($i=="mathness") { ## for \.{WEAVE} + i++ + this_mathness=$i + i++ + } else if ($i=="category") { ## for \.{WEAVE} + i++ + this_category=$i + categories[$i]=1 + i++ + } else if ($i=="name") { ## for debugging + i++ + this_name="SP_" $i ##OK, so it's hacking... + i++ + } else { + print "Error: unrecognized token description", $i, "on line", NR-1 + #<Punt...#> + } +} +#<Check that we used everything#> + +# We check for the presence or absence of certain empty strings after +scanning. +#<Make sure |this_name| is empty#>= +if (this_name != "") { + print "Error: name doesn't apply on line", NR-1 + #<Punt...#> + } +# #<Make sure |this_tangleto| is empty#>= +if (this_tangleto != "") { + print "Error: tangleto doesn't apply on line", NR-1 + #<Punt...#> + } +# #<Make sure |this_category| is empty#>= +if (this_category != "") { + print "Error: category doesn't apply on line", NR-1 + #<Punt...#> + } +# #<Make sure |this_translation| is empty#>= +if (this_translation != "") { + print "Error: translation doesn't apply on line", NR-1 + #<Punt...#> + } +# #<Make sure |this_category| is not empty#>= +if (this_category == "") { + print "Error: you must give a category on line", NR-1 + #<Punt...#> + } + +#*1Setting the default token descriptions. +\.{SPIDER} maintains default information about {\em mathness} +and {\em translation}, so these can be omitted from token descriptions. +We can change the operative defaults at any time by using a +|"default"| command. +It too, scans for keywords, using the standard scanning module +#<Pattern-action...#>= +#=/^default /#> { + print "Setting defaults..." > logfile + start_place=2 + #<Set |this_mathness| etcetera to the defaults and those with no + defaults to |""|#> + #<Scan this line from |start_place| to finish, looking for + \.{translation}$\ldots$ and putting results in + |this_translation|$\ldots$#> + #<Make sure |this_name| is empty#> + #<Make sure |this_category| is empty#> + default_translation=this_translation + default_mathness=this_mathness +#@ print "\tdefault translation is", default_translation > logfile + print "\tdefault mathness is", default_mathness > logfile +#@ next +} + +# Normally, we will set all quantities to the defaults before scanning: +#<Set |this_mathness| etcetera to the defaults and those with no +defaults to |""|#>= + this_translation=default_translation + this_mathness=default_mathness + this_name="" + this_category="" + this_tangleto="" +# When \.{SPIDER} starts up, the defaults are already set: +#<Set initi...#>= + default_translation="<*>" + default_mathness="maybe" + + +#*1Recognizing token designators. +Let's begin by discussing the way \.{WEAVE} and \.{TANGLE} represent +tokens internally. + +\.{WEAVE} and \.{TANGLE} process tokens in a two-step process. +Both read the token from the input using |get_next|, which returns a +unique eight-bit number representing the token. +Generally printable ASCII characters represent themselves, and other +tokens get numbers in the unprintable range. +\.{TANGLE} assigns ranges to some tokens ahead of time: |string| is 2, +|identifier| is #'202, and so on. +Tokens that we introduce to \.{TANGLE} must have numbers between +#'13 and #'37 inclusive. + +Rather than work with eight-bit numbers themselves, we use names for +the tokens. +This makes \.{WEAVE} and \.{TANGLE} easier to debug when things go wrong. + +In \.{WEAVE}, the category, mathness, and translation are all +attached to a scrap based on the eight-bit number returned by +|get_next|, and this is done at a later time. + +In \.{TANGLE}, characters are written to the output file(s) based on +the token code, which can be either eight bits for simple tokens or +sixteen for identifiers and things. + +Our mission in this section will be to read in all the token +information from the {\tt token} command, +and to create the names and numbers used by \.{WEAVE} and \.{TANGLE} +to represent the tokens. +In the next section we will +write the code that processes the tokens for both \.{WEAVE} and +\.{TANGLE} (lexical analysis in +|get_next|, and subsequent processing elsewhere). +You will pardon us if things get a bit tedious. + +# The {\tt token} command is used to specify tokens that are not +reserved words. +Reserved word tokens get special treatment all their own. + +#<Pattern...#>= +#=/^token /#> { + print "Token", $2 > logfile + if ($2=="identifier") { + #<Process identifier token description#> + } else if ($2=="number") { + #<Process numeric token description#> + } else if ($2=="newline") { + #<Process newline token description#> + } else if ($2=="pseudo_semi") { + #<Process |pseudo_semi| token description#> + } else if ($2 ~ #=/[a-zA-ZA-Z0-9]+/#>) { + ## we recognize no other names + print "Error: unknown token species:", $2 + #<Punt this command#> + } else { + #<Process a non-alphanumeric token description#> + } + categories[this_category]=1 ## is this right? +#^questions#> + next +} + +# Identifiers, numbers (and string literals), newlines, and the special +token \.{pseduo\_semi} are predefined. +#<Process identifier token description#>= + #<Set |this_mathness| etcetera to the defaults and those with no + defaults to |""| #> + this_translation="" + start_place=3 + #<Scan this line from |start_place| to finish, looking for + \.{translation}$\ldots$ and putting results in + |this_translation|$\ldots$#> + #<Make sure |this_name| is empty#> + #<Make sure |this_tangleto| is empty#> + #<Make sure |this_category| is not empty#> + #<Make sure |this_translation| is empty#> + id_category=this_category + id_mathness=this_mathness + +# We have yet to implement a separate procedure for numerics and strings! +#<Process numeric token description#>= + print "Warning: numeric constants and strings are",\ + "identified in this WEAVE." + print "Warning: numeric constants and strings are",\ + "identified in this WEAVE." > logfile + #<Set |this_mathness| etcetera to the defaults and those with no + defaults to |""| #> + this_translation="" + start_place=3 + #<Scan this line from |start_place| to finish, looking for + \.{translation}$\ldots$ and putting results in + |this_translation|$\ldots$#> + #<Make sure |this_name| is empty#> + #<Make sure |this_tangleto| is empty#> + #<Make sure |this_category| is not empty#> + #<Make sure |this_translation| is empty#> + number_category=this_category + number_mathness=this_mathness + +# +#<Process newline token description#>= + #<Set |this_mathness| etcetera to the defaults and those with no + defaults to |""| #> + start_place=3 + #<Scan this line from |start_place| to finish, looking for + \.{translation}$\ldots$ and putting results in + |this_translation|$\ldots$#> + #<Make sure |this_name| is empty#> + #<Make sure |this_tangleto| is empty#> + #<Make sure |this_category| is not empty#> + newline_category=this_category + newline_mathness=this_mathness + newline_translation=this_translation + +# +#<Process |pseudo_semi| token description#>= + #<Set |this_mathness| etcetera to the defaults and those with no + defaults to |""| #> + start_place=3 + #<Scan this line from |start_place| to finish, looking for + \.{translation}$\ldots$ and putting results in + |this_translation|$\ldots$#> + #<Make sure |this_name| is empty#> + #<Make sure |this_tangleto| is empty#> + #<Make sure |this_category| is not empty#> + pseudo_semi_category=this_category + pseudo_semi_mathness=this_mathness + pseudo_semi_translation=this_translation + +# Here is where things get a bit more interesting; we have to +consider all the other (non-reserved-word) tokens, and find a way to +convert them to \.{WEAVE} and \.{TANGLE}'s internal form. +We take single characters straight, except for those that must be +escaped one way or another. +For multicharacter tokens, we have to invent a name and a number, +which process we will describe below. + + +Tokens have a zillion attributes: not just category, translation, and +their friends, but things like internal representations, the length of +the input string, you name it. + +We remember the length of the longest token in the system, +because when we go to +recognize tokens we will look for the longest first and then on down. +We maintain that length at the very end here. +#<Process a non-alphanumeric token description#>= + this_string=$2 + #<Translate |"{space}"| to |" "| in |this_string|#> +## print NF, "fields on line", NR-1 ## caught a bug in DEC awk + $2 = this_string +## print NF, "fields on line", NR-1 + #<Set |tokenname[$2]|, |tokenlength[$2]|, and, for long + tokens, set |tokentest[$2]| and |tokennumbers[$2]|#> + if (tokens[$2]!="") { + print "Warning: token", $2, "defined twice" + } + tokens[$2]=1 ## remember this token + #<Set attributes of token |$2|#> + #<Make sure token |$2| has a number if it needs one#> + #<Update record of maximum token length#> + + +# This code represents and undocumented feature. +We should replace it by allowing restricted translations +in |$2|, the then documenting it. +When doing this, we'll have to match the full |trans_pattern| +in all its glory; A mere |#=/<.*>/#>| won't do. + +#<Translate |"{space}"| to |" "| in |this_string|#>= +old_string = this_string +this_string = "" +## Invariant: |this_string old_string| corresponds to result, and +## |"{space}"| is translated in |this_string| but not |old_string| +idx = index(old_string,"{space}") +while (idx != 0) { + temp =substr(old_string,1,idx-1) + this_string = this_string temp " " + old_string = substr(old_string,idx+7) + idx = index(old_string,"{space}") +} +this_string = this_string old_string + +# Tokens need an internal eight-bit representation. +For single characters (which are assumed to be printable), we use +the ASCII code as the internal representation. +Multicharacter tokens will be assigned a name and a number. +(The names may be specified by the user or generated by \.{SPIDER}.) +Unfortunately the numbers for \.{WEAVE} and \.{TANGLE} have to be +different (the reasons will only depress you). +We assign \.{WEAVE} numbers by starting numbering from |highesttoken|, and +working our way down. +At the moment |hisghesttoken==200|, and I can't remember whether 200 is +a ``magic number'' or not, so you'd better assume that it is. +We get the tpoken numbers for \.{TANGLE} by subtracting an offset, +as you'll see later. +#<Set initial...#>= + highesttoken=200 ## highest numbered token + tokennumber=highesttoken + +# At the end we check to make sure we haven't used up too many numbers +for tokens. +\.{WEAVE} token numbers must be |>=127|. +#<Check for errors at the...#>= +if (tokennumber<127) { + print "Error: too many token names for WEAVE --- over by",\ + 127-tokennumber + exitcode=-1 + } +# \.{TANGLE} tokens must be between #'13 and #'37 inclusive. +We add three to the number because \.{TANGLE} has special definitions for +the three tokens taken off the top. +#<Check for errors...#>= +if (highesttoken-tokennumber > #'37-(#'13-1)+3) { \ + ## number of tokens in |#'13|--|#'37|, plus 3 + print "Error: too many token names for TANGLE --- over by",\ + highesttoken-tokennumber - (#'37-(#'13-1)+3) + exitcode=-1 + } + + + +# The token name is what \.{WEAVE} and \.{TANGLE} will use internally +to refer to the token's internal representation as an eight-bit code. +We use names instead of using the numbers directly in the vague hope that +it will make \.{WEAVE} and \.{TANGLE} easier to debug when something goes +wrong. +For multi-character tokens, the name will be a \.{WEB} macro that is defined +to be equal to the token's eight-bit code. +If the token is a single character, its ``name'' will be that character, +quoted with single quotes. +The single-character tokens \.{@}, \.{\\}, and \.{'} require special +handling, since they have to be escaped in some way to be quoted. + +Once we've computed the name, we put it in |tokenname[$2]|. +#<Set |tokenname[$2]|, |tokenlength[$2]|, and, for long + tokens, set |tokentest[$2]| and |tokennumbers[$2]|#>= + if ($2=="@") { + $2="@@" + tokenname[$2]="'@@'" + tokenlength[$2]=1 + } else if ($2=="'" || $2 == "\\") { + $2="\\" $2 + tokenname[$2]="'" $2 "'" + tokenlength[$2]=1 + } else if (length($2)>1) { + #<Handle multicharacter tokens#> + } else { + temp = sprintf("'%s'", $2) + tokenname[$2] = temp + tokenlength[$2]=1 + } + +# For the long tokens, we generate a name by which we'll refer to the +token. +That name will actually be defined to be a number, which we'll take to +be the current value of |tokennumber|. +We'll write in |tokentest[$2]| the C~code used to recognize that token, +and in |tokenlength[$2]| we'll leave that token's length. +(The length is used both to find long tokens before short ones, and +to avoid finding long ``tokens'' that +actually go beyond the end of the line.) +#<Handle multicharacter tokens#>= + tokenname[$2]="SP_gen_token_" tokennumber + tokennumbers[$2]=tokennumber + tokennumber-- + ## figure out how to recognize the token + temp = sprintf( "strncmp(\"%s\",loc-1,%d)==0", $2, length($2)) + tokentest[$2]=temp + tokenlength[$2]=length($2) + + +# The setting of attributes is as for all tokens: +#<Set attributes of token |$2|#>= + #<Set |this_mathness| etcetera to the defaults and those with no + defaults to |""| #> + this_name=tokenname[$2] + start_place=3 + #<Scan this line from |start_place| to finish, looking for + \.{translation}$\ldots$ and putting results in + |this_translation|$\ldots$#> + #<Make sure |this_category| is not empty#> + tokencategory[$2]=this_category + tokenmathness[$2]=this_mathness + tokentranslation[$2]=this_translation + tokenname[$2]=this_name + tokentangleto[$2]=this_tangleto + +# We have to remember the length of the longest token so we can +recognize long tokens before short ones. +#<Update record of maximum token length#>= + temp = tokenlength[$2] + if (temp > maxtokenlength) { + maxtokenlength=temp + } + +# We're paranoid. +#<Make sure token |$2| has a number if it needs one#>= + if (tokenlength[$2]>1 && tokennumbers[$2]=="") { + print "This can't happen: token", $2, "is long", \ + "but has no number" + exitcode = -1 + } + + +#*1Writing {\tt WEB}'s lexical analysis code. +The token recognition problem is the same for \.{WEAVE} and +\.{TANGLE}. +Both have routines called |get_next| that recognize the tokens on +input. +Most of |get_next| is prefabricated +(and the same in both \.{WEAVE} and \.{TANGLE}), +but we have to put in the part that recognizes multi-character +non-alphanumeric tokens. + +We write the same code to both \.{WEAVE} and \.{TANGLE}. +#<Write out...#>= + tempfile = scrapfile + #<Write token recognition code to |tempfile|#> + tempfile = ttokfile + #<Write token recognition code to |tempfile|#> + +# This is how we do it. +#<Write token recognition code to |tempfile|#>= +print "@ Here we input tokens of more than one character" > tempfile +print "@<Compress two-symbol operator@>=" > tempfile +#<Look for multicharacter tokens, starting with the longest, + and working down#> + +# We look for long tokens, then shorter, and so on. +We have to make sure we don't look beyond the end of a line. +#<Look for multicharacter tokens, starting with the longest, + and working down#>= + for (len=maxtokenlength; len>=2; len--) { + printf "if (loc+%d<=limit) {\n", len-1 > tempfile + #<Check for tokens in |tokentest| of length |len|#> + printf "\t}\n" > tempfile + } + #<Make sure there are no tokens of length 1 in |tokentest|#> + +# #<Check for tokens in |tokentest| of length |len|#>= +notfirst=0 +for (t in tokentest) { + if (tokenlength[t]==len) { + printf "\t" > tempfile + if (notfirst==1) { + printf "else " > tempfile + } + notfirst=1 + printf "if (%s) {\n", tokentest[t] > tempfile + printf "\t\tloc += %d;\n", len-1 > tempfile + printf "\t\treturn %s;\n\t\t}\n", tokenname[t] > tempfile + } + } + + +# #<Make sure there are no tokens of length 1 in |tokentest|#>= +for (t in tokentest) { + if (tokenlength[t]==1) { + print "This can't happen: token", t, "is of length 1 but", \ + "it has a test" + exitcode=-1 + } +} + + + +#*1Writing out {\tt WEAVE}'s token-to-scrap code. +Here is where we write the code that converts an already-recognized +token (from |get_next|) into a scrap. +There are several different kinds of tokens, and each requires a +slightly different treatment. +Will write out the code for the different species one at a time. +#<Write out all...#>= + print "Writing out predefined scraps" > logfile + #<Write code for identifier scrap#> + #<Write code for string or constant scrap#> + #<Write code for newline scrap#> + #<Write code for |pseudo_semi| scrap#> + print "Writing out token scraps" > logfile + #<Write code for ordinary token scraps#> + + + + +# This is how we write out the information for the identifier. +#<Write code for identifier scrap#>= + if (id_category != "") { + print "@ @<Append an identifier scrap@>=" > scrapfile + print "p=id_lookup(id_first, id_loc,normal);" > scrapfile + print "if (p->ilk==normal) {" > scrapfile + print " small_app(id_flag+p-name_dir);" > scrapfile + printf " app_scrap(SP_%s,%s_math);", \ + id_category, id_mathness > scrapfile + appended[id_category]=1 + print " /* not a reserved word */" > scrapfile + print "}" > scrapfile + print "else if reserved(p) {" > scrapfile + print "@<Decide on reserved word scraps@>;" > scrapfile + print "}" > scrapfile + print "else {" > scrapfile + print " err_print(\"! Identifier with unmentioned ilk\");" > scrapfile + print "@.Identifier with unmentioned ilk@>" > scrapfile + print "}" > scrapfile + } else { + print "Error: I don't know what to do with an identifier" + print " Please give me a \"token identifier ...\"" + exitcode = -1 + } + +# We hold the name |"identifier"|, and we reserve a number for +identifiers. +#<Set initial...#>= + tokennumbers["identifier"]=tokennumber; tokennumber-- + tokenname["identifier"]="identifier" + +# This is how we write out the string or constant scrap, at the end. +#<Write code for string or constant scrap#>= +print "Warning: TeX strings have the same category as ", \ + "numeric constants in this WEAVE." +print "Warning: TeX strings have the same category as ", \ + "numeric constants in this WEAVE." > logfile +if (number_category != "") { +print "@ For some reason strings, constants,",\ + " and \TeX\ strings are identified." > scrapfile +print "That has to be fixed." > scrapfile +print "@<Do the |app_scrap| for a string or constant@>=" > scrapfile +printf "app_scrap(SP_%s,%s_math);\n", number_category,\ + number_mathness > scrapfile +appended[number_category]=1 +} else { + print "Error: I don't know what to do with a numeric constant" + print " Please give me a \"token number ...\"" + exitcode = -1 + } + + +# We hold names and numbers for constants and strings, as well as identifiers. +#<Set initial...#>= + tokennumbers["constant"]=tokennumber; tokennumber-- + tokenname["constant"]="constant" + tokennumbers["string"]=tokennumber; tokennumber-- + tokenname["string"]="string" + + +# +#<Write code for newline scrap#>= +if (newline_category != "") { + print "@ @<Append a newline scrap@>=" > scrapfile + transstring=newline_translation + selfstring="small_app(next_control);" + wherestring="in translation of token newline" + append_keyword="small_app" + #<Take translation from |transstring| and write corresponding \.{WEAVE} code to + |outstring|, using |selfstring| as translation of |"<*>"|#> + print outstring > scrapfile + printf " app_scrap(SP_%s,%s_math);\n", newline_category,\ + newline_mathness > scrapfile + appended[newline_category]=1 +} else { + print "Error: I don't know what to do with a newline" + print " Please give me a \"token newline ...\"" + exitcode = -1 + } + +# +#<Write code for |pseudo_semi| scrap#>= +if (pseudo_semi_category != "") { + print "@ @<Append a |pseudo_semi| scrap@>=" > scrapfile + transstring=pseudo_semi_translation + selfstring="small_app(next_control);" + wherestring="in translation of token pseudo_semi" + append_keyword="small_app" + #<Take translation from |transstring| and write corresponding \.{WEAVE} code to + |outstring|, using |selfstring| as translation of |"<*>"|#> + print outstring > scrapfile + printf " app_scrap(SP_%s,%s_math);\n", pseudo_semi_category,\ + pseudo_semi_mathness > scrapfile + appended[pseudo_semi_category]=1 +} else { + printf "Error: I don't know what to do with a pseudo_semi (%s;)",\ + substr(at_sign,1,1) + print " Please give me a \"token pseudo_semi ...\"" + exitcode = -1 + } + +# Here is how we write out the code that converts ordinary tokens to scraps: +#<Write code for ordinary token scraps#>= +print "@ @<Cases for ordinary tokens@>=" > scrapfile +for (t in tokens) { + temp = tokenname[t] + printf "case %s:\n", temp > scrapfile + transstring=tokentranslation[t] + selfstring="small_app(next_control);" + wherestring= sprintf ("in translation of token %s", t) + append_keyword="small_app" + #<Take translation from |transstring| and write corresponding \.{WEAVE} code to + |outstring|, using |selfstring| as translation of |"<*>"|#> + print outstring > scrapfile + printf "\tapp_scrap(SP_%s,%s_math);\n", tokencategory[t], \ + tokenmathness[t] > scrapfile + temp = tokencategory[t] + appended[temp]=1 +#^append check#> + print "\tbreak;" > scrapfile + } + +#*3{\tt TANGLE}'s token-to-output conversion. +We have to write special cases for things appearing in |tokennumbers|. +The output conventions for |string|, |constant| and |identifier| are +fixed by \.{TANGLE}. + +One day we have to improve \.{TANGLE}'s treatment of spacing in the output; +at the moment it just makes sure there are spaces between adjacent identifiers +or numbers. +#^future enhancements#> +#<Write out...#>= +print "@ @<Cases for tokens to be output@>=" > ttokfile +for (t in tokennumbers) { + #<If |t| is |"string"|, |"constant"|, or |"identifier"|, just |continue|#> + printf "case %s:\n", tokenname[t] > ttokfile + this_tangleto = tokentangleto[t] + if (this_tangleto=="") { + printf "\tC_printf(\"%%s\",\"%s\");\n",t > ttokfile + } else { + printf "\tif (out_state==verbatim) {\n" > ttokfile + printf "\t\tC_printf(\"%%s\",\"%s\");\n",t > ttokfile + printf "\t} else {\n" > ttokfile + #<Write code to print |this_tangleto| onto |ttokfile|#> + printf "\t}\n" > ttokfile + } + print "\tif (out_state!=verbatim) out_state=misc;" > ttokfile + print "break;" > ttokfile + } + +# We also have to write something for the tokens that aren't in |tokennumbers| +but which have a nonnull |tokentangleto| anyway. +#<Write out...#>= +print "@ @<Cases for tokens to be output@>=" > ttokfile +for (t in tokentangleto) { + #<If |t| is |"string"|, |"constant"|, or |"identifier"|, just |continue|#> + if (tokennumbers[t]!="" || tokentangleto[t]=="") + continue + if (t=="@") { + thistangletokname = "@@" + } else if (t=="\\" || t=="'") { + thistangletokname = "\\" t + } else { + thistangletokname = t + } + printf "case '%s':\n", thistangletokname > ttokfile + this_tangleto = tokentangleto[t] + if (this_tangleto=="") { + print "This can't happen -- null tangleto for", t, wherestring + exitcode = -1 + } else { + printf "\tif (out_state==verbatim) {\n" > ttokfile + printf "\t\tC_printf(\"%%s\",\"%s\");\n",t > ttokfile + printf "\t} else {\n" > ttokfile + #<Write code to print |this_tangleto| onto |ttokfile|#> + printf "\t}\n" > ttokfile + } + print "\tif (out_state!=verbatim) out_state=misc;" > ttokfile + print "break;" > ttokfile +} +# The tokens for |string|, |constant|, and |identifier| are treated +specially by \.{TANGLE}; code to handle them already lives in \.{TANGLE}.web. +Therefore, we don't gum up the works with our scheming. +#<If |t| is |"string"|, |"constant"|, or |"identifier"|, just |continue|#>= +if (t=="string"||t=="constant"||t=="identifier") + continue + + + +# This is somewhat like the translation code, but tuned for \.{TANGLE} +#<Write code to print |this_tangleto| onto |ttokfile|#>= +oldwherestring = wherestring +wherestring = "for tangleto " wherestring +#@ +transstring=this_tangleto +#<Convert restricted translation in |transstring| + to quoted string in |outstring|#> +printf "\tC_printf(\"%%s\",%s);\n",outstring > ttokfile +#@ +wherestring=oldwherestring + + + +#*3Defining the token names. + At some point we'll have to define all these names, for both +\.{TANGLE} and \.{WEAVE}. We may as well +show how we do that now. +#<Write out...#>= + tempfile = scrapfile + #<Write the definitions of the token names to |tempfile|#> + tempfile = ttokfile + #<Write the definitions of the token names to |tempfile|#> + +# We use an ugly trick to get the token numbers different for +\.{WEAVE} and \.{TANGLE}: +#<Write the definitions of the token names to |tempfile|#>= + print "@ Here are the definitions of the token names" > tempfile + for (t in tokennumbers) { + temp = tokennumbers[t] + if (temp==0) + continue ## don't know why we need this!! + if (tempfile==ttokfile) { ## output to \.{TANGLE} + #<If |t| is |"string"|, |"constant"|, or |"identifier"|, + just |continue|#> ## already defined in \.{TANGLE} + temp = temp + #'37 + 3 - highesttoken ## hackety hack! + ## +3 because three highest are already defined! + } + printf "@d %s = %s\n", tokenname[t], temp > tempfile + } + + +# Some token names are just characters quoted with |'|. We write out +all the others. +#<Write lists...#>= + for (t in tokenname) { + temp = tokenname[t] + if (substr(temp,1,1) != "'") { + #<Strip opening |"SP_"| from |temp|, if it is there#> + print temp > tokennamefile + } + } + +# #<Strip opening |"SP_"| from |temp|, if it is there#>= +tempa=substr(temp,1,3) +if (tempa=="SP_") { + temp = substr(temp,4) ## remove |"SP_"| + } + + +#*Reserved words and ilks. +\.{TANGLE} doesn't even need the {\it idea} of + reserved words; it treats them like +all other identifiers. +\.{WEAVE}, however, needs to be able to recognize reserved words to do +prettyprinting. +\.{WEAVE} uses a two-tiered system for coping with reserved words. +I think this system was really designed to make it easier to code +\.{WEAVE} by hand, and is therefore not of much interest for +\.{SPIDER}, but we retain it as a matter of least resistance. + +Every reserved word belongs to an ilk, and it is the ilks that, like +tokens, have translations, categories, and so on. + +I have made a bewildering array of defaults that is probably full of +bugs. +We use a special convention to initialize the |this_| family. + +#<Pattern-act...#>= +#=/^ilk /#> { + print "Ilk", $2 > logfile + #<Set |this_mathness| etcetera to the defaults and those with no + defaults to |""| #> + #<If no category is specified, invent a default if you can#> + this_name="" + start_place=3 + #<Scan this line from |start_place| to finish, looking for + \.{translation}$\ldots$ and putting results in + |this_translation|$\ldots$#> + #<Make sure |this_category| is not empty#> + #<Make sure |this_name| is empty#> + ilk_category[$2]=this_category + ilk_mathness[$2]=this_mathness + ilk_translation[$2]=this_translation + next +} + + +# The pernicious option here is to be able to leave off the category, so +that an item of ilk |fish_like| will get category |fish|. + +#<If no category is specified, invent a default if you can#>= + if ($2 ~ #=/^[a-zA-Z_]+_like$/#> && $0 !~ #=/ category /#>) { + ## give default category + this_category = substr($2,1,length($2)-5) + categories[this_category]=1 + } + +# For the reserved words, our only option is to set an ilk. +We go through wild and assuredly ill-advised gyrations attempting to +set all the default properties of that ilk. +If the ilk is omitted, we make a new ilk by attaching the string +|"_like"| to the name of the reserved word. +{\bf Don't use this feature; it embarrasses the author.} +#^ill-advised#> +#<Pattern-action...#>= +#=/^reserved /#> { + print "Reserved word", $2 > logfile + if ($0 !~ #=/ ilk /#>) { + #<Attempt to make up an ilk, with all its defaults#> + } + for (i=3; i<=NF;) { + if ($i == "ilk") { + i++ + reservedilk[$2]=$i + has_reserved[$i]=1 ## remember that ilk has some reserved word + i++ + } else { + print "Error: bad reserved word attribute:", $i, \ + "on line", NR-1 + #<Punt...#> + } + } + #<Check that we used everything#> + next +} + +# Here is our feeble attempt to make up an ilk for a reserved word for +which no ilk is given. +The default ilk for |"with"| is |"with_like"|, and so on. +{\bf Please, please don't do this.} +#<Attempt to make up an ilk, with all its defaults#>= + temp = $2 "_like" + reservedilk[$2]=temp + if (ilk_translation[temp]=="") { + ilk_translation[temp]=default_translation + } + has_reserved[temp]=1 + if (ilk_mathness[temp]=="") { + ilk_mathness[temp]=default_mathness + } + ## and default category for that ilk is the resword itself + if (ilk_category[temp]=="") { + ilk_category[temp]=$2 + categories[$2]=1 + } + ilk_is_made_up[temp]=1 ## we really should do something with this +#^mistakes#> + + +#*1Telling {\tt WEAVE} how to recognize reserved words. +At the end, we'll write out definitions for the ilk names, and we'll +write translations of all the ilks. +#<Write out all...#>= +print "Writing out reserved words and ilks" > logfile +ilkno=64 +print "@ Here is a list of all the ilks" > reserved +for (i in ilk_translation) { + printf "@d SP_%s = %d\n", i, ilkno > reserved + ilkno++ + } + +# Here is where we write the code that converts reserved word tokens +into scraps. +#<Write out all...#>= +print " " > reserved +print "@ Here are the scraps we get from the reserved words" > reserved +print "@d the_word = res_flag+p-name_dir" > reserved +print "@<Decide on reserved word scraps@>=" > reserved +print "switch (p->ilk) {" > reserved +for (t in ilk_translation) { + printf "\tcase SP_%s: \n\t\t", t > reserved + transstring=ilk_translation[t] + selfstring="small_app(the_word);" + wherestring= sprintf ("in translation of ilk %s", t) + append_keyword="small_app" + #<Take translation from |transstring| and + write corresponding \.{WEAVE} code to + |outstring|, using |selfstring| as translation of |"<*>"|#> + if (trcnt>0) ## at least one text in the translation + has_translation[t]=1 + print outstring > reserved + printf "\tapp_scrap(SP_%s,%s_math);\n", ilk_category[t], \ + ilk_mathness[t] > reserved + temp=ilk_category[t] + appended[temp]=1 +#^append check#> + printf "\t\tbreak;\n" > reserved + } +print "}" > reserved + + +# At the end, we'll have to enter each reserved word in the identifier +table, along with its ilk. +#<Write out all...#>= +print "@ @<Store all the reserved words@>=" > reserved +for (i in reservedilk) { + printf "id_lookup(\"%s\",NULL,SP_%s);\n", i, reservedilk[i] > reserved +} + +# At the very end, we'll make sure every ilk has both a reserved word +and some translation. +{\bf Perhaps this could be cleaned up a bit?} +#<Check for errors at...#>= + for (i in ilk_translation) { + if (has_reserved[i] != 1) { + print "Error: there is no reserved word of ilk", i + exitcode=-1 + } + if (has_translation[i] != 1) { + print "Error: ilk", i, "has no translation" + exitcode=-1 + } + } + +# #<Write lists...#>= + for (i in ilk_translation) { + print i > ilkfile + } + +# #<Write stat...#>= +for (i in ilk_translation) number_of_ilks++ +for (i in reservedilk) number_of_reserved_words++ +printf "You defined %d reserved words of %d ilks.\n", \ + number_of_reserved_words, number_of_ilks +printf "You defined %d reserved words of %d ilks.\n", \ + number_of_reserved_words, number_of_ilks > logfile + +#*The prettyprinting grammar. +The most intricate part of \.{WEAVE} is its mechanism for converting +programming language code into \TeX\ code. +A ``bottom up'' approach is used to parse the +programming language material, since \.{WEAVE} 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 +program 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 find 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 is +$$\hbox{\.{open [ math semi <\.{"\\\\,"}-opt-5> ] --> +open math}}$$ +and it means that three consecutive scraps whose respective categories are +|open|, |math|, and |semi| are con\-verted to two scraps whose categories +are |open| and |math|. + The |open| scrap has not changed, while the string \.{<"\\\\,"-opt-5>} +indicates that the new |math| scrap +has a translation composed of the translation of the original +|math| scrap followed by the translation of the |semi| scrap followed +by `\.{\\,}' followed by `|opt|' followed by `\.5'. (In the \TeX\ file, +this will specify an additional thin space after the semicolon, followed +by an optional line break with penalty 50.) + +Their is an extensive discussion of the grammar, with examples, in the +``Spider User's Guide.'' +Y'oughta read it. + +#*1Scanning a production. + A production in the grammar is written as a sequence of category +names and translations, followed by a right arrow (\.{-->}), followed +by a category name. +When \.{WEAVE} is scanning the sequence of scraps that makes up a +module, it checks to see whether the categories of those scraps match +the categories given on the left side of the production. +If so, the production fires, and the scraps and translations on the +left side of the arrow are combined into a single, new scrap, and the +new scrap is given the category from the right side of the arrow. +The scraps which are combined are called the firing scraps, +#^firing scraps#> +and the category given to the combination is called the target category. + +Instead of a category name, e.g.~``\.{math},'' one can write a list of +category names, e.g.~``\.{(open\vert lsquare)}'' instead. +A scrap matches the list if and only if its category is one of the +names listed. +One can also use the wildcard ``\.?'', which any scrap matches. + +On the right-hand side, one can write a \## followed by a number in +place of the target category name. +If we specify the target category as ``\.{\##2}'', for example, it +means ``give the new scrap the same category as the second scrap that +matched the left side of the production.'' + +# Here is the whole syntax as quoted from the ``Spider User's Guide'' + +\begingroup\def\\{\par\noindent\ignorespaces}\tt +\noindent\syntax{production} \produces\\\quad +\syntax{left context} [ \syntax{firing instructions} ] \syntax{right context} +--> \syntax{left context} \syntax{target category} \syntax{right +context}\\ +\syntax{left context} \produces~\syntax{scrap designators}\\ +\syntax{right context} \produces~\syntax{scrap designators}\\ +\syntax{firing instruction} \produces \syntax{scrap designator}\\ +\syntax{firing instruction} \produces \syntax{translation}\\ +\syntax{scrap designator} \produces~?\\ +\syntax{scrap designator} \produces~\opt{!}\syntax{marked category}\\ +\syntax{scrap designator} \produces~\opt{!}\syntax{category alternatives}\\ +\syntax{category alternatives} \produces~(\syntax{optional +alternatives}\syntax{marked category})\\ +\syntax{optional alternative} \produces~\syntax{marked category}\vert\\ +\syntax{marked category} \produces~\syntax{category name}\opt{*}\\ +\syntax{target category} \produces~\#\syntax{integer}\\ +\syntax{target category} \produces~\syntax{category name}\\ +\endgroup + +# Here is the pattern that reads productions. +In most of the modules below, we read through some of the fields of the +production. +We use |i| to remember what field we are about to examine. +When a module terminates, |$i| is left pointing to the first field of +interest to the next module. +#<Production patt...#>= +#=/-->/#> { + #<Set up to parse this production#> + #<Read through the fields of the production, up to the arrow#> + #<Set |lowpos|, |highpos|, and |arrowpos| to their proper values#> + #<Update |highestposoverall|#> + #<Update |highestunknownpos|#> + #<Check to see that left context matches#> + #<Process scrap to which we are translating#> + #<Check to see that right context matches#> + #<Check to make sure we used all the fields of the production#> + #<Compute the appropriate test for this production and put it + in |prodtest[prodnum]|#> + #<Compute the code to write the new translation, should this + production fire, and put it in |prodtrans[prodnum]|#> + #<Write the start token in |ppstart[prodnum]| and the number + of tokens reduced in |tokensreduced[prodnum]|#> + #<If we only reduced one token, write the reduction + out to file |cycles| for later testing#> + next +} ## \.{/-->/} + +# Each scrap in the production will be given a position |pos|, +beginning with 1. (Using 1 and not 0 lets us make good use of the fact +that uninitialized AWK variables will have value zero.) +We will remember the positions of the scraps that get reduced; they +will be from |lowpos| to |highpos-1|. +We keep track of the production number in |prodnum|, and we save a +copy of the input line in |inputline[prodnum]|. +#<Set up to parse this production#>= + lowpos=0; highpos=0; pos=1 + prodnum=prodnum+1 + inputline[prodnum]=$0 + print "Parsing production", prodnum, $0 > logfile + + +# This is the guts of the parsing. We have to read each field in the +production, determine whether it is category or translation +information, and act accordingly. +Each scrap will be given a position |pos|. +We will write in |test[pos]| the code needed to decide whether a +particular scrap matches the pattern given in the production. +Scraps can match a single category by name, a list of categories, or +|"?"|, which every scrap matches. +Categories can be starred, in which case we underline the index entry +of the first identifier in the scrap's translation. + +We also write in |trans[pos]| the code necessary to produce the +translations preceding the scrap at |pos|. + +#<Read through the fields...#>= +trans[pos]="" +for (i=1; i<=NF; i++) { + if ($i ~ #=/<.*>/#>) { ## should be |trans_pattern| + #<Process a translation in |$i|#> + } else if ($i ~ #=/^!?[a-zA-Z_]+(\*\*?)?$/#>) { ## |cat_pattern| + #<Process a single category#> + } else if ($i ~ #=/^!?\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/#>){ + #<Process a list of alternative categories#> + } else if ($i == "?") { + #<Process a category wild card#> + } else if ($i == "[") { + lowpos=pos + } else if ($i == "]") { + highpos=pos + } else if ($i=="-->") { + break + } else { ## we don't recognize the field + print "Error: bad field is", $i, "in production on line", NR-1 + #<Forget this production#> + } +} +i++ + + +# When we find a mistake, we just abandon the current production. +Decrementing |prodnum| will make it as if this production never happened. +#<Forget this production#>= + prodnum-- + #<Punt this...#> + +# We process the translation and add the result to the current +translation for |pos|. +#<Process a translation...#>= +transstring=$i +selfstring="" ## senseless for productions +wherestring= sprintf ("in production on line %d", NR-1) +append_keyword="app" +#<Take translation from |transstring| and write corresponding \.{WEAVE} code to +|outstring|, using |selfstring| as translation of |"<*>"|#> +trans[pos]=trans[pos] outstring + +# Here we'll set |test[pos]|. +The phrase |test[pos]| will be a single C conjunct; if the test for +each scrap is true, the whole production will fire. +If we're called upon to make a scrap underlined or reserved, we'll add +to |trans[pos]|. + +If a category is negated we add an extra clause to make +sure nothing matches the zero category, since {\tt WEAVE} assumes +no production ever matches a scrap with category zero. +#<Process a single category#>= + field[pos]=$i ## save this field to compare RHS + #<Set |negation|, and remove leading |"!"| from |$i| if necessary#> + #<Strip stars from |$i| (if any) and add appropriate + translations to |trans[pos]|#> + cat = $i + categories[cat]=1 ## remember |cat| is a category + if (negation==0) { + test[pos]=sprintf("(pp+%d)->cat==SP_%s",pos-1,cat) + } else { + test[pos]=sprintf("((pp+%d)->cat!=SP_%s && (pp+%d)->cat != 0)",\ + pos-1,cat,pos-1) + } + #<Update the record of the rightmost occurrence of category |cat|#> + #<Advance |pos|, making the new |trans[pos]| empty#> + +# The list of categories is enclosed in parentheses and the individual +categories are separated by vertical bars. +We have to make the test for these things a disjunction, but +processing is more or less like the processing for a single category. + +If a list of alternatives is negated we add an extra clause to make +sure nothing matches the zero category, since {\tt WEAVE} assumes +no production ever matches a scrap with category zero. +#<Process a list of alternative categories#>= + field[pos]=$i ## save this field to compare RHS + #<Set |negation|, and remove leading |"!"| from |$i| if necessary#> + if (negation==0) { + test[pos]="(" ## open for a list of good alternatives + } else { + temp=sprintf("(pp+%d)->cat==0",pos-1) + test[pos]="!(" temp "||" ## open for a list of bad alternatives + } + #<Strip stars from |$i| (if any) and add appropriate + translations to |trans[pos]|#> + temp = substr($i,2,length($i)-2) ## throw out parens + m = split(temp,tok,"|") + for (j=1;j<=m;j++) { + cat = tok[j] + categories[cat]=1 ## remember it's a category + #<Update the record of the rightmost occurrence of + category |cat|#> + temp=sprintf("(pp+%d)->cat==SP_%s",pos-1,cat) + test[pos]=test[pos] temp ## add alternative to test + if (j!=m) + test[pos]=test[pos] "||\n" ## line too long errors + } + test[pos]= test[pos] ")" + #<Advance |pos|, making the new |trans[pos]| empty#> + + +# We keep track of the rightmost occurrence of each category. +This enables us to backtrack by exactly the right amount when a +production fires and creates a new scrap. +#<Update the record of the rightmost occurrence of category |cat|#>= + if (pos > highestpos[cat]) { + highestpos[cat]=pos + } + +# If a category or lsit of alternatives is preceded by an exclamation +point (|"!"|), we set |negation|, and we will test for scraps that are +{\it not} of that category or are {\it not} of one of the categories +listed. +#<Set |negation|...#>= +temp = substr($i,1,1) +if (temp=="!") { + negation = 1 + $i = substr($i,2) +} else { + negation = 0 +} + +# Since both translations and tokens can add to |trans[pos]| we must +make sure it is empty whenever we get a new |pos|. +This device makes that easy. + +#<Advance |pos|, making the new |trans[pos]| empty#>= + pos=pos+1 + trans[pos]="" + +# If a category is single-starred, we take this construct to be the +{\it definition} of that item, and we underline the index entry for +this module. +The |make_underlined| routine finds the first identifier in the +translation of the starred scrap, and underlines the index entry for +that identifier in this module. + +If a category is double-starred, we used to try to change the ilk of the +appropriate identifier to make it a reserved word. +The only use this ever had was in handling C typedefs, and it should +probably be removed. +#^mistakes#> +In the meanwhile, double starring is like single starring. + +#<Strip stars from |$i| (if any) and add appropriate + translations to |trans[pos]|#>= +if ($i ~ #=/^([a-zA-Z_]+|\(([a-zA-Z_]+\|)*[a-zA-Z_]+\))\*\*$/#>) { ## it's double-starred + temp = sprintf("\tmake_underlined(pp+%d);\n",pos-1) + trans[pos] = trans[pos] temp + $i = substr($i,1,length($i)-2) +} else if ($i ~ #=/^([a-zA-Z_]+|\(([a-zA-Z_]+\|)*[a-zA-Z_]+\))\*$/#>) { ## it's starred + temp = sprintf("\tmake_underlined(pp+%d);\n",pos-1) + trans[pos] = trans[pos] temp + $i = substr($i,1,length($i)-1) +} else if ($i ~ #=/\*$/#>) { ## a bad star? + print "Error: can't remove stars in production on line", NR-1 + #<Forget this production#> +} + +# Wild cards are easy to process, but we do have to remember that +not even a wild card matches a scrap of category zero. +#<Process a category wild card#>= + field[pos]=$i ## save this field to compare RHS + test[pos]=sprintf("(pp+%d)->cat!=0",pos-1) ## anything nonzero matches + highwildcard=pos ## we don't really need this? + #<Advance |pos|, making the new |trans[pos]| empty#> + + + +# +We reach this point in the program after we will have read the arrow +into |$i|. + +This module establishes in what ranges of |pos| the contexts fall: +$$\vbox{\halign{##\hfil\tabskip1em&\hfil##\hfil\cr +\bf Items&\bf Range\cr +\noalign{\vskip2pt} +left context&|1..lowpos-1|\cr +firing instructions&|lowpos..highpos-1|\cr +right context&|highpos..arrowpos-1|\cr +}}$$ +If |lowpos| and |highpos| haven't been set by the appearance of square +brackets, we set them to make the contexts empty. +None or both should be set. + + +#<Set |lowpos|, |highpos|, and |arrowpos| to their proper values#>= + arrowpos=pos + if (lowpos==0 && highpos==0) { + lowpos=1 ## first transform position + highpos=arrowpos ## first token not reduced + ## (or one beyond last token position) + } else if (lowpos==0 || highpos==0) { + print "Error: square brackets don't balance in", \ + "production on line", NR-1 + #<Forget this production#> + } + +# Here is the efficient place to update the rightmost (highest) +position of {\it any} category. +#<Update |highestposoverall|#>= + if (arrowpos-1 > highestposoverall) { + highestposoverall=arrowpos-1 + } + +# Dealing with grammars in which categories can be unnamed (using +wildcards or negation) can be a pain in the ass. +What we have to do, when reducing after firing a production, is move +backwards enough so that we don't miss any earlier productions that +are supposed to fire. +This means we have to move back at least far enough so that the new +scrap will match any unnamed category. +{\bf But} we don't have to worry about wildcards (|"?"|) at the end of +a production, because they would have matched anyway, even before the +current production fired. Hence: +#<Update |highestunknownpos|#>= +for (hup=arrowpos-1; field[hup]=="?";) { + hup-- + } +for (;hup>highestunknownpos;hup--) { + temp=field[hup] + temp=substr(temp,1,1) + if (temp=="?" || temp =="!") { + highestunknownpos=hup ## we know |hup>highestunknownpos| + break ## redundant, since test will fail + } +} + +# Here is the error checking for context sensitive productions. +#<Check to see that left context matches#>= + for (pos=1;pos<lowpos;pos++) { + #<Check |$i| against |field[pos]|#> + i++ + } + +# #<Check to see that right context matches#>= + for (pos=highpos;pos<arrowpos;pos++) { + #<Check |$i| against |field[pos]|#> + i++ + } +# #<Check |$i| against |field[pos]|#>= + if (i>NF || $i != field[pos]) { + print "Error: token mismatch is: found", $i, \ + "sought", field[pos], "on line", NR-1 + #<Forget this...#> + } + +# We process our target scrap in between checking the left and right +contexts. +This scrap can be the name of a category, or it can be ``$\##nnn$'', +where $nnn$ refers to the number of a category on the left side of the +arrow. +In this way it is possible to match wildcards and lists of alternatives. +#<Process scrap to which we are translating#>= + ## i points to the target category + if (i>NF) { + print "Error: no target category in production on line", NR-1 + #<Forget this...#> + } + if ($i ~ #=/##[0-9]+/#>) { ## a number + $i = substr($i,2) ## peel off the \## + #<Make sure |1 <= $i < arrowpos|#> + targetcategory[prodnum]="Unnamed category" + temp = sprintf("(pp+%d)->cat", $i-1) + unnamed_cat[prodnum]=temp + } else if ($i ~ #=/[a-zA-Z][a-zA-Z_]*/#>) { ## a category + targetcategory[prodnum]=$i + categories[$i]=1 ## remember this is a category + } else { + print "Error: unrecognizable target token", $i, \ + "in production on line", NR-1 + #<Forget this...#> + } + i++ + +# We call this at the end to make sure there aren't unused fields left over +#<Check to make sure we used all the fields of the production#>= + if (i<=NF) { + print "Error: used only " i-1 " of " NF " tokens", \ + "in production on line", NR-1 + #<Forget this...#> + } + +# After having vetted the whole production, we combine the tests and +translations for each |pos|. +#<Compute the appropriate test for this production and put it + in |prodtest[prodnum]|#>= + prodtest[prodnum]="" + for (pos=1;pos<arrowpos;pos++) { + if (pos>1) { + prodtest[prodnum]=prodtest[prodnum] " &&\n\t\t" + } + prodtest[prodnum]=prodtest[prodnum] test[pos] + } + +# #<Compute the code to write the new translation, should this + production fire, and put it in |prodtrans[prodnum]|#>= + prodtrans[prodnum]="" + for (pos=lowpos;pos<highpos;pos++) { + prodtrans[prodnum]=prodtrans[prodnum] trans[pos] + ## add code to append this scrap + temp = sprintf("\tapp1(pp+%d);\n",pos-1) + prodtrans[prodnum]=prodtrans[prodnum] temp + #<If not negated, record the fact that a token of + category satisfying |test[pos]| could have + been reduced#> + } + prodtrans[prodnum]=prodtrans[prodnum] trans[highpos] + +# #<Write the start token in |ppstart[prodnum]| and the number + of tokens reduced in |tokensreduced[prodnum]|#>= + ppstart[prodnum]=lowpos-1 + tokensreduced[prodnum]=highpos-lowpos + +# #<If we only reduced one token, write the reduction + out to file |cycles| for later testing#>= + if (highpos-lowpos==1) { + printf "%d: %s --> %s\n", prodnum, field[lowpos], \ + targetcategory[prodnum] > cycles + wrotecycles = 1 + } + +# If we never even had the possibility of a cycle, we still have to write +out a dummy file so the cycle checker in the Makefile won't barf. +# #<Write lists of everything#>= +if(wrotecycles==0) { + print "0: dummy --> nodummy" > cycles + } + +# For error checking, we keep track of categories that get reduced in +productions. +We can't do this while scanning the production, because we don't know +at the beginning what |lowpos| will be, since we might or might not +ever see a left square bracket. + +If a particular category is never reduced, that merits a warning later on. +#<If not negated, record the fact that a token of category satisfying + |test[pos]| could have been reduced#>= +temp = field[pos] +tempa = substr(temp,1,1) +if (tempa != "!") { + if (temp ~ #=/^\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/#>) { + ## list of alternatives + #<Remove trailing stars from |temp|#> + temp = substr(temp,2,length(temp)-2) + m = split(temp,tok,"|") + for (j=1;j<=m;j++) { + alternate = tok[j] + reduced[alternate]=1 + } + } else if (temp ~ #=/^[a-zA-Z_]+(\*\*?)?$/#>) { + #<Remove trailing stars from |temp|#> + reduced[temp]=1 + } else if (temp != "?") { + print "Confusion: unintelligible field[pos]:", temp, \ + "in production on line", NR-1 + #<Forget this...#> + } +} + +# #<Remove trailing...#>= +while (temp ~ #=/\*$/#>) { + temp = substr(temp,1,length(temp)-1) +} + +# #<Check for err...#>= +for (c in categories) { + if (reduced[c] != 1) { + print "Warning: category", c, "never reduced" + } +} + + +# Here's a check for the target token number +#<Make sure |1 <= $i < arrowpos|#>= +if ((0+$i)<1 || (0+$i)>=0+arrowpos) { + print "Error: can't take token number", $i, "of", arrowpos-1, \ + "tokens", "in production on line", NR-1 + #<Forget this...#> + } + +#*1Writing the scrap reduction code. +Before writing the grammar, we want to define all of the category codes. +#<Write out...#>= + print "Writing out category codes" > logfile + print "@ Here is a list of category codes scraps can have" > grammarfile + i=1 + for (t in categories) { + printf "@d SP_%s = %d\n",t,i > grammarfile + i++ + } + print "@c" > grammarfile +# We also want to make sure we can print the names of categories in +case we need to debug. +#<Write out...#>= + print "##ifdef DEBUG" > grammarfile + print "##define PRINT_CAT(A,B) case A: printf(B); break" > grammarfile + print "print_cat(c) /* symbolic printout of a category */" > grammarfile + print "eight_bits c;" > grammarfile + print "{" > grammarfile + print " switch(c) {" > grammarfile + for (t in categories) { + printf "PRINT_CAT(SP_%s,\"%s\");\n",t,t > grammarfile + } + print " case 0: printf(\"zero\"); break;" > grammarfile + print " default: printf(\"UNKNOWN\"); break;" > grammarfile + print " }" > grammarfile + print "}" > grammarfile + print "##endif DEBUG" > grammarfile + print " " > grammarfile + +# And there goes the list... +#<Write lists...#>= + for (c in categories) { + print c > categoryfile + } + +# #<Write stat...#>= +for (c in categories) { + number_of_categories++ +} +printf "You used %d different categories in %d productions.\n", \ + number_of_categories, prodnum +printf "You used %d different categories in %d productions.\n", \ + number_of_categories, prodnum > logfile +printf "The biggest production had %d scraps on its left-hand side.\n", \ + highestposoverall +printf "The biggest production had %d scraps on its left-hand side.\n", \ + highestposoverall > logfile + + +# We will write a list of the successfully parsed productions to a +separate file. +The list will include + production numbers, to which the user can refer +when debugging. +#<Write lists...#>= +for (n=1; n<= prodnum; n++) { + printf "%2d: %s\n",n,inputline[n] > productions + } + +# Finally, we write out the code for all of the productions. +Here is our first view of category checking: we want to make sure that +each category can be appended, either by |app_scrap| or by |reduce|. +We also want to make sure each category can be reduced by firing some +production. +We track these things using the arrays |appended| and |reduced|. + +We write the definition of |highestposoverall|, for safety. + +We used to write this code as a very deeply nested if-then-else, +but that caused a yacc overflow in the generated code for C~{\tt WEAVE}. +So now we write +{\tt if (...) \LB...; goto end\_prods;\RB} +#<Write out...#>= +print "Writing out grammar" > logfile +print "@ Here is where we define |highestposoverall| and where we" > grammarfile +print "check the productions." > grammarfile +print "@d highestposoverall =", highestposoverall > grammarfile +print "@<Test for all of the productions@>=" > grammarfile +for (n=1; n<=prodnum; n++) { + if (n%5==0) + print "@ @<Test for all of the productions@>=" \ + > grammarfile ## avoids overflowing \.{WEAVE} of \.{WEAVE} + #<Change \vert,\_, and {\tt \##} in |inputline[n]|; put results in |this_string|#> + #<Make |this_string| no more than 60 characters wide#> + printf "if (%s) {\n\t/* %d: {\\tt %s} */\n%s",\ + prodtest[n],n,this_string,prodtrans[n] > grammarfile + #<Write the |reduce| call, taking note of whether the + category is named#> + print "\tgoto end_prods;" > grammarfile + printf "} " > grammarfile + } +printf "\n" > grammarfile +print "end_prods:" > grammarfile + +# We do different things for a category that is unnamed. +#<Write the |reduce| call, taking note of whether the category is named#>= + ttk=targetcategory[n] + if (ttk == "Unnamed category") { +#^append check#> + printf "\treduce(pp+%d,%d,%s,%d,%d);\n",ppstart[n],\ + tokensreduced[n],unnamed_cat[n],\ + 1-highestposoverall,n > grammarfile + } else { + appended[ttk]=1 ## remember we appended this token +#^append check#> + reduction=highestpos[ttk] + if (reduction<highestunknownpos) { + reduction = highestunknownpos + } + printf "\treduce(pp+%d,%d,SP_%s,%d,%d);\n",ppstart[n],\ + tokensreduced[n],targetcategory[n],\ + 1-reduction,n > grammarfile + } + +# This is the place we check for errors. +#^append check#> +#^reduce check#> +#<Check for errors...#>= +for (c in categories) { + if (appended[c] != 1) { + if (c=="ignore_scrap") { ## appended by \.{WEAVE} + print "Warning: category", c, "never appended" + } else { + print "Error: category", c, "never appended" + exitcode=-1 + } + } + } + + + +# It's desirable to put the production in a comment, but we have to +get rid of the confusing \vert, or \.{WEAVE} will think it introduces +code. +We also have to escape underscores and sharp signs, otherwise \TeX\ will +think we want math mode. +#<Change \vert,\_, and {\tt \##} in |inputline[n]|; put results in |this_string|#>= + this_string = inputline[n] + tempi = index(this_string,"|") + while (tempi != 0) { + tempa = substr(this_string,1,tempi-1) + tempb = substr(this_string,tempi+1) + this_string = tempa "\\vert " tempb + tempi = index(this_string,"|") + } + templ = ""; tempr = this_string + tempi = index(tempr,"_") + while (tempi != 0) { + tempa = substr(tempr,1,tempi-1) + tempr = substr(tempr,tempi+1) + templ = templ tempa "\\_" + tempi = index(tempr,"_") + } + this_string = templ tempr + templ = ""; tempr = this_string + tempi = index(tempr,"##") + while (tempi != 0) { + tempa = substr(tempr,1,tempi-1) + tempr = substr(tempr,tempi+1) + templ = templ tempa "\\##" + tempi = index(tempr,"##") + } + this_string = templ tempr + + +# We have to keep these productions from making an input line too long. +#<Make |this_string| no more than 60 characters wide#>= +toolong=this_string; this_string="" +while (length(toolong)>60) { + idx=59 + idchar = substr(toolong,idx,1) + while (idx>1 && idchar!=" ") { + idx-- + idchar = substr(toolong,idx,1) + } + if (idx==1) + idx=59 + temp = substr(toolong,1,idx-1) + toolong = substr(toolong,idx+1) + this_string = this_string temp "\n" +} +this_string = this_string toolong + + + +#*The rest of {\tt SPIDER}. +We present the remaining features of \.{SPIDER} in them order we +used in the ``\.{SPIDER} User's Guide.'' +#*2 Naming the target language. +\.{SPIDER} is designed to help you build a \.{WEB} system for any +programming language. +We need to know the name of the language, and what extension to +use when writing the tangled unnamed module. +We use this information to pick a name for the file that will hold +this \.{WEB}'s special \TeX{} macros, and we write |"\\input webkernel"| +on that file. +#<Patt...#>= +#=/^language /#> { + language = $2 + extension=language + for (i=3; i<NF; ) { + if ($i=="extension") { + i++ + extension=$i + i++ + } else if ($i=="version") { + i++ + version=$i + i++ + } else { + print "Error: unknown language property", $i,\ + "on line", NR-1 + #<Punt...#> + } + } + #<Check that we used everything#> + #<Write the first line of the macro file#> + next +} + +# #<Write out...#>= +if (language != "") { + print "@ Here is the language-dependent stuff" > tlang + if (version!="") + version = ", Version " version + printf "@d banner = \"This is %s TANGLE%s %s\\n\"\n", language, \ + version, date > tlang + printf "@<Global...@>=char C_file_extension[]=\"%s\";\n", extension \ + > tlang +#@ + print "@ Here is the language-dependent stuff" > wlang + if (version!="") + version = ", Version " version + printf "@d banner = \"This is %s WEAVE%s %s\\n\"\n", language, \ + version, date > wlang + print "@<Set |out_ptr| and do a |tex_printf| to read the macros@>=" \ + > wlang + printf "*out_ptr='x'; tex_printf(\"\\\\input %sweb.te\");\n", \ + extension > wlang + printf "@ @<Global...@>=char C_file_extension[]=\"%s\";\n", extension \ + > wlang +} else { + print "Error: you haven't given me any \"language\" information" + exitcode=-1 +} + +#*1Defining {\TeX} macros. +The first thing we do after getting the language is write a line to +the macro file. +This makes sure the kernel \.{WEB} macros will be available. +#<Write the first line of the macro file#>= + macrofile = extension "web.tex" + print "\\input webkernel.tex" > macrofile + + +# Processing macros is straightforward: everything between \.{macros +begin} and \.{macros end} gets copied into the macro file. +#<Patt...#>= +#=/^macros begin$/,/^macros end$/#> { + if (begunmacs==0) { + begunmacs=1 + next + } + if ($0 ~ #=/^macros end$/#>) { + begunmacs=0 + next + } + if (macrofile=="") { + if (complained==0) { + print "Error: you must give \"language\"",\ + "before \"macros\"" + complained=1 + #<Punt...#> + } + } else { + print $0 > macrofile + } + next +} + + + +#*1Handling modules. +We need to give module names a category, both when we define modules +and when we use them in other modules. + +We might conceivably fool around with mathness, but we don't +really intend to do so. +#<Pattern-action...#>= +#=/^module /#> { + for (i=2;i<NF;) { + if ($i=="definition") { + i++ + mod_def_cat=$i + categories[$i]=1 + print "Module definition category set to", $i > logfile + i++ + } else if ($i=="use") { + i++ + mod_use_cat=$i + categories[$i]=1 + print "Module use category set to", $i > logfile + i++ + } else { + print "Error: unknown module property", $i, \ + "on line", NR-1 + #<Punt...#> + } + } + #<Check that we used everything#> + next +} + +# Here's how we rig it: +#<Write out...#>= +if (mod_def_cat!="") { + print "@ @<Call |app_scrap| for a module definition@>=" > scrapfile + printf "app_scrap(SP_%s,no_math);\n", mod_def_cat > scrapfile + appended[mod_def_cat]=1 +} else { + print "Error: I don't know what to do with a module definition" + print " Give me a \"module definition ...\"" + exitcode=-1 +} +if (mod_use_cat!="") { + print "@ @<Call |app_scrap| for a module use@>=" > scrapfile + printf "app_scrap(SP_%s,maybe_math);\n", mod_use_cat > scrapfile + appended[mod_use_cat]=1 +} else { + print "Error: I don't know what to do with a module use" + print " Give me a \"module use ...\"" + exitcode=-1 +} + + +#*1At sign. +With \.{SPIDER}, we can designate any character we like as the +``magic at sign.'' +#<Pattern-act...#>= +#=/^at_sign /#> { + if (NF==2 && length($2)==1) { + if ($2=="@") { + at_sign="@@" + } else { + at_sign=$2 + } + } else { + print "Error: I can't understand", $0 + print " Give me an at sign of length 1" + #<Punt...#> + } + next +} + +# We write the at sign out to the grammar file and to \.{TANGLE}'s token file +#<Write out all...#>= + tempfile = grammarfile + #<Write |at_sign| definion to |tempfile|#> + tempfile = ttokfile + #<Write |at_sign| definion to |tempfile|#> + +# It's trivially done +#<Write |at_sign| definion to |tempfile|#>= + print "@ Here is the |at_sign| for the new web" > tempfile + printf "@d at_sign = @`%s'\n", at_sign > tempfile + print " " > tempfile + print "@ Here is |the_at_sign| left for common" > tempfile + print "@<Global...@>=char the_at_sign = at_sign;" > tempfile + print " " > tempfile + +# We provide a default at sign: +#<Set init...#>= + at_sign="@@" + + +#*1Comments. +We have to explain how our programming language supports comments. +We give the strings that initiate and terminate a comment. +We can say comments are terminated by ``newline'' if that's the case. +#<Pattern-act...#>= +#=/^comment /#> { + print $0 > logfile + for (i=2; i<NF;) { + if ($i=="begin") { + i++ + if ($i ~ #=/^<.*>$/#>) { + transstring = $i + wherestring = "in \"comment begin\" on line " NR-1 + #<Convert restricted translation in |transstring| + to quoted string in |outstring|#> + begin_comment_string = outstring + i++ + } else { + print "Error: \"comment begin\" must have a restricted translation" + #<Punt...#> + } + } else if ($i=="end") { + i++ + if ($i=="newline") { + comments_end_with_newline = 1 + end_comment_string = "\"\\n\"" + } else if ($i ~ #=/^<.*>$/#>){ + comments_end_with_newline = 0 + transstring = $i + wherestring = "in \"comment end\" on line " NR-1 + #<Convert restricted translation in + |transstring| + to quoted string in |outstring|#> + end_comment_string = outstring + } else { + print "Error: \"comment end\" must have a restricted translation" + #<Punt...#> + } + i++ + } else { + print "Error: bad comment attribute:", $i + #<Punt...#> + } + } + #<Check that we used everything#> + #<Write the comment definitions to the macro file#> + next +} + +# \.{WEAVE} and \.{TANGLE} must be able to recognize comments. +Here we give \.{TANGLE} + quoted strings that show the beginning and end of a +comment. + +#<Write out...#>= +print "@ Here we recognize the comment start seqence" > ttokfile +print "@<See a comment starting at |loc| and skip it@>=" > ttokfile + printf "{int len; len=strlen(%s);\n", begin_comment_string > ttokfile + printf "if (loc+len<=limit && !strncmp(loc,%s,len)) {\n",\ + begin_comment_string > ttokfile + print "\tloc += len; /* a new thing */" > ttokfile + print "\tskip_comment(); /* scan to end of comment or newline */" > ttokfile + print "\tif (comment_continues || comments_end_with_newline)" > ttokfile + print "\t\treturn('\\n');" > ttokfile + print "\telse continue;\n}\n}" > ttokfile + + +# Now this is \.{WEAVE} finding the start of a comment +#<Write out...#>= +print "@ @<See a comment starting at |loc-1| and return |begin_comment|@>=" \ + > scrapfile + printf "{int len; len=strlen(%s);\n", begin_comment_string > scrapfile + printf "if (loc+len-1<=limit && !strncmp(loc-1,%s,len)) {\n",\ + begin_comment_string > scrapfile + print "\tloc += len-1;" > scrapfile + print "\t return (begin_comment); /* scan to end of comment or newline */" > scrapfile + print "}\n}" > scrapfile + + + + +# Here \.{TANGLE} spots the end of a comment +#<Write out...#>= +print "@ Here we deal with recognizing the end of comments" > ttokfile +printf "@d comments_end_with_newline = %d\n", comments_end_with_newline >ttokfile +print "@<Recognize comment end starting at |loc-1|@>=" > ttokfile +if (comments_end_with_newline != 1) { + printf "{int len; len=strlen(%s);\n", end_comment_string > ttokfile + printf "if (loc+len-1<=limit && !strncmp(loc-1,%s,len)) {\n",\ + end_comment_string > ttokfile + print "loc += len-1; return(comment_continues=0); }}" > ttokfile +} else { + print "/* This code will never be executed */ " > ttokfile +} + +# Now here is \.{WEAVE}. +\.{WEAVE} copes elsewhere with the situation when +|comments_end_with_newline| holds, so we don't need to consider it here. +#<Write out...#>= +printf "@ Here we recognize end of comments" > scrapfile +printf "@d comments_end_with_newline = %d\n",comments_end_with_newline >scrapfile +print "@<Check for end of comment@>=" > scrapfile + printf "{int len; len=strlen(%s);\n", end_comment_string > scrapfile + printf "if (loc+len-1<=limit && !strncmp(loc-1,%s,len)) {\n",\ + end_comment_string > scrapfile +print " loc++; if(bal==1) {if (phase==2) app_tok('}'); return(0);}" > scrapfile +print " else {" > scrapfile +print " err_print(\"! Braces don't balance in comment\");" > scrapfile +print "@.Braces don't balance in comment@>" > scrapfile +print " @<Clear |bal| and |return|@>;" > scrapfile +print " }" > scrapfile +print "}" > scrapfile +print "}" > scrapfile + + +# We have to give \.{TANGLE} the beginning and ending comment strings, so +it can use thing in writing its own comments. +#<Write out...#>= + print "@ Important tokens:" > ttokfile + printf "@d begin_comment_string = %s\n", begin_comment_string > ttokfile + printf "@d end_comment_string = %s\n", end_comment_string > ttokfile + +# We also have to write out the starting and ending comment strings to +the macro file. +We do this at the time of parsing |#=/^comment /#>|, so the user has a +chance to override. +#<Write the comment definitions to the macro file#>= +if (macrofile!="") { + this_string=substr(begin_comment_string,2,length(begin_comment_string)-2) + #<Write |this_string| into |tex_string|, escaping \TeX's specials#> + printf "\\def\\commentbegin{%s}\n", tex_string > macrofile + if (comments_end_with_newline==0) { + this_string=substr(end_comment_string,2,length(end_comment_string)-2) + #<Write |this_string| into |tex_string|, escaping \TeX's specials#> + printf "\\def\\commentend{%s}\n", tex_string > macrofile + } else { + print "\\def\\commentend{\\relax}" > macrofile + } +} else { + print "Error: I can't write comment info to the macro file---" + print " you haven't given me any \"language\" information" + #<Punt...#> + } + + + +# Escaping \TeX's specials is pretty easy: +#<Set initial...#>= +texof["\\"]="\\BS" +texof["{"]="\\{" +texof["}"]="\\{" +texof["$"]="\\$" +texof["&"]="\\amp" +texof["##"]="\\##" +texof["^"]="\\H" +texof["_"]="\\_" +texof["~"]="\\TI" +texof["%"]="\\%" + +# +#<Write |this_string| into |tex_string|, escaping \TeX's specials#>= +tex_string="" +while (length(this_string)>0) { + c = substr(this_string,1,1) + this_string = substr(this_string,2) + cprime = texof[c] + if (cprime=="") { + tex_string = tex_string c + } else { + tex_string = tex_string cprime + } +} + +#*1Controlling line numbering. +Here we fart around with line numbering for \.{TANGLE}. +This lets \.{TANGLE} write an indication of the locations of things in +the \.{WEB} source. +The C preprocessor accepts these things as \.{\##line} directives. +#<Pattern-act...#>= +#=/^line /#> { + print $0 > logfile + for (i=2; i<NF;) { + if ($i=="begin") { + i++ + if ($i ~ #=/^<.*>$/#>) { + transstring = $i + wherestring = "in \"line begin\" on line " NR-1 + #<Convert restricted translation in |transstring| + to quoted string in |outstring|#> + sharp_line_open = outstring + i++ + } else { + print "Error: \"line begin\" must have a restricted translation" + #<Punt...#> + } + } else if ($i=="end") { + i++ + if ($i ~ #=/^<.*>$/#>){ + transstring = $i + wherestring = "in \"line end\" on line " NR-1 + #<Convert restricted translation in + |transstring| + to quoted string in |outstring|#> + sharp_line_close = outstring + } else { + print "Error: \"line end\" must have a restricted translation" + #<Punt...#> + } + i++ + } else { + print "Error: bad line attribute:", $i, "on line", NR-1 + #<Punt...#> + } + } ## |for| + #<Check that we used everything#> + next +} + +# We have to give \.{TANGLE} the strings for \&{\##line} commands. +#<Write out...#>= + print "@ Important tokens:" > ttokfile + printf "@d sharp_line_open = %s\n", sharp_line_open > ttokfile + printf "@d sharp_line_close = %s\n", sharp_line_close > ttokfile + +# We'll choose some innocuous defaults +#<Set init...#>= +sharp_line_open = "\"##line\"" +sharp_line_close = "\"\"" + +#*1Tracking the generation date. +We want to be able to note the date on which we generate files. +#<Patt...#>= +#=/^date /#> { + ## date returned as ``Fri Dec 11 11:31:18 EST 1987'' + mo = month[$3] + day = $4 + year = $7 + time = $5 + #<Set |hour|, |minute|, and |ampm| from |time|#> + date = sprintf ("(generated at %d:%s %s on %s %d, %d)",\ + hour, minute, ampm, mo, day, year) + next +} + +# We want the months to have their full names +#<Set init...#>= +month["Jan"]="January" +month["Feb"]="February" +month["Mar"]="March" +month["Apr"]="April" +month["May"]="May" +month["Jun"]="June" +month["Jul"]="July" +month["Aug"]="August" +month["Sep"]="September" +month["Oct"]="October" +month["Nov"]="November" +month["Dec"]="December" + +# We make a ``friendly'' time from |time=="hh:mm:ss"|. +#<Set |hour|, |minute|, and |ampm| from |time|#>= + hour = substr(time,1,2) + if (hour >=12) + ampm = "PM" + else + ampm="AM" + + if (hour==0) { + hour =12 + } else if (hour>12) { + hour = hour -12 + } + minute = substr(time,4,2) + + +#*=The {\tt SPIDER} tools. +#i cycle.web +#*Flagging duplicate names. +Detects duplicate names in a sorted list. +#(nodups.awk#>= +{ if ($0==last) { + print "Error: duplicate name", $0, "on lines", NR-1"-"NR + exit -1 + } + last = $0 +} +#*Checking translation keywords for validity. +#(transcheck.awk#>= +#=/^good translations$/#>,#=/^test translations$/#> { + if ($0 !~ #=/^good translations$|^test translations$/#>) { + istranslation[$0]=1 + } + next + } + +{ if (istranslation[$0]!=1) { + print "Error:", $0, "is not a valid translation" + exitcode = -1 + } +} + +END { + exit exitcode + } +# This is a copy of {\tt transcheck.list}, which should be the first +part of the input to {\tt transcheck.awk}. +Since \.{TANGLE} will insert its own stuff, we can't use it. +{\tt transcheck.awk} {\em could} be updated to work with the +tangled output, though, if it seemed desirable. +#(junk.list#>= +good translations +break_space +force +big_force +opt +backup +big_cancel +cancel +indent +outdent +math_rel +math_bin +math_op +test translations + +#*=Index. +This is a combined index to {\tt SPIDER} and the {\tt SPIDER} tools. +Since the {\tt SPIDER} tools are nearly trivial, it's really just +{\tt SPIDER}. + + diff --git a/web/spiderweb/src/master/tangle.web b/web/spiderweb/src/master/tangle.web new file mode 100644 index 0000000000..26266034ca --- /dev/null +++ b/web/spiderweb/src/master/tangle.web @@ -0,0 +1,1800 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +% This file is part of Spidery WEB + +% This program by Norman Ramsey is based on programs Silvio Levy +% and D. E. Knuth. Silvio Levy wrote most of the code. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Dec 1987 + +% Here is TeX material that gets inserted after \input webmac + +\message{OK, entering \string\batchmode...} +\batchmode + +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps +\def\cee{C} +\def\pb{$\.|\ldots\.|$} % C brackets (|...|) +\def\v{\char'174} % vertical (|) in typewriter font +\def\ceeref{{\it The C Reference Manual}} +\mathchardef\RA="3221 % right arrow +\mathchardef\BA="3224 % double arrow + +\def\title{Spidery TANGLE} +\def\contentspagenumber{1} % should be odd +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont Spidery TANGLE} processor} + \vfill +} + +@* Introduction. +\.{TANGLE} has a fairly straightforward outline. It operates in +two phases: first it reads the source file, saving the \cee\ code in +compressed form; then outputs the code, after shuffling it around. +It can be compiled +with certain optional flags, |DEBUG| and |STAT|, the latter being used +to keep track of how much of \.{TANGLE}'s resources were actually used. + +@u +@<Include files@>@; +@<Common code for \.{WEAVE} and \.{TANGLE}@>@; +@<Typedef declarations@>@; +@<Global variables@>@; + +main (ac, av) +char **av; +{ + argc=ac; argv=av; + program=tangle; + @<Set initial values@>; + common_init(); + 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 */ + wrap_up(); +} + +@ The following parameters were sufficient in the original \.{TANGLE} to +handle \TeX, so they should be sufficient for most applications of \.{TANGLE}. + +If you change |max_bytes|, |max_names| or |hash_size| you should also +change them in the file |"common.web"|. + +@d max_bytes = 90000 /* the number of bytes in identifiers, + index entries, and module names; used in |"common.web"| */ +@d max_toks = 150000 /* number of bytes in compressed \cee\ code */ +@d max_names = 4000 /* number of identifiers, strings, module names; + must be less than 10240; used in |"common.web"| */ +@d max_texts = 2000 /* number of replacement texts, must be less than 10240 */ +@d hash_size = 353 /* should be prime; used in |"common.web"| */ +@d longest_name = 400 /* module names shouldn't be longer than this */ +@d stack_size = 50 /* number of simultaneous levels of macro expansion */ +@d buf_size = 100 /* for \.{WEAVE} and \.{TANGLE} */ + +@i common.h + +@ Should include tlang.web but can't because AWK runs out of files. + +@* Data structures exclusive to {\tt TANGLE}. +We've already seen that the |byte_mem| array holds the names of identifiers, +strings, and modules; +the |tok_mem| array holds the replacement texts +for modules. 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 |char unsigned| you should change +the definition of \&{eight\_bits} to |short unsigned|. +@^system dependencies@> + +@<Typed...@>= +typedef struct { + eight_bits *tok_start; /* pointer into |tok_mem| */ + sixteen_bits text_link; /* relates replacement texts */ +} text; +typedef text *text_pointer; + +@ @<Glob...@>= +text text_info[max_texts]; +text_pointer text_info_end=text_info+max_texts-1; +text_pointer text_ptr; /* first unused position in |text_info| */ +eight_bits tok_mem[max_toks]; +eight_bits *tok_mem_end=tok_mem+max_toks-1; +eight_bits *tok_ptr; /* first unused position in |tok_mem| */ + +@ @<Set init...@>= +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 module 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 */ + +@ @<Set init...@>= +name_dir->equiv=(ASCII *)text_info; /* the undefined module 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|: + +@u +names_match(p,first,l) +name_pointer p; /* points to the proposed match */ +ASCII *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); +} + +@ +@u +init_node(node) +name_pointer node; +{ + node->equiv=(ASCII *)text_info; + +} +init_p(p,t) +name_pointer p; +eight_bits t; +{ + p->ilk=t; +} + + + +@*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 module. In the latter case |p->text_link| is either equal to +|module_flag|, which means that there is no further text for this module, or +|p->text_link| points to a continuation of this replacement text; such +links are created when several modules have \cee\ texts with the same +name, and they also tie together all the \cee\ texts of unnamed modules. +The replacement text pointer for the first unnamed module appears in +|text_info->text_link|, and the most recent such pointer is |last_unnamed|. + +@d module_flag = max_texts /* final |text_link| in module replacement texts */ + +@<Glob...@>= +text_pointer last_unnamed; /* most recent replacement text of unnamed module */ + +@ @<Set init...@>= last_unnamed=text_info; text_info->text_link=0; + +@ If the first byte of a token is less than |@'200|, the token occupies a +single byte. Otherwise we make a sixteen-bit token by combining two consecutive +bytes |a| and |b|. If |@'200<=a<@'250|, then |(a-@'200)@t${}\times2^8$@>+b| +to an identifier; if |@'250<=a<@'320|, then +|(a-@'250)@t${}\times2^8$@>+b| points to a module name; otherwise, i.e., if +|@'320<=a<@'400|, then |(a-@'320)@t${}\times2^8$@>+b| is the number of the module +in which the current replacement text appears. + +Codes less than @'200 are 7-bit ASCII codes that represent themselves. +In particular, a single-character identifier like `|x|' will be a one-byte +token, while all longer identifiers will occupy two bytes. + +Some of the 7-bit ASCII 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 \.{WEB}). + +\hang |string| denotes the beginning or end of a string, verbatim +construction or numerical constant. +@^ASCII code@> + +@d string = @'2 +@d param = @'7 +@d join = @'177 /* ASCII delete will not appear */ + +@ The following procedure is used to enter a two-byte value into +|tok_mem| when a replacement text is being generated. + +@u 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&@'377; /* 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 modules 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 |mod_field| is the module 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_mod|. + +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|. + +@<Typed...@>= +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 mod_field; /* module number or zero if not a module */ +} 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_mod = cur_state.mod_field /* current module number being expanded */ + +@<Global...@>= +output_state cur_state; /* |cur_end|, |cur_byte|, |cur_name|, |cur_repl| + and |cur_mod| */ +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 module that generates +code; if there are no such modules, there is nothing to output, and an +error message will have been generated before we do any of the initialization. + +@<Initialize the output stacks@>= +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_mod=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 C compiler can copy structures. +@^system dependencies@> + +@u push_level(p) /* suspends the current level */ +name_pointer p; +{ + @<Trace the name of what's pushed (|#ifdef TRACE_MACROS|)@>; + if (stack_ptr==stack_end) overflow("stack"); + *stack_ptr=cur_state; + stack_ptr++; + cur_name=p; cur_repl=(text_pointer)p->equiv; + cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start; + cur_mod=0; +} + +@ @<Trace the name of what's pushed (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS + if (tracing>0) { + printf("\nPushing "); print_id(p); + printf(" =nd[%d]",p-name_dir); + } +#endif TRACE_MACROS + +@ 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. +If this level is the end of a macro definition, it pops all the parameters +off the stack. + +@u pop_level() /* do this when |cur_byte| reaches |cur_end| */ +{ int number_of_parameters; +@<Trace the name of what's popped (|#ifdef TRACE_MACROS|)@>; + if (cur_repl->text_link==0) { /* macro definition */ + if (cur_name->ilk==macro) { + @<Pop the parameters from the parameter stack@>; + } + } else if (cur_repl->text_link<module_flag) { /* link to a continuation */ + cur_repl=cur_repl->text_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; +} + + +@ @<Pop the parameters...@>= +number_of_parameters=*(cur_repl->tok_start); +@<Trace number of parms popped (|#ifdef TRACE_MACROS|)@>; +while (number_of_parameters-->0) { + name_ptr--; text_ptr--; +#ifdef TRACE_MACROS +byte_ptr-=2; +#endif TRACE_MACROS + } +#ifdef STAT +#ifdef STAT_HAS_BEEN_FIXED + if (tok_ptr>max_tok_ptr) max_tok_ptr = tok_ptr; + /* maximum value of |tok_ptr| occurs just before + parameter popping */ +#endif STAT_HAS_BEEN_FIXED +#endif STAT +tok_ptr = text_ptr->tok_start; + + +@ @<Trace number of parms popped (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>1) { + printf("\nUnstacking %d parameters",number_of_parameters); + } +#endif TRACE_MACROS +@ @<Trace the name of what's popped (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS + if (tracing>0) { + printf("\nPopping "); print_id(cur_name); + printf(" =nd[%d]",cur_name-name_dir); + } + +#endif TRACE_MACROS + + + +@*1 Expanding macros. + The heart of the output procedure is the |get_output| routine, which produces +the next token of output that is not a reference to a macro. This procedure +handles all the stacking and unstacking that is necessary. + +@ Before we can get on to |get_output|, +we have to talk about expanding macros. +Macro parameters must be stacked. +They are placed in |tok_mem| just +above the other replacement texts, and dummy parameter ``names'' are +placed in |byte_start| just after the other names. +The variables |text_ptr| and |tok_ptr| essentially serve +as parameter stack pointers during the output phase, so there is +no need for a separate data structure to handle this problem. + + +@ Here are our invariants (assuming $\#$ represents |param|): +(1) in a replacement text, $\#n$ always refers to |*(name_ptr-n)|. +(2) when a parameter is scanned, any $\#n$ are replaced with references +to the appropriate name, so that the replacement text for a parameter +never contains a $\#n$. +(3) |name_ptr| is not changed until all the parameters are scanned; +otherwise invariant (1) wouldn't work during parameter scanning. +(4) when all parameters are scanned, |name_ptr| is moved +so that $\#n$ in the replacement text will be interpreted correctly. +(5) When we have finished scanning the replacement text for a macro, we +have to pop |name_ptr| to maintain the invariant in (1). + +@ |get_output| returns the value |module_number| +if the next output begins or ends the replacement text of some module, +in which case |cur_val| is that module's number (if beginning) or the +negative of that value (if ending). (A module number of 0 indicates +not the beginning or ending of a module, but a \&{\#line} command.) +And it returns the value |identifier| +if the next output is an identifier of length two or more, in which case +|cur_val| points to that identifier name. + +@d module_number = @'201 /* code returned by |get_output| for module numbers */ +@d identifier = @'202 +@<Global...@>= +int cur_val; /* additional information corresponding to output token */ + + +@ If |get_output| finds that no more output remains, it returns the value zero. +@u sixteen_bits +get_output() /* returns next token after macro expansion */ +{ + sixteen_bits a; /* value of current byte */ + restart: if (stack_ptr==stack) return 0; + if (cur_byte==cur_end) { + cur_val=-((int)cur_mod); /* cast needed because of sign extension */ + pop_level(); + if (cur_val==0) goto restart; + out_char(module_number); return; + } + a=*cur_byte++; + if (a<@'200) + if(a==param) { + @<Trace parameter number (|#ifdef TRACE_MACROS|)@>; + @<Get the parameter number, set up to substitute + that parameter, and go to |restart|@>; + } else + out_char(a); /* one-byte token */ + else { + a=(a-@'200)*@'400+*cur_byte++; + switch (a/@'24000) { /* |@'24000=(@'250-@'200)*@'400| */ + case 0: + @<If |a| is a macro, set it up and go to |restart|@>; + cur_val=a; out_char(identifier); break; + case 1: @<Expand module |a-@'24000|, |goto restart|@>; + default: cur_val=a-@'50000; if (cur_val>0) cur_mod=cur_val; + out_char(module_number); + } + } + return 1; +} + + +@ @<Get the parameter number...@>= +push_level(name_ptr-*cur_byte++); goto restart; +@ @<Trace parameter number...@>= +#ifdef TRACE_MACROS +if (tracing>2) { + printf (" [#%d]",*cur_byte); + } +#endif TRACE_MACROS + +@ @<If |a| is a macro...@>= +if (name_dir[a].ilk==macro) { + @<Trace macro expansion (|#ifdef TRACE_MACROS|)@>; + @<Scan the parameters (if any) and stack them, + or go to |restart| if an error occurs@>; + push_level(name_dir+a); + cur_byte++; /* skip number of parameters */ + goto restart; +} else if (name_dir[a].ilk==simple) { + @<Trace parameter expansion (|#ifdef TRACE_MACROS|)@>; + push_level(name_dir+a); + goto restart; +} + +@ @<Trace macro expansion (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>2) { + printf("\nExpanding macro ("); print_id(name_dir+a); + printf("=nd[%d])",a); + } +#endif TRACE_MACROS + +@ @<Trace parameter expansion (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>2) { + printf("\nExpanding parameter ("); print_id(name_dir+a); + printf("=nd[%d])",a); + } +#endif TRACE_MACROS + + +@ @<Scan the parameters...@>= +{int number_of_parameters; + while (cur_byte==cur_end && stack_ptr>stack) pop_level(); + number_of_parameters = *(((text_pointer)name_dir[a].equiv)->tok_start); + if (number_of_parameters>0) { + if (stack_ptr==stack || *cur_byte!=@`(') { + printf("\n! No parameters given for "); + print_id(a+name_dir); + err_print(""); + goto restart; + } + cur_byte++; /* skip left parenthesis */ + parm_ptr = name_ptr; /* maintain |name_ptr| invariant */ + while (number_of_parameters-->0) { + @<Stack a parameter ending in + comma or parenthesis@>; + } + name_ptr=parm_ptr; /* we are about to |push_level|, + so this maintains the |name_ptr| invariant */ + } +} + +@ In scanning parameter lists, we require that parameters be separated +by commas, and that parentheses balance in parameters. +The balancing is done with the array |balances|, and {\tt SPIDER} +could easily be extended to make certain tokens {\tt balance left} and +other tokens {\tt balance right}, so that {\tt left} and {\tt right} +tokens balance in parameters. +@ @<Global variables@>= +short balances[@'200]; +@ @<Set initial values@>= +{ int i; +for (i=0;i<@'200;i++) balances[i]=0; +@<Set special |balances|@>; +} +@ Eventually we will want {\tt SPIDER} to set balances. +For now let's try just tossing in parenthesis, braces, and square brackets. +@<Set special |balances|@>= +balances[@`(']=1; +balances[@`)']=-1; +balances[@`[']=1; +balances[@`]']=-1; +balances[@`{']=1; +balances[@`}']=-1; + +@ @<Stack a parameter...@>= +{ int bal; /* used to balance parentheses in parameter lists */ + eight_bits b, oldb; + sixteen_bits c; +bal=0; +@<Trace scanning for stack (|#ifdef TRACE_MACROS|)@>; +while (1) { + b=*cur_byte++; + if (b==param) { /* convert to name reference */ + b=*cur_byte++; + @<Trace parameter scansion (|#ifdef TRACE_MACROS|)@>; + c=name_ptr-name_dir-b; /* |name_ptr-b| points to parm */ + app_repl(@'200 + (c/@'400)); + app_repl(c % @'400); + } else { + if (b>=@'200) { + @<Trace scansion of token in |b| (|#ifdef TRACE_MACROS|)@>; + app_repl(b); + b=*cur_byte++; + } else if (bal==0 && ((number_of_parameters==0 && b==@`)') + || (number_of_parameters>0 && b==@`,'))) { + goto done; + } else if (@<|b| opens verbatim or string@>) { + @<Copy verbatim or string token list beginning with |b|@>; + } else { + @<Trace scansion of ordinary token in |b|@>; + bal += balances[b]; + } + app_repl(b); + } +} +done: +parm_ptr->equiv=(ASCII *)text_ptr; +text_ptr->text_link=0; /* label a macro */ +parm_ptr->ilk=simple; /* treat parm \# like simple macro */ +#ifdef TRACE_MACROS +if(byte_ptr+2>=byte_mem_end) overflow("byte memory"); +*byte_ptr++=@`#'; *byte_ptr++=number_of_parameters+1+@`0'; +#endif TRACE_MACROS +if (parm_ptr>=name_dir_end) overflow ("name"); +(++parm_ptr)->byte_start=byte_ptr; + if (text_ptr>=text_info_end) overflow("text"); + (++text_ptr)->tok_start=tok_ptr; +@<Trace stacking the parameter (|#ifdef TRACE_MACROS|)@>; +} + +@ @<Global variables@>= +name_pointer parm_ptr; /* used while stacking parameters */ + +@ @<|b| opens verbatim or string@>=(b==string||b==constant) +@ @<Copy verbatim or string...@>= +app_repl(b); +oldb=b; +@<Write |" <"| (|#ifdef TRACE_MACROS|)@>; +while((b=*cur_byte++)!=oldb) { +@<Trace scansion of character |b| (|#ifdef TRACE_MACROS|)@>; + app_repl(b); + if (cur_byte>=cur_end) + confusion("string or constant didn't end in token list"); +} +@<Write |">"| (|#ifdef TRACE_MACROS|)@>; + + + +@ @<Write |" <"| (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if(tracing>2) printf(" <"); +#endif TRACE_MACROS +@ @<Trace scansion of character |b| (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>2) printf("%c",b); +#endif TRACE_MACROS +@ @<Write |">"| (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if(tracing>2) printf(">"); +#endif TRACE_MACROS +@ @<Trace parameter scansion (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>2) { + printf (" <#%d=",b); print_id(name_ptr-b); printf("=nd[%d]>", + name_ptr-b-name_dir); + } +#endif TRACE_MACROS + +@ @<Trace scansion of token in |b| (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>2) { + int c; + printf (" <"); + c=(b-@'200)*@'400+*cur_byte; + switch (c/@'24000) { + case 0: print_id(name_dir+c); + printf(" =nd[%d]",c); + break; + case 1: printf("MODULE"); break; + default: printf("CONTEXT"); break; + } + printf(">"); +} +#endif TRACE_MACROS + +@ @<Trace scansion of ordinary token in |b|@>= +#ifdef TRACE_MACROS +if (tracing>2) { + printf (" <"); + if (@'37<b && b<@'177) printf("%c",b); + printf(">"); +} +#endif TRACE_MACROS + +@ @<Trace scanning for stack (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>2) { + printf ("\nScanning #%d...", number_of_parameters+1); + } +#endif TRACE_MACROS +@ @<Trace stacking the parameter (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>1) { + printf ("\nStacked "); print_id(parm_ptr-1); + printf ("=nd[%d]", parm_ptr-1-name_dir); + } +#endif TRACE_MACROS + +@ The user may have forgotten to give any \cee\ text for a module name, +or the \cee\ text may have been associated with a different name by mistake. + +@<Expand module |a-...@>= + a-=@'24000; + if ((a+name_dir)->equiv!=(ASCII *)text_info) push_level(a+name_dir); + else if (a!=0) { + printf("\n! Not present: <"); print_id(a+name_dir); err_print(">"); +@.Not present: <section name>@> + } + goto restart; + +@* Producing the output. +The |get_output| routine above handles most of the complexity of output +generation, but there is one further consideration that has a nontrivial +effect on \.{TANGLE}'s algorithms. Namely, +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 a \.= +because the C 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 |misc| means none of the above. + +\yskip Furthermore, if the variable |protect| is positive, new-lines +are preceded by a `\.\\'.% note this for /*spider*/ + +@d misc = 0 /* ``normal'' state */ +@d num_or_id = 1 /* state associated with numbers and identifiers */ +@d unbreakable = 3 /* state associated with \.{@@\&} */ +@d verbatim = 4 /* state in the middle of a string */ + +@<Global...@>= +eight_bits out_state; /* current status of partial output */ +boolean protect; /* current status of partial output */ + +@ 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. + +@u flush_buffer() /* writes one line to output file */ +{ + C_putc('\n'); + if (cur_line % 100 == 0) { + printf("."); + if (cur_line % 500 == 0) printf("%d",cur_line); + update_terminal; /* progress report */ + } + cur_line++; +} + +@* The big output switch. Here then is the routine that does the +output. +We have made some modifications to \.{TANGLE} so it will write output +on multiple files. +We do this very simply: if a module name is introduced by \.{@@(} +instead of \.{@@<}, we treat it as the name of a file. +All these special modules are saved on a stack, |output_files|. +We write them out after we've done the unnamed module. + +@d max_files = 256 +@<Glob...@>= +name_pointer output_files[max_files]; +name_pointer *cur_out_file, *end_output_files, *an_output_file; +char cur_module_char; /* is it |'<'| or |'('| */ +char output_file_name[longest_name]; /* name of the file */ + +@ We make |end_output_files| point jsut beyond the end of +|output_files|. +|cur_out_file| starts out there. Every time we see a new file, we +decrement |cur_out_file| and then write it in. +@<Set initial...@>= +cur_out_file=end_output_files=output_files+max_files; + +@ @<If it's not there, add |cur_module| to the output file stack, or +complain we're out of room@>= +{ +if (cur_out_file>output_files) { + for (an_output_file=cur_out_file; + an_output_file<end_output_files; an_output_file++) + if (*an_output_file==cur_module) break; + if (an_output_file==end_output_files) + *--cur_out_file=cur_module; +} else { + overflow("output files"); +} +} + +@ Here is the output switch, then... + +@u +phase_two () { + cur_line=1; + if (text_info->text_link==0) { + if(end_output_files==cur_out_file) { + printf("\n! No program text was specified."); mark_harmless; +@.No output was specified@> + } + } else { + printf("\nWriting the output files: (%s)",C_file_name); update_terminal; + @<Initialize the output stacks@>; + while (stack_ptr>stack) get_output(); + flush_buffer(); + } + if (end_output_files>cur_out_file) { + if(text_info->text_link==0) { + printf("\nWriting the output files: "); update_terminal; + } + @<Write all the named output files@>@; + } + printf("\nDone."); +} + +@ To write the named output files, we proceed as for the unnamed +module. +The only subtlety is that we have to open each one. +@<Write all the named output files@>= +for (an_output_file=end_output_files; an_output_file>cur_out_file;) { + an_output_file--; + strncpy(output_file_name,(*an_output_file)->byte_start, longest_name); + output_file_name[length(*an_output_file)]='\0'; + fclose(C_file); + C_file=fopen(output_file_name,"w"); + if (C_file == NULL) { + fatal("! Cannot open output file:",output_file_name)@; + } else { + printf(" (%s)",output_file_name); update_terminal; + } + stack_ptr=stack+1; + cur_name= (*an_output_file); + cur_repl= (text_pointer) cur_name->equiv_or_xref; + cur_byte=cur_repl->tok_start; + cur_end=(cur_repl+1)->tok_start; + cur_mod=0; + while (stack_ptr > stack) get_output(); + flush_buffer(); +} + + + +@ A many-way switch is used to send the output: + +@u out_char(cur_char) +eight_bits cur_char; +{ + ASCII *j; /* pointer into |byte_mem| */ + @<Trace |cur_char| (|#ifdef TRACE_MACROS|)@>; + switch (cur_char) { + case @`\n': if (protect) C_putc(' '); /*spider*/ + if (protect || out_state==verbatim) C_putc('\\'); /*spider*/ + /*spider*/ /*may need to escape newlines*/ + flush_buffer(); if (out_state!=verbatim) out_state=misc; break; + @/@t\4@>@<Case of an identifier@>; + @/@t\4@>@<Case of a module number@>; + @<Cases for tokens to be output@>@; + 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=misc; + else out_state=verbatim; break; + default: C_putc(cur_char); if (out_state!=verbatim) out_state=misc; + break; + } +} + +@ @<Trace |cur_char| (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>2) { + switch(cur_char) { + case @`\n': printf(" [\\n]"); break; + case string: + printf( "[STRING]"); break; + case join: + printf( "[JOIN]"); break; + case constant: + printf( "[CONSTANT]"); break; + case identifier: + printf (" ["); print_id(cur_val+name_dir); printf("]"); + break; + case module_number: + if (cur_val>0) { + printf(" [%d:]", cur_val); + } else if(cur_val<0) { + printf(" [:%d]", - cur_val); + } else { + printf( "[LINE NUMBER]"); + } + break; + + default: + if (@'37<cur_char && cur_char < @'177) { + printf (" [%c]", cur_char); + } else { + printf(" [\\%3o]",cur_char); + } + } +} +#endif TRACE_MACROS + + + + +@ @<Case of an identifier@>= +case identifier: + if (out_state==num_or_id) C_putc(' '); + for (j=(cur_val+name_dir)->byte_start; j<(name_dir+cur_val+1)->byte_start; + j++) C_putc(*j); + out_state=num_or_id; break; + +@ @<Case of a mod...@>= +case module_number: + if (cur_val>0) { + C_printf("%s",begin_comment_string); + C_printf("%d:",cur_val); + C_printf("%s",end_comment_string); + } else if(cur_val<0) { + C_printf("%s",begin_comment_string); + C_printf(":%d",-cur_val); + C_printf("%s",end_comment_string); + } else { + sixteen_bits a; + a=@'400* *cur_byte++; + a+=*cur_byte++; /* gets the line number */ + C_printf("\n%s",sharp_line_open); + C_printf(" %d \"",a); + cur_val=*cur_byte++; + cur_val=@'400*(cur_val-@'200)+ *cur_byte++; /* points to the file name */ + for (j=(cur_val+name_dir)->byte_start; j<(name_dir+cur_val+1)->byte_start; + j++) C_putc(*j); + C_printf("\"%s\n",sharp_line_close); + } + break; + +@i outtoks.web +@* Introduction to the input phase. +We have now seen that \.{TANGLE} will be able to output the full +\cee\ program, if we can only get that program into the byte memory in +the proper format. The input process is something like the output process +in reverse, since we compress the text as we read it in and we expand it +as we write it out. + +There are three main input routines. The most interesting is the one that gets +the next token of a \cee\ text; the other two are used to scan rapidly past +\TeX\ text in the \.{WEB} source code. One of the latter routines will jump to +the next token that starts with `\.{@@}', and the other skips to the end +of a \cee\ comment. + +@ Control codes in \.{WEB} begin with `\.{@@}', and the next character +identifies the code. Some of these are of interest only to \.{WEAVE}, +so \.{TANGLE} ignores them; the others are converted by \.{TANGLE} into +internal code numbers by the |control_code| table below. The ordering +of these internal code numbers has been chosen to simplify the program logic; +larger numbers are given to the control codes that denote more significant +milestones. + +@d ignore = 0 /* control code of no interest to \.{TANGLE} */ +@d octal = @'5 +@d hex = @'6 +@d trace = @'370 +@d ascii_constant = @'371 /* control code for `\.{@@`}' */ +@d control_text = @'372 /* control code for `\.{@@t}', `\.{@@\^}', etc. */ +@d format = @'373 /* control code for `\.{@@f}' */ +@d definition = @'374 /* control code for `\.{@@d}' */ +@d begin_unnamed = @'375 /* control code for `\.{@@u}' */ +@d module_name = @'376 /* control code for `\.{@@<}' */ +@d new_module = @'377 /* control code for `\.{@@\ }' and `\.{@@*}' */ + +@<Global...@>= +eight_bits ccode[128]; /* meaning of a char following \.{@@} */ + +@ @<Set ini...@>= { + int c; /* must be |int| so the |for| loop will end */ + for (c=0; c<=127; c++) ccode[c]=ignore; + ccode[' ']=ccode[tab_mark]=ccode['*']=new_module; + ccode ['@@'] = '@@'; + ccode['=']=string; + ccode['d']=ccode['D']=definition; + ccode['f']=ccode['F']=format; + ccode['c']=ccode['C']=begin_unnamed; + ccode['u']=ccode['U']=begin_unnamed; + ccode['^']=ccode[':']=ccode['.']=ccode['t']=ccode['T']=control_text; + ccode['&']=join; + ccode['<']=ccode['(']=module_name; + ccode['`']=ascii_constant; + ccode['\'']=octal; + ccode['"']=hex; +/*Now adjust for |at_sign|... if it is @@, we have no-op followed by quoting */ +/* ... but if it is other, say \#, then \#@@ replaces @@\#, and \#\# + quotes itself*/ +ccode['@@']=ccode[at_sign]; +ccode[at_sign]=at_sign; + +#ifdef DEBUG +ccode['0']=ccode['1']=ccode['2']=ccode['3']=ccode['4']=trace; +#endif DEBUG + +} + +@ We may want some sort of tracing facility: +@<Global variables@>=short tracing; +@ @<Set initial...@>=tracing=0; + +@ The |skip_ahead| procedure reads through the input at fairly high speed +until finding the next non-ignorable control code, which it returns. + +@u 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_module); + *(limit+1)=at_sign; + while (*loc!=at_sign) loc++; + if (loc<=limit) { + loc++; c=ccode[*loc]; +#ifdef DEBUG + if (c==trace) { + tracing=*loc-@`0'; c=ignore; + } +#endif DEBUG + loc++; + if (c!=ignore || *(loc-1)=='>') return(c); + } + } +} + +@ The |skip_comment| procedure reads through the input at somewhat high +speed until finding the end-comment token \.{*/} or a new-line, in which +case |skip_comment| will be called again by |get_next|, since the +comment is not finished. This is done so that the each newline in the +C part of a module is copied to the output; otherwise the \&{\#line} +commands inserted into the C file by the output routines become useless. +If it comes to the end of the module it prints an error message. + +@<Global...@>= +boolean comment_continues=0; /* are we scanning a comment? */ + +@ @u +skip_comment() /* skips over comments */ +{ + ASCII c; /* current character */ + if (comments_end_with_newline) { + get_line(); + return (comment_continues=0); + } else { + while (1) {/*spider*/ /* fix this to recognize end ok */ + if (loc>limit) + if(get_line()) return(comment_continues=1); + else{ + err_print("! Input ended in mid-comment"); +@.Input ended in mid-comment@> + return(comment_continues=0); + } + c=*(loc++); + @<Recognize comment end starting at |loc-1|@>@; + if (c==at_sign) { + if (ccode[*loc]==new_module) { + 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 = @'3 +@<Global...@>= +name_pointer cur_module; /* name of module just scanned */ + +@ @<Include...@>= +#include "ctype.h" /* definition of |isalpha|, |isdigit| and so on */ + +@ As one might expect, |get_next| consists mostly of a big switch +that branches to the various special cases that can arise. + +@u eight_bits get_next() /* produces the next input token */ +{ + eight_bits c; /* the current character */ + while (1) { + if (loc>limit) { + if (get_line()==0) return(new_module); + else if (print_where) { + print_where=0; + @<Insert the line number into |tok_mem|@>; + } + else return (@`\n'); + } + c=*loc; + if (comment_continues) { + skip_comment(); /* scan to end of comment or newline */ + if (comment_continues || comments_end_with_newline) return(@`\n'); + else continue; + } + @<See a comment starting at |loc| and skip it@>@; + loc++; + if (isdigit(c) || c=='\\' || c=='.') @<Get a constant@>@;/*spider*/ + else if (isalpha(c) || c=='_' || c=='$') @<Get an identifier@>@;/*spider*/ + else if (c=='\'' || c=='\"') @<Get a string@>@;/*spider*/ + else if (c==at_sign) @<Get control code and possible module name@>@; + else if (c==' ' || c==tab_mark) { + continue; /* ignore spaces and tabs */ + } + mistake: @<Compress two-symbol operator@>@; + return(c); + } +} + +@ @<Get an identifier@>= {/*spider*/ + id_first=--loc; + while (isalpha(*++loc) || isdigit(*loc) || *loc=='_'); + if (*loc=='$') while (isdigit(*++loc)||*loc=='$'); + /* make room for \$\$ and \$nnn suffixes */ + id_loc=loc; return(identifier); +} + +@ @<Get a constant@>= {/*spider*/ + id_first=loc-1; + if (*id_first=='.' && !isdigit(*loc)) goto mistake; /* not a constant */ + if (*id_first=='\\') while (isdigit(*loc)) loc++; /* octal constant */ + else { + if (*id_first=='0') { + if (*loc=='x' || *loc=='X') { /* hex constant */ + loc++; while (isxdigit(*loc)) loc++; goto found; + } + } + while (isdigit(*loc)) loc++; + if (*loc=='.') { + loc++; + while (isdigit(*loc)) loc++; + } + if (*loc=='e' || *loc=='E') { /* float constant */ + if (*++loc=='+' || *loc=='-') loc++; + while (isdigit(*loc)) loc++; + } + } + found: + 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|. + +@<Get a string@>= {/*spider*/ + ASCII delim = c; /* what started the string */ +@# +/* if it's not a single-character literal, it's a tick mark or an |at_sign| */ + if (delim=='\'' && (loc+1>=limit || + (*loc != '\\' && *loc!=at_sign && loc[1]!='\'') || + (*loc=='\\' && (loc+2>=limit||loc[2]!='\'')) || + (*loc==at_sign && + (loc+2>=limit||loc[1]!=at_sign||loc[2]!='\'')) + )) goto mistake; + id_first = mod_text+1; + id_loc = mod_text; *++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<=mod_text_end) *id_loc=@`\n'; /* will print as + \.{"\\\\\\n"} */ + } + if ((c=*loc++)==delim) { + if (++id_loc<=mod_text_end) *id_loc=c; + break; + } + if (c=='\\') { + if (loc>=limit) continue; + if (++id_loc<=mod_text_end) *id_loc = '\\'; + c=*loc++; + } + if (++id_loc<=mod_text_end) *id_loc=c; + } + if (id_loc>=mod_text_end) { + printf("\n! String too long: "); +@.String too long@> + ASCII_write(mod_text+1,25); + printf("..."); mark_error; + } + id_loc++; + return(string); +} + +@ After an \.{@@} sign has been scanned, the next character tells us +whether there is more work to do. + +@<Get control code and possible module name@>= { + c=ccode[*loc++]; + switch(c) { + case ignore: continue; + case control_text: while ((c=skip_ahead())==at_sign); + /* only \.{@@@@} and \.{@@>} are expected */ + if (*(loc-1)!='>') err_print("! Improper @@ within control text"); +@.Improper {\AT!} within control text@> + continue; + case module_name: + cur_module_char=*(loc-1); + @<Scan the module name and make |cur_module| point to it@>; + case string: @<Scan a verbatim string@>; +#ifdef DEBUG + case trace: tracing=*(loc-1)-'0'; continue; +#endif DEBUG + case ascii_constant: @<Scan an ASCII constant@>; + case octal: @<Scan an octal constant@>; + case hex: @<Scan a hex constant@>; + default: return(c); + } +} + +@ @<Scan an ASCII...@>=/*spider*/ + id_first=loc; + if (*loc=='\\') loc++; + while (*loc!='\'') { + loc++; + if (loc>limit) { + err_print("! String didn't end"); loc=limit-1; break; + } + } + loc++; + return(ascii_constant); + +@ @<Scan an octal constant@>= { + id_first=loc; + while ('0'<=*loc && *loc<'8') loc++; + id_loc=loc; + return(octal); +} + +@ @<Scan a hex constant@>= { + id_first=loc; + while (isxdigit(*loc)) loc++; + id_loc=loc; + return(hex); +} + + +@ @<Scan the module name...@>= { + ASCII *k; /* pointer into |mod_text| */ + @<Put module name into |mod_text|@>; + if (k-mod_text>3 && strncmp(k-2,"...",3)==0) cur_module=prefix_lookup(mod_text+1,k-3); + else cur_module=mod_lookup(mod_text+1,k); + if (cur_module_char=='(') { + @<If it's not there, add |cur_module| to the output file stack, or + complain we're out of room@>@; + } + return(module_name); +} + +@ Module names are placed into the |mod_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 |mod_text[0]=' '| to facilitate +this, since the |mod_lookup| routine uses |mod_text[1]| as the first +character of the name.) + +@<Set init...@>=mod_text[0]=' '; + +@ @<Put module name...@>= +k=mod_text; +while (1) { + if (loc>limit && get_line()==0) { + err_print("! Input ended in section name"); +@.Input ended in section name@> + loc=buffer+1; break; + } + c=*loc; + @<If end of name, |break|@>; + loc++; if (k<mod_text_end) k++; + if (c==' ' || c==tab_mark) { + c=' '; if (*(k-1)==' ') k--; + } +*k=c; +} +if (k>=mod_text_end) { + printf("\n! Section name too long: "); +@.Section name too long@> + ASCII_write(mod_text+1,25); + printf("..."); mark_harmless; +} +if (*k==' ' && k>mod_text) k--; + +@ @<If end of name,...@>= +if (c==at_sign) { + c=*(loc+1); + if (c=='>') { + loc+=2; break; + } + if (ccode[c]==new_module) { + err_print("! Section name didn't end"); break; +@.Section name didn't end@> + } + *(++k)=at_sign; 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. + +@<Scan a verbatim string@>= { + id_first=loc++; *(limit+1)=at_sign; *(limit+2)='>'; + while (*loc!=at_sign || *(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 module are almost identical; the only differences are that + +\yskip \item{a)}Module names are not allowed in macros; +in fact, the appearance of a module name terminates such macros and denotes +the name of the current module. + +\item{b)}The symbols \.{@@d} and \.{@@f} and \.{@@u} are not allowed after +module names, while they terminate macro definitions. + +\yskip Therefore there is a single procedure |scan_repl| whose parameter +|t| specifies either |macro| or |module_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 app_repl(c) = {if (tok_ptr==tok_mem_end) overflow("token"); *tok_ptr++=c;} + +@<Global...@>= +text_pointer cur_text; /* replacement text formed by |scan_repl| */ +eight_bits next_control; + +@ @u scan_repl(t) /* creates a replacement text */ +eight_bits t; +{ + sixteen_bits a; /* the current token */ + int set_print_where; + if (t==module_name) {@<Insert the line number into |tok_mem|@>;} + /* avoid inserting line number in macro replacement texts */ + /* |print_where| is both tested and set in |get_next| */ + while (1) { + if (t==macro) { + print_where = 0; + } + a=get_next(); + if (t==macro) { + set_print_where = print_where; + } + switch (a) { + @<In cases that |a| is a non-ASCII token (|identifier|, + |module_name|, etc.), either process it and change |a| to a byte + that should be stored, or |continue| if |a| should be ignored, + or |goto done| if |a| signals the end of this replacement text@>@; + default: app_repl(a); /* store |a| in |tok_mem| */ + } + } + done: next_control=(eight_bits) a; + if (text_ptr>text_info_end) overflow("text"); + if (t==macro) { + @<Strip trailing newlines from the replacement text@>; + } + cur_text=text_ptr; (++text_ptr)->tok_start=tok_ptr; + print_where = set_print_where; +} + +@ We don't ever want a macro replacement text to end with newline, +but for readability of the {\tt WEB} source +we usually want the last token in a macro definition +to be a newline token. +We can't just look for |@`\n'| at the end of the token list, because +that might be the second half of a two-byte token, in which case it +certainly {\em wouldn't} be a newline! +So we look for a two-byte token (|*tok_ptr>=@'200|); as soon as we find one +we've eliminated all trailing newlines. +As long as we keep finding one-byte tokens, we drop trailing newlines +as they come along. +@<Strip trailing newlines...@>= +tok_ptr -= 2; +while (*tok_ptr<@'200 && *(tok_ptr+1)==@`\n') tok_ptr--; +tok_ptr += 2; + +@ We use macros with zero or more parameters, and we give the parameters names. +In order to scan a macro definition, we need to be able to substitute +special markers for the parameter names. +We {\em don't} put the parameter names in the hash table, because they're +strictly temporary. +Instead we keep them in temporary storage: +We allow macros to have up to 32 parameters using 256 text chars. + +@d max_param_name_texts = 256 +@d max_param_names = 32 +@<Global variables@>= +ASCII param_name_texts[max_param_name_texts]; +ASCII *param_name_texts_end = param_name_texts+max_param_name_texts; +ASCII * param_names[max_param_names]; /* pointers into |param_name_texts| */ +short next_param_name; /* first free spot in |param_names| */ +ASCII * next_param_name_text; /* first free spot in |param_name_texts| */ + +@ @<Initialize the parameter name area@>= +next_param_name=0; +next_param_name_text=param_name_texts; +param_names[next_param_name]=next_param_name_text; + +@ @<Set initial values@>=@<Initialize the parameter name area@>; + +@ @<Add identifier to parameter name list@>= +@<Check for parameter name overflow@>; +while (id_first<id_loc) + *next_param_name_text++=*id_first++; +param_names[++next_param_name]=next_param_name_text; + +@ @<Check for parameter name overflow@>= +if (next_param_name==max_param_names) + overflow ("parameter names"); +if (id_loc - id_first > + param_name_texts_end - next_param_name_text) + overflow ("parameter name texts"); + + +@ The function |parameter_number(first,loc)| returns |0| if the identifier +is not a parameter, and the number of the parameter if it is a parameter. +This is not the parameter number we'll store, because for storage we +want the {\em last} parameter to be {\tt \#1}, the penultimate to +be {\tt \#2}, and so on. +This means we have to know the number of parameters only when constructing +the replacement text, not when scanning the replacement text. +@u +int parameter_number(first, loc) + ASCII *first, *loc; +{ + ASCII *f, *p; + int n; + for (n=0;n<next_param_name;n++) { + if (loc-first==param_names[n+1]-param_names[n]) { + /* lengths match */ + for(f=first,p=param_names[n];f<loc;) + if (*f++!=*p++) goto nomatch; + return n+1; /* matched parameter */ + } + nomatch: continue; /* need |continue| to avoid syntax error! */ + } + return 0; /* never matched anything */ +} + + +@ While scanning the macro name and parameter list, we ignore newlines. +We initialize the parameter name area at the beginning, and again +after scanning each replacement text. +This makes sure we have an empty parameter name area when scanning the +replacement text for a module. + +@<Scan a macro definition@>= +@<Set |next_control| to the first non-newline token@>@; +@<Take the macro name in |next_control|, put it in the hash table. + and set |p| to its entry in |name_dir|@>; +@<Scan the parameter list (if any), + and set |next_control| to the non-newline + token following the parameter list@>; +if (next_control!= @`=') { + err_print("! You must put an = sign before the macro replacement text"); + @<Quit scanning the macro definition@>; +} +@<Trace macro name (|#ifdef TRACE_MACROS|)@>; +app_repl(next_param_name); /* store number of parameters in |tok_mem| */ +scan_repl(macro); +p->equiv=(ASCII *)cur_text; +@<Trace equivalent text (|#ifdef TRACE_MACROS|)@>; +@<Initialize the parameter name area@>; + +@ @<Trace macro name (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>1) { + printf("\nScanning definition of macro "); print_id(p); + } +#endif TRACE_MACROS + +@ @<Trace equivalent text (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if (tracing>2) { + printf("\nMacro "); print_id(p); + printf("'s replacement text is in text_info[%d]", cur_text-text_info); + } +#endif TRACE_MACROS + + +@ @<Scan the parameter list (if any), and set |next_control| to the + non-newline token + following the parameter list@>= +@<Set |next_control| to the first non-newline token@>@; +if (next_control==@`(') { + do { + @<Get a parameter name@>; + @<Set |next_control| to the first non-newline token@>@; + } while (next_control==@`,'); + if (next_control != @`)') { + err_print("! Macro parameter list must end with )"); + @<Quit scanning the macro definition@>; + } + next_control=get_next(); /* first token following parameter list */ +} + + +@ @<Take the macro name in |next_control|...@>= +if (next_control!=identifier) { + err_print("! Macro name must be an identifier"); +@.Macro name must be an identifier@> + @<Quit scanning the macro definition@>; +} else { + p = id_lookup(id_first,id_loc,macro); + if (p->ilk!=macro) { +#ifdef WARN_USE_BEFORE_DEF + printf("\n! Warning: macro name "); + print_id(p); + printf(" was used before it was defined"); + mark_harmless; +#endif WARN_USE_BEFORE_DEF + p->ilk=macro; + } else if (p+1!=name_ptr) { + err_print ("! Macro name is multiply defined: "); + } +} + +@ @<Get a parameter name@>= +@<Set |next_control| to the first non-newline token@>; +if (next_control!=identifier) { + err_print("! Macro parameter name not an identifier"); +@.Macro parameter name...@> + @<Quit scanning the macro definition@>; +} else { + if (parameter_number(id_first,id_loc)!=0) { + err_print("! Duplicate parameters in macro definition"); +@.Duplicate parameters...@> + @<Quit scanning the macro definition@>; + } else { + @<Add identifier to parameter name list@>; + } +} + + +@ @<Set |next_control| to the first non-newline token@>= +while ((next_control=get_next())==@`\n'); + +@ We modify this from the old tangle: + +@<In cases that |a| is a non-ASCII token (|identifier|, + |module_name|, etc.), either process it and change |a| to a byte + that should be stored, or |continue| if |a| should be ignored, + or |goto done| if |a| signals the end of this replacement text@>= +case identifier: + { short n; + if ((n=parameter_number(id_first,id_loc))!=0) { +#ifdef TRACE_MACROS +if(tracing>1) { + printf("\nIdentified "); ASCII_write(id_first,id_loc-id_first); + printf(" as parameter number %d (%d from back)",n,next_param_name-n+1); + } +#endif TRACE_MACROS + app_repl(param); + app_repl(next_param_name-n+1); /* reverses numbering */ + } else { /* not a parameter */ + a=id_lookup(id_first,id_loc,normal)-name_dir; + app_repl((a / @'400)+@'200); app_repl(a % @'400); + } + } + break; +case module_name: if (t!=module_name) goto done; + else { + @<Was an |at_sign| missed here?@>; + a=cur_module-name_dir; + app_repl((a / @'400)+@'250); + app_repl(a % @'400); + @<Insert the line number into |tok_mem|@>; break; + } +case constant: case string: + @<Copy a string or verbatim construction or numerical constant@>; +case ascii_constant: + @<Copy an ASCII constant@>; +case octal: + @<Copy an octal constant@>; break; +case hex: + @<Copy a hex constant@>; break; +case @`\n': +#ifdef NEWLINES_IN_MACROS + app_repl(a); +#else + if (t==macro) continue; + else app_repl(a); +#endif NEWLINES_IN_MACROS + break; +case definition: case format: case begin_unnamed: + if (t!=module_name) goto done; + else { + err_print("! @@d, @@f and @@u are ignored in C text"); continue; +@.{\AT!}d, {\AT!}f and {\AT!}u are ignored in C text@> + } +case new_module: goto done; + +@ Here is the code for the line number: first a |sixteen_bits| equal +to |@'150000|; then, if we're dealing with the change file, the line +number plus |@'100000|; or, if we're dealing with the web file, the +line number; or, if we're dealing with an include file, the number 0, +then the line number, followed by the number of characters in the file +name and the file name. + +@<Insert the line...@>= +store_two_bytes(@'150000); +if (changing) id_first=change_file_name; +else id_first=cur_file_name; +id_loc=id_first+strlen(id_first); +if (changing) store_two_bytes((sixteen_bits)change_line); +else store_two_bytes((sixteen_bits)cur_line); +{int a=id_lookup(id_first,id_loc,normal)-name_dir; app_repl((a / @'400)+@'200); + app_repl(a % @'400);} + +@ @<Was an |at_sign|...@>= { + ASCII *try_loc=loc; + while (*try_loc==' ' && try_loc<limit) try_loc++; + if (*try_loc=='+' && try_loc<limit) try_loc++; + while (*try_loc==' ' && try_loc<limit) try_loc++; + if (*try_loc=='=') err_print ("! Nested named modules. Missing @@?"); +@.Nested named modules@> +} + +@ @<Copy a string...@>= + app_repl(a); /* |string| or |constant| */ + while (id_first < id_loc) { /* simplify \.{@@@@} pairs */ + if (*id_first==at_sign) id_first++; + app_repl(*id_first++); + } + app_repl(a); break; + +@ @<Copy an ASCII constant@>= { + int c; + if (*id_first==at_sign) { + c=xchr[*id_first++]; + if (*id_first!=at_sign) err_print("! Double @@ within string"); + } + else if (*id_first=='\\') { + id_first++; + switch (*id_first) { + case 't':c=@`\t';break; + case 'n':c=@`\n';break; + case 'b':c=@`\b';break; + case '0':c=@`\0';break; + case '\\':c=@`\\';break; + default: err_print("! Unrecognized escape sequence"); + } + } + else c=xchr[*id_first]; + app_repl(constant); +/* we don't want octal; we want decimal */ + /* we know |c<=255| */ + app_decimal((long)c); + app_repl(constant); +} +break; + +@ Paranoia to work on any 32 bit integer machine... +@<Copy an octal constant@>= { +long sum=0; +while (id_first<id_loc) { + sum = 8*sum + *id_first++ - '0'; + if (sum > @"04000000) err_print("! Octal constant exceeds @@\"04000000"); + } +app_repl(constant); +app_decimal(sum); +app_repl(constant); +} + +@ @<Copy a hex constant@>= { +long sum=0; +while (id_first<id_loc) { + sum = 16*sum + + (isdigit(*id_first) + ? *id_first - '0' + : isupper(*id_first) + ? *id_first - 'A' + 10 + : *id_first - 'a' + 10 + ); + id_first++; + if (sum > @"04000000) err_print("! Hex constant exceeds @@\"04000000"); + } +app_repl(constant); +app_decimal(sum); +app_repl(constant); +} + +@ This function prints out a decimal constant using |app_repl|. +@u +app_decimal(c) + long c; /* on entry require |c>=0| */ +{long power; + if (c==0) {app_repl('0'); return;} + if (c<0) /* should never happen */ {app_repl('-'); c = - c;} + for (power=1; c>=power; power *=10); + /* now |power/10<=c<power| */ + for (power /=10; power>=1; power /=10) { + app_repl('0'+c/power); /* leading digit $>0$ */ + c%=power; + /* invariant: original c = this c + printed string*power */ + } + } + + + +@* Scanning a module. +The |scan_module| procedure starts when `\.{@@\ }' or `\.{@@*}' has been +sensed in the input, and it proceeds until the end of that module. It +uses |module_count| to keep track of the current module number; with luck, +\.{WEAVE} and \.{TANGLE} will both assign the same numbers to modules. + +@<Global...@>= +extern sixteen_bits module_count; /* the current module number */ + +@ The top level of |scan_module| is trivial. +@u scan_module() +{ + name_pointer p; /* module name for the current module */ + text_pointer q; /* text for the current module */ + sixteen_bits a; /* token for left-hand side of definition */ + module_count++; + if (*(loc-1)=='*') /* starred module */ + printf("*%d",module_count); fflush(stdout); + @<Scan the definition part of the current module@>; + @<Scan the \cee\ part of the current module@>; +} + +@ We define two kinds of ilks for identifiers: |normal| for ordinary +identifiers, and |macro| for macros. +@d normal = 0 +@d macro = 1 +@d simple = 2 +@<Scan the definition part...@>= +next_control=0; +while (1) { +done_scanning: + while (next_control<=format) + if ((next_control=skip_ahead())==module_name) { + /* scan the module name too */ + loc-=2; next_control=get_next(); + } + if (next_control!=definition) break; + @<Scan a macro definition@>; + cur_text->text_link=0; /* |text_link=0| characterizes a macro */ +} + +@ We initialize the parameter name area at the beginning, and we re-initialize +any time we have to punt a macro definition. +This makes sure we have an empty parameter name area when scanning the +replacement text for a module. +@<Quit scanning the macro definition@>= +@<Initialize the parameter name area@>; +p->ilk=normal; /* turn off macro replacement and hope for the best */ +goto done_scanning; + + +@ @<Scan the \cee...@>= +switch (next_control) { + case begin_unnamed: p=name_dir; break; + case module_name: p=cur_module; + @<Check that |=| follows this module name, otherwise |return|@>; + break; + default: return; +} +@<Insert the module number into |tok_mem|@>; +scan_repl(module_name); /* now |cur_text| points to the replacement text */ +@<Update the data structure so that the replacement text is accessible@>; + +@ @<Check that |=|...@>= +while ((next_control=get_next())=='+'); /* allow optional `\.{+=}" */ +if (next_control!='=') { + err_print("! C text flushed, = sign is missing"); +@.C text flushed...@> + while ((next_control=skip_ahead()) != new_module); + return; +} + +@ @<Insert the module number...@>= +store_two_bytes((sixteen_bits)(@'150000+module_count)); /* |@'150000==@'320*@'400| */ + +@ @<Update the data...@>= +if (p==name_dir||p==0) { /* unnamed module, or bad module name */ + (last_unnamed)->text_link=cur_text-text_info; last_unnamed=cur_text; +} +else if (p->equiv==(ASCII *)text_info) p->equiv=(ASCII *)cur_text; + /* first module of this name */ +else { + q=(text_pointer)p->equiv; + while (q->text_link<module_flag) q=q->text_link+text_info; /* find end of list */ + q->text_link=cur_text-text_info; +} +cur_text->text_link=module_flag; /* mark this replacement text as a nonmacro */ + +@ @u phase_one() { + phase=1; + module_count=0; + reset_input(); + while ((next_control=skip_ahead())!=new_module); + while (!input_has_ended) scan_module(); + check_complete(); + phase=2; +} + +@ @u print_stats() { + printf("\nMemory usage statistics:\n"); + printf("%d names (out of %d)\n",name_ptr-name_dir,max_names); + printf("%d replacement texts (out of %d)\n",text_ptr-text_info,max_texts); + printf("%d bytes (out of %d)\n",byte_ptr-byte_mem,max_bytes); + printf("%d tokens (out of %d)\n",tok_ptr-tok_mem,max_toks); +} + +@* Index. +Here is a cross-reference table for the \.{TANGLE} processor. +All modules 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 module names are not indexed. Underlined entries +correspond to where the identifier was declared. Error messages and +a few other things like ``ASCII code'' are indexed here too. diff --git a/web/spiderweb/src/master/transcheck.awk b/web/spiderweb/src/master/transcheck.awk new file mode 100644 index 0000000000..ec02b62ba3 --- /dev/null +++ b/web/spiderweb/src/master/transcheck.awk @@ -0,0 +1,23 @@ +##162: + +#line 2537 "/u/norman/pu/web/dist/src/master/spider.web" + +#line 2538 "/u/norman/pu/web/dist/src/master/spider.web" +/^good translations$/,/^test translations$/{ +if($0!~/^good translations$|^test translations$/){ +istranslation[$0]=1 +} +next +} + +{if(istranslation[$0]!=1){ +print"Error:",$0,"is not a valid translation" +exitcode=-1 +} +} + +END{ +exit exitcode +} +##:162 + diff --git a/web/spiderweb/src/master/transcheck.list b/web/spiderweb/src/master/transcheck.list new file mode 100644 index 0000000000..d0ed25c6cf --- /dev/null +++ b/web/spiderweb/src/master/transcheck.list @@ -0,0 +1,14 @@ +good translations +break_space +force +big_force +opt +backup +big_cancel +cancel +indent +outdent +math_rel +math_bin +math_op +test translations diff --git a/web/spiderweb/src/master/weave.web b/web/spiderweb/src/master/weave.web new file mode 100644 index 0000000000..81dfec3f78 --- /dev/null +++ b/web/spiderweb/src/master/weave.web @@ -0,0 +1,3250 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +% This file is part of Spidery WEB +% This program by Norman Ramsey is based on programs Silvio Levy +% and D. E. Knuth. Silvio Levy wrote most of the code. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Dec 1987 + +% Here is TeX material that gets inserted after \input webmac + +\message{Entering \string\batchmode...} +\batchmode + +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps +\def\cee{C} +\def\Pascal{Pascal} +\def\PASCAL{Ada} +\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 module names + +\def\title{Spidery WEAVE} +\def\contentspagenumber{1} % should be odd +\def\topofcontents{\null\vfill + \titlefalse % include headline on the contents page + \def\rheader{\hfil} + \centerline{\titlefont The {\ttitlefont Spidery WEAVE} processor} + \vfill} +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iftrue + +@* Introduction. +\.{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, and finally it sorts and outputs the index. It can be compiled +with certain optional flags, |DEBUG| and |STAT|, the latter being used +to keep track of how much of \.{WEAVE}'s resources were actually used. + +@u +@<Include files@>@; +@<Common code for \.{WEAVE} and \.{TANGLE}@>@; +@<Typedef declarations@>@; +@<Global variables@>@; + +main (ac, av) +char **av; +{ + argc=ac; argv=av; + program=weave; + common_init(); + @<Set initial values@>; + printf(banner); /* print a ``banner line'' */ + @<Store all the reserved words@>; + phase_one(); /* read all the user's text and store the cross-references */ + phase_two(); /* read all the text again and translate it to \TeX\ form */ + phase_three(); /* output the cross-reference index */ +#ifdef STAT + @<Print statistics about memory usage@>; +#endif STAT + wrap_up(); +} + +@ The following parameters were sufficient in the original \.{WEAVE} to +handle \TeX, so they should be sufficient for most applications of \.{CWEAVE}. + +@d max_bytes = 90000 /* the number of bytes in identifiers, + index entries, and module names */ +@d max_names = 4000 /* number of identifiers, strings, module names; + must be less than 10240 */ +@d max_modules = 2000 /* greater than the total number of modules */ +@d hash_size = 353 /* should be prime */ +@d buf_size = 100 /* maximum length of input line, plus one */ +@d longest_name = 400 /* module names and strings shouldn't be longer than this */ +@d long_buf_size = 500 /* |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 = 2000 /* number of phrases in \cee\ texts being parsed; + must be less than 10240 */ +@d max_scraps = 1000 /* number of tokens in \cee\ texts being parsed */ +@d stack_size = 400 /* number of simultaneous output levels */ + +@i common.h + +@ Should include wlang.web but can't because AWK runs out of files. + +@* Data structures exclusive to {\tt WEAVE}. +As explained in \.{common.web}, the field of a |name_info| structure +that contains the |rlink| of a module name is used for a completely +different purpose in the case of identifiers. If is then called the +|ilk| of the identifier, and it is used to +distinguish between various types of identifiers, as follows: + +@ Several types of identifiers are distinguished by their |ilk|: + +\yskip\hang |normal| identifiers are part of the \PASCAL\ program and +will appear in italic type. +\yskip\hang |roman| identifiers are index entries that appear after +\.{@@\^} in the \.{WEB} file. + +\yskip\hang |wildcard| identifiers are index entries that appear after +\.{@@:} in the \.{WEB} file. + +\yskip\hang |typewriter| identifiers are index entries that appear after +\.{@@.} in the \.{WEB} file. + +\yskip\hang |array_like|, |begin_like|, \dots, |var_like| +identifiers are \PASCAL\ reserved words whose |ilk| explains how they are +to be treated when \PASCAL\ code is being formatted. + +\yskip\hang Finally, if |c| is an ASCII code, an |ilk| equal to +|char_like+c| denotes a reserved word that will be converted to character +|c|. + +@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 reserved(a) = (a->ilk>typewriter) /* tells if a name is a reserved word */ +/* begin with 64 */ + +/* ilks are generated by spider into file grammar.web */ + +@ We keep track of the current module number in |module_count|, which +is the total number of modules that have started. Modules which have +been altered by a change file entry have their |changed_module| flag +turned on during the first phase. + +@<Global...@>= +boolean change_exists; /* has any module 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 module number where |p| is used, +or it is |def_flag| plus a module number where |p| is defined, +or it is |file_flag| plus a module number where the file |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 +module number. The next unused slot in |xmem| is |xref_ptr|. + +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} or \.{@@f} is scanned, and it is cleared to zero when +the next identifier or index entry cross-reference has been made. +Similarly, +the global variable |mod_xref_switch| is either |def_flag|, +|file_flag|, or zero, depending +on whether a module name is being defined, defined as a file, or used. + +@<Type...@>= +typedef struct xref_info { + sixteen_bits num; /* module number plus zero,|def_flag|, or |file_flag| */ + struct xref_info *xlink; /* pointer to the previous cross-reference */ +} xref_info; +typedef xref_info *xref_pointer; + +@ @<Global...@>= +xref_info xmem[max_refs]; /* contains cross-reference information */ +xref_pointer xmem_end = xmem+max_refs-1; +xref_pointer xref_ptr; /* the largest occupied position in |xmem| */ +sixteen_bits xref_switch,mod_xref_switch; /* either zero or |def_flag| */ + +@ @d def_flag = 10240 /* must be strictly larger than |max_modules| */ +@d file_flag = 2*def_flag +@d xref = equiv_or_xref + +@<Set init...@>= +name_dir->xref=(ASCII *)xmem; +xref_ptr=xmem; +xref_switch=0; +mod_xref_switch=0; +xmem->num=0; /* cross-references to undefined modules */ + +@ 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 identifers. +If one were careful, one could probably make more changes around module +100 to avoid a lot of identifier looking up. + +@d append_xref(c) = if (xref_ptr==xmem_end) stat_overflow("cross-reference"); + else (++xref_ptr)->num=c; + +@u 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 ((reserved(p) || length(p)==1) && xref_switch==0) return; + m=module_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=(ASCII *)xref_ptr; +} + +@ The cross-reference lists for module names are slightly different. Suppose +that a module name is defined in modules $m_1$, \dots, $m_k$ and used in +modules $n_1$, \dots, $n_l$. Then its list will contain $m_1+|def_flag|{}$, +$m_k+|def_flag|{}$, \dots, $m_2+|def_flag|{}$, $n_l$, \dots, $n_1$, in +this order. +If the module is a file module (\.{@@(}), read |file_flag| for +|def_flag|. +Since no module should ever have both |file_flag| and |def_flag|, we +check that. + After Phase II, however, the order will be +$m_1+|def_flag|{}$, \dots, $m_k+|def_flag|{}$, $n_1$, \dots, $n_l$. + +@u new_mod_xref(p) +name_pointer p; +{ + xref_pointer q,r; /* pointers to previous cross-references */ + q=(xref_pointer)p->xref; r=xmem; + if (q>xmem) { + if (mod_xref_switch==0) while (q->num>=def_flag) { + r=q; q=q->xlink; + } + else if (q->num>=def_flag) { + @<Make sure |mod_xref_switch| is consistent with |q->num|@> + r=q; q=q->xlink; + } + } + append_xref(module_count+mod_xref_switch); + xref_ptr->xlink=q; mod_xref_switch=0; + if (r==xmem) p->xref=(ASCII *)xref_ptr; + else r->xlink=xref_ptr; +} + +@ Consistency check +@<Make sure |mod_xref_switch| is consistent with |q->num|@>= +{ + if ((mod_xref_switch==def_flag && q->num >= file_flag) || + (mod_xref_switch==file_flag && q->num < file_flag)) { + printf("\n! You can't use <"); print_id(p); + printf("> both as a file and as a named module"); mark_harmless; +@.You can't use <section name> both as a file...@> + + } +} + + +@ A third large area of memory is used for sixteen-bit `tokens', which appear +in short lists similar to the strings of characters in |byte_mem|. Token lists +are used to contain the result of \cee\ code translated into \TeX\ form; +further details about them will be explained later. A |text_pointer| variable +is an index into |tok_start|. + +@<Typed...@>= +typedef sixteen_bits token; +typedef token *token_pointer; +typedef token_pointer *text_pointer; + +@ The first position of |tok_mem| +that is unoccupied by replacement text is called |tok_ptr|, and the first +unused location of |tok_start| is called |text_ptr|. +Thus, we usually have |*text_ptr=tok_ptr|. + +@<Global...@>= +token tok_mem[max_toks]; /* tokens */ +token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */ +token_pointer tok_start[max_texts]; /* directory into |tok_mem| */ +token_pointer tok_ptr; /* first unused position in |tok_mem| */ +text_pointer text_ptr; /* first unused position in |tok_start| */ +text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */ +#ifdef STAT +token_pointer max_tok_ptr; /* largest value of |tok_ptr| */ +text_pointer max_text_ptr; /* largest value of |text_ptr| */ +#endif STAT + +@ @<Set init...@>= +tok_ptr=tok_mem+1; text_ptr=tok_start+1; tok_start[0]=tok_mem+1; +tok_start[1]=tok_mem+1; /* |tok_start| is the empty token list, + and |*textptr==tok_mem+1==tok_ptr| */ +#ifdef STAT +max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1; +#endif STAT + +@ @u +names_match(p,first,l,t) +name_pointer p; /* points to the proposed match */ +ASCII *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 && reserved(p))) return 0; + return !strncmp(first,p->byte_start,l); +} + +init_p(p,t) +name_pointer p; +eight_bits t; +{ + p->ilk=t; p->xref=(ASCII*)xmem; +} + +init_node(p) +name_pointer p; +{ + p->xref=(ASCII*)xmem; +} + +@ We have to get Ada's +reserved words into the hash table, and the simplest way to do this is +to insert them every time \.{CWEAVE} is run. Since there are relatively +few reserved words, we use an ad hoc function to simplify the code. +@^reserved words@> +There's not enough room to include \.{reserved.web}, since AWK can't open +enough files. +We make do with \.{scraps.web}. + + + +@* Lexical scanning. +Let us now consider the subroutines that read the \.{WEB} source file +and break it into meaningful units. There are four such procedures: +One simply skips to the next `\.{@@\ }' or `\.{@@*}' that begins a +module; another passes over the \TeX\ text at the beginning of a +module; 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 \.{WEB}, 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_module| should be the largest of +all. Some of these numeric control codes take the place of ASCII +control codes that will not otherwise appear in the output of the +scanning routines. +@^ASCII code@> + +@d ignore = 0 /* control code of no interest to \.{CWEAVE} */ +@d verbatim = @'2 /* extended ASCII alpha will not appear */ + /* extended ASCII beta will not appear */ +@d begin_comment = @'10 /* ASCII tab mark will not appear */ +@d octal = @'14 /* ASCII carriage return will not appear */ +@d hex = @'15 /* ASCII form feed will not appear */ +@d switch_math_flag = @'175 /* this code will be intercepted without confusion */ +@d underline = @'176 /* this code will be intercepted without confusion */ +@d param = @'177 /* ASCII delete will not appear */ +/* identifier =200 or octal @'310 */ +@#/* following three must be conseccutive for indexing to work */ +@d xref_roman = (identifier+roman) /* control code for `\.{@@\^}' */ +@d xref_wildcard = (identifier+wildcard) /* control code for `\.{@@:}' */ +@d xref_typewriter = (identifier+typewriter) /* control code for `\.{@@.}' */ +@d TeX_string = @'356 /* control code for `\.{@@t}' */ +@d ascii_constant = @'357 /* control code for `\.{@@`}' */ +@d join = @'360 /* control code for `\.{@@\&}' */ +@d thin_space = @'361 /* control code for `\.{@@,}' */ +@d math_break = @'362 /* control code for `\.{@@\char'174}' */ +@d line_force = @'363 /* control code for `\.{@@/}' */ +@d line_break = @'364 /* control code for `\.{@@-}' */ +@d big_line_break = @'365 /* control code for `\.{@@\#}' */ +@d no_line_break = @'366 /* control code for `\.{@@+}' */ +@d pseudo_semi = @'367 /* control code for `\.{@@;}' */ +@d vertical_bar = @'370 /* The `\v' used to mark Ada text */ +@d trace = @'371 /* control code for `\.{@@0}', `\.{@@1}' and `\.{@@2}' */ +@d format = @'373 /* control code for `\.{@@f}' */ +@d definition = @'374 /* control code for `\.{@@d}' */ +@d begin_unnamed = @'375 /* control code for `\.{@@u}' */ +@d module_name = @'376 /* control code for `\.{@@<}' */ +@d new_module = @'377 /* control code for `\.{@@\ }' and `\.{@@*}' */ + +@ Control codes are converted from ASCII to \.{CWEAVE}'s internal +representation by means of the table |ccode|. + +@<Global...@>= +eight_bits ccode[128]; /* meaning of a char following \.{@@} */ + +@ @<Set ini...@>= +{int c; for (c=0; c<=127; c++) ccode[c]=0;} +ccode[' ']=ccode[tab_mark]=ccode['*']=new_module; +ccode['-']=line_break; +ccode['#']=big_line_break; +ccode['=']=verbatim; +ccode['d']=ccode['D']=definition; +ccode['f']=ccode['F']=format; +ccode['c']=ccode['C']=begin_unnamed; +ccode['u']=ccode['U']=begin_unnamed; +ccode['t']=ccode['T']=TeX_string; +ccode['&']=join; +ccode['<']=ccode['(']=module_name; +ccode['!']=underline; ccode['^']=xref_roman; +ccode['$']=switch_math_flag; +ccode[':']=xref_wildcard; +ccode['.']=xref_typewriter; +ccode[',']=thin_space; +ccode['|']=math_break; +ccode['/']=line_force; +ccode['+']=no_line_break; +ccode[';']=pseudo_semi; +ccode['`']=ascii_constant; +ccode['\'']=octal; +ccode['"']=hex; +@t\4@>@<Special control codes allowed only when debugging@>@; +@# +/*Now adjust for |at_sign|... if it is @@, we have no-op followed by quoting */ +/* ... but if it is other, say \#, then \#@@ replaces @@\#, and \#\# + quotes itself*/ +ccode['@@']=ccode[at_sign]; +ccode[at_sign]=at_sign; + +@ If \.{CWEAVE} is compiled with debugging commands, one can write +\.{@@2}, \.{@@1}, and \.{@@0} to turn tracing fully on, partly on, +and off, respectively. + +@<Special control codes...@>= +#ifdef DEBUG +ccode['0']=ccode['1']=ccode['2']=trace; +#endif DEBUG + +@ The |skip_limbo| routine is used on the first pass to skip through +portions of the input that are not in any modules, i.e., that precede +the first module. After this procedure has been called, the value of +|input_has_ended| will tell whether or not a module has actually been found. + +@u skip_limbo() { + while(1) { + if (loc>limit && get_line()==0) return; + *(limit+1)=at_sign; + while (*loc!=at_sign) loc++; /* look for |at_sign|, then skip two chars */ + if (loc++ <=limit) if (ccode[*loc++]==new_module) return; + } +} + +@ The |skip_TeX| routine is used on the first pass to skip through +the \TeX\ code at the beginning of a module. It returns the next +control code or `\v' found in the input. A |new_module| is +assumed to exist at the very end of the file. + +@u unsigned skip_TeX() /* skip past pure \TeX\ code */ +{ + while (1) { + if (loc>limit && get_line()==0) return(new_module); + *(limit+1)=at_sign; + while (*loc!=at_sign && *loc!=vertical_char) loc++; + if (*loc++ ==vertical_char) return(vertical_bar); + if (loc<=limit) return(ccode[*(loc++)]); + } +} + +@* Inputting the next token. +As stated above, \.{WEAVE}'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 an ASCII 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 +|mod_text|; |id_first| and |id_loc| are set as above (now they are +pointers into |mod_text|). + +\yskip\hang |constant|: The constant is copied into |mod_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 |module_name|: In this case the global variable |cur_module| will +point to the |byte_start| entry for the module name that has just been scanned. + +\yskip\noindent If |get_next| sees `\.{@@!}' +it sets |xref_switch| to |def_flag| and goes on to the next token. + +\yskip\noindent If |get_next| sees `\.{@@\$}' +it sets |math_flag| to |!math_flag| and goes on to the next token. + + + +@<Global...@>= +name_pointer cur_module; /* name of module just scanned */ +int math_flag; + +@ @<Include...@>= +#include "ctype.h" + +@ As one might expect, |get_next| consists mostly of a big switch +that branches to the various special cases that can arise. + +Get next takes one argument that determines whether |vertical_char| is a +character or gets translated to a |vertical_bar|. +(Normally, |vertical_char=='|'|.) +If it does get translated, the following rules apply: + +\yskip\hang|'|'| as part of a string or as a noninitial character in a +multicharacter token is not a |vertical_bar|. + +\yskip\hang An initial |"||"| is treated like a single |'|'|, and +taken to be either a token itself or the initial |'|'| in a +multicharacter token. + +@d vertical_char = @`|' +@u eight_bits get_next(see_vertical) /* produces the next input token +*/ + char see_vertical; +{ + eight_bits c; /* the current character */ + while (1) { + if (loc>limit) { + if (get_line()==0) return(new_module); + else { return (@`\n'); } + } + c=*(loc++); + @<See a comment starting at |loc-1| and return |begin_comment|@>@; + if (see_vertical && c==vertical_char) { + if (*loc==vertical_char && loc < limit) { + loc++; + } else { + return vertical_bar; + } + } + if (isdigit(c)) @<Get a constant@>@; /*spider*/ + else if (isalpha(c) || c=='_') @<Get an identifier@>@;/*spider*/ + else if (c=='\'' || c=='"') @<Get a string@>@;/*spider*/ + else if (c==at_sign) @<Get control code and possible module name@>@; + else if (c==' ' || c==tab_mark) continue; /* ignore spaces and tabs */ + mistake: @<Compress two-symbol operator@>@; + return(c); + } +} + +@ @<Set |next_control| to the first non-newline token@>= +while ((next_control=get_next(0))==@`\n'); + +@ @<Get an identifier@>= {/*spider*/ + id_first=--loc; + while (isalpha(*++loc) || isdigit(*loc) || *loc=='_'); + id_loc=loc; return(identifier); +} + +@ Notice that in this section and the next, |id_first| and |id_loc| +are pointers into the array |mod_text|, not into |buffer|. + +@<Get a constant@>= { + id_first=id_loc=mod_text+1; + + if (*(loc-1)=='.' && !isdigit(*loc)) goto mistake; /* not a constant */ + *id_loc++=*(loc-1); + while (isdigit(*loc)) *id_loc++=*loc++; + if (*loc=='.') { + *id_loc++=*loc++; + while (isdigit(*loc)) *id_loc++=*loc++; + } +#ifdef C_FLOATING_POINT +/* no floating point --- it depends too much on C */ + if (*loc=='e' || *loc=='E') { /* float constant */ + *id_loc++='_'; loc++; + if (*loc=='+' || *loc=='-') *id_loc++=*loc++; + while (isdigit(*loc)) *id_loc++=*loc++; + } +#endif C_FLOATING_POINT + return(constant); +} + + + +@ Here we do octals, which I should say more about later... +@<Get an octal constant@>= { + id_first=id_loc=mod_text+1; + *id_loc++='~'; /* marks octal constant */ + while ('0'<=*loc && *loc<'8') *id_loc++=*loc++; + return(constant); +} +@ And hexes are even easier... +@<Get a hex constant@>= { + id_first=id_loc=mod_text+1; + *id_loc++='^'; /* marks hex constant */ + while (isxdigit(*loc)) { + *id_loc++=(islower(*loc)?toupper(*loc):*loc); + loc++; + } + return(constant); +} + +@ \cee\ strings and character constants, delimited by double and single +quotes, respectively, can contain newlines or instances of their own +delimiters if they are protected by a backslash. We follow this +convention, but do not allow the string to be longer than |longest_name|. + +@<Get a string@>= {/*spider*/ + ASCII delim = c; /* what started the string */ + id_first = mod_text+1; + id_loc = mod_text; + if (delim=='`' && *(loc-2)==at_sign) { + /* make string begin with |"@@`"| */ + *++id_loc=at_sign; + *++id_loc=at_sign; + } + /* this is hack for ascii constant */ +@# +/* if it's not a single-character literal, it's a tick mark or an |at_sign| */ + if ((delim=='\'' || delim == '`') && + (loc+1>=limit || + (*loc != '\\' && *loc!=at_sign && loc[1]!='\'') || + (*loc=='\\' && (loc+2>=limit||loc[2]!='\'')) || + (*loc==at_sign && + (loc+2>=limit||loc[1]!=at_sign||loc[2]!='\'')) + ) + ) goto mistake; + *++id_loc=delim; + if (delim=='`') delim='\''; /* for |ascii_constant|s */ + 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<=mod_text_end) *id_loc=c; + break; + } + if (c=='\\') if (loc>=limit) continue; + else if (++id_loc<=mod_text_end) { + *id_loc = '\\'; c=*loc++; + } + if (++id_loc<=mod_text_end) *id_loc=c; + } + if (id_loc>=mod_text_end) { + printf("\n! String too long: "); +@.String too long@> + ASCII_write(mod_text+1,25); + printf("..."); mark_error; + } + id_loc++; + return(string); +} + +@ After an \.{@@} sign has been scanned, the next character tells us +whether there is more work to do. + +@<Get control code and possible module name@>= { + c=*loc++; + switch(ccode[c]) { + case underline: xref_switch=def_flag; continue; + case switch_math_flag: math_flag=!math_flag; continue; +#ifdef DEBUG + case trace: tracing=c-'0'; continue; +#endif DEBUG + case xref_roman: case xref_wildcard: case xref_typewriter: + case TeX_string: + @<Scan to the next \.{@@>}@>@; + case module_name: + @<Scan the module name and make |cur_module| point to it@>@; + case verbatim: @<Scan a verbatim string@>@; + case ascii_constant: /* fake into looking like quoted char */ + @<Get a string@>; + case octal: @<Get an octal constant@>; + case hex: @<Get a hex constant@>; + default: return(ccode[c]); + } +} + +@ The occurrence of a module name sets |xref_switch| to zero, +because the module name might (for example) follow \&{int}. + +@<Scan the module name...@>= { + ASCII *k; /* pointer into |mod_text| */ + cur_module_char=c; /* remember |'<'| or |'('| */ + @<Put module name into |mod_text|@>; + if (k-mod_text>3 && strncmp(k-2,"...",3)==0) cur_module=prefix_lookup(mod_text+1,k-3); + else cur_module=mod_lookup(mod_text+1,k); + xref_switch=0; return(module_name); +} + +@ @<Global...@>=ASCII cur_module_char; + +@ Module names are placed into the |mod_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 |mod_text[0]=' '| to facilitate +this, since the |mod_lookup| routine uses |mod_text[1]| as the first +character of the name.) + +@<Set init...@>=mod_text[0]=' '; + +@ @<Put module name...@>= +k=mod_text; +while (1) { + if (loc>limit && get_line()==0) { + err_print("! Input ended in section name"); +@.Input ended in section name@> + loc=buffer+1; break; + } + c=*loc; + @<If end of name, |break|@>; + loc++; if (k<mod_text_end) k++; + if (c==' ' || c==tab_mark) { + c=' '; if (*(k-1)==' ') k--; + } +*k=c; +} +if (k>=mod_text_end) { + printf("\n! Section name too long: "); +@.Section name too long@> + ASCII_write(mod_text+1,25); + printf("..."); mark_harmless; +} +if (*k==' ' && k>mod_text) k--; + +@ @<If end of name,...@>= +if (c==at_sign) { + c=*(loc+1); + if (c=='>') { + loc+=2; break; + } + if (ccode[c]==new_module) { + err_print("! Section name didn't end"); break; +@.Section name didn't end@> + } + *(++k)=at_sign; loc++; /* now |c==*loc| again */ +} + +@ @<Scan to the next...@>= { + c=ccode[*(loc-1)]; id_first=loc; *(limit+1)=at_sign; + while (*loc!=at_sign) loc++; + id_loc=loc; + if (loc++>limit) { + err_print("! Control text didn't end"); loc=limit; return(c); +@.Control text didn't end@> + } + if (*loc++!='>') err_print("! Control codes are forbidden in control text"); +@.Control codes are forbidden...@> + return(c); +} + +@ At the present point in the program we +have |*(loc-1)=verbatim|; we set |id_first| to the beginning +of the string itself, and |id_loc| to its ending-plus-one location in the +buffer. We also set |loc| to the position just after the ending delimiter. + +@<Scan a verbatim string@>= { + id_first=loc++; *(limit+1)=at_sign; *(limit+2)='>'; + while (*loc!=at_sign || *(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 +\.{WEAVE}'s first pass over the source file. If everything works right, +both phase one and phase two of \.{WEAVE} will assign the same numbers to +modules, and these numbers will agree with what \.{TANGLE} 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 module or part of a module. + +@<Global...@>= +eight_bits next_control; /* control code waiting to be acting upon */ + +@ The overall processing strategy in phase one has the following +straightforward outline. + +@u phase_one() { +phase=1; reset_input(); module_count=0; +skip_limbo(); change_exists=0; +while (!input_has_ended) + @<Store cross-reference data for the current module@>; +changed_module[module_count]=change_exists; + /* the index changes if anything does */ +phase=2; /* prepare for second phase */ +@<Print error messages about unused or undefined module names@>; +} + +@ @<Store cross-reference data...@>= +{ + if (++module_count==max_modules) stat_overflow("section number"); + changed_module[module_count]=0; /* it will become 1 if any line changes */ + if (*(loc-1)=='*') { + printf("*%d",module_count); + update_terminal; /* print a progress report */ + } + @<Store cross-references in the \TeX\ part of a module@>; + @<Store cross-references in the definition part of a module@>; + @<Store cross-references in the \cee\ part of a module@>; + if (changed_module[module_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|). If +|next_control>=format| 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 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| and |normal=0|. + +@u C_xref(see_v) /* makes cross-references for \cee\ identifiers */ + char see_v; +{ + name_pointer p; /* a referenced name */ + while (next_control<format) { + if (next_control>=identifier && next_control<=xref_typewriter) { + p=id_lookup(id_first, id_loc,next_control-identifier); new_xref(p); + } + next_control=get_next(see_v); + if (next_control==vertical_bar || next_control==begin_comment) return; + } +} + +@ The |outer_xref| subroutine is like |C_xref| but it begins +with |next_control!=vertical_bar| and ends with |next_control>=format|. Thus, it +handles \cee\ text with embedded comments. + +@u outer_xref() /* extension of |C_xref| */ +{ + int bal; /* brace level in comment */ + while (next_control<format) + if (next_control!=begin_comment) C_xref(0); + else { + bal=copy_comment(1); next_control=vertical_bar; + while (bal>0) { + C_xref(1); + if (next_control==vertical_bar) bal=copy_comment(bal); + else bal=0; /* an error message will occur in phase two */ + } + } +} + +@ In the \TeX\ part of a module, cross-reference entries are made only for +the identifiers in \cee\ texts enclosed in \pb, or for control texts +enclosed in \.{@@\^}$\,\ldots\,$\.{@@>} or \.{@@.}$\,\ldots\,$\.{@@>} +or \.{@@:}$\,\ldots\,$\.{@@>}. + +@<Store cross-references in the \T...@>= +while (1) { + switch (next_control=skip_TeX()) { + case underline: xref_switch=def_flag; continue; +#ifdef DEBUG + case trace: tracing=next_control-'0'; continue; +#endif DEBUG + case vertical_bar: C_xref(1); break; + case xref_roman: case xref_wildcard: + case xref_typewriter: case module_name: + loc-=2; next_control=get_next(1); /* scan to \.{@@>} */ + if (next_control!=module_name) { +/* |printf ("\nweave debugging: new xref: ");| */ +/* |{char *p; for (p=id_first;p<id_loc;p++) putchar(*p);}| */ +/* |putchar('\n');| + */ + new_xref(id_lookup(id_first, id_loc,next_control-identifier)); + } + break; + } + if (next_control>=format) break; +} + +@ During the definition and \cee\ parts of a module, cross-references +are made for all identifiers except reserved words; however, the +identifiers in a format definition are referenced even if they are +reserved. The \TeX\ code in comments is, of course, ignored, except for +\cee\ portions enclosed in \pb; the text of a module name is skipped +entirely, even if it contains \pb\ constructions. + +The variables |lhs| and |rhs| point to the respective identifiers involved +in a format definition. + +@<Global...@>= +name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */ + +@ When we get to the following code we have |next_control>=format|. + +@<Store cross-references in the d...@>= +while (next_control<=definition) { /* |format| or |definition| */ + xref_switch=def_flag; /* implied \.{@@!} */ + if (next_control==definition) next_control=get_next(1); + else @<Process a format definition@>; + outer_xref(); +} + +@ Error messages for improper format definitions will be issued in phase +two. Our job in phase one is to define the |ilk| of a properly formatted +identifier, and to fool the |new_xref| routine into thinking that the +identifier on the right-hand side of the format definition is not a +reserved word. + +@<Process a form...@>= { + next_control=get_next(1); + if (next_control==identifier) { + lhs=id_lookup(id_first, id_loc,normal); lhs->ilk=normal; new_xref(lhs); + next_control=get_next(1); + if (next_control==identifier) { + rhs=id_lookup(id_first, id_loc,normal); + lhs->ilk=rhs->ilk; rhs->ilk=normal; new_xref(rhs); + rhs->ilk=lhs->ilk; next_control=get_next(1); + } + } +} + +@ Finally, when the \TeX\ and definition parts have been treated, we have +|next_control>=begin_unnamed|. + +@<Store cross-references in the \cee...@>= +if (next_control<=module_name) { /* |begin_unnamed| or |module_name| */ + if (next_control==begin_unnamed) mod_xref_switch=0; + else mod_xref_switch=(cur_module_char=='<' ? def_flag: file_flag); + do { + if (next_control==module_name && cur_module!=NULL) new_mod_xref(cur_module); + next_control=get_next(1); outer_xref(); + } while ( next_control<=module_name); +} + +@ After phase one has looked at everything, we want to check that each +module name was both defined and used. The variable |cur_xref| will point +to cross-references for the current module name of interest. + +@<Global...@>= +xref_pointer cur_xref; /* temporary cross-reference pointer */ + +@ The following recursive procedure +walks through the tree of module names and prints out anomalies. +@^recursion@> + +@u mod_check(p) name_pointer p; /* print anomalies in subtree |p| */ +{ + int level; /* 0: use 1: definition 2: file definition */ + if (p) { + mod_check(p->llink); + cur_xref=(xref_pointer)p->xref; + level=(cur_xref->num)/def_flag; + if (level==0) { + printf("\n! Never defined: <"); print_id(p); putchar('>'); mark_harmless; +@.Never defined: <section name>@> + } + while (cur_xref->num >=def_flag) { + if ((cur_xref->num)/def_flag != level) { + printf("\n! You can't use <"); print_id(p); + printf("> both as a file and as a named module"); mark_harmless; +@.You can't use <section name> both as a file...@> + } + cur_xref=cur_xref->xlink; + } + if (cur_xref==xmem && level<2) { + printf("\n! Never used: <"); print_id(p); putchar('>'); mark_harmless; +@.Never used: <section name>@> + } + else if (cur_xref!=xmem && level==2) { + printf("\n! You can't use file module ("); print_id(p); + putchar(')'); mark_harmless; +@.You can't use file module (file name)@> + } + mod_check(p->rlink); + } +} + +@ @<Print error messages about un...@>=mod_check(root) + +@* Low-level output routines. +The \TeX\ output is supposed to appear in lines at most |line_length| +characters long, so we place it into an output buffer. During the output +process, |out_line| will hold the current line number of the line about to +be output. + +@<Global...@>= +ASCII out_buf[line_length+1]; /* assembled characters */ +ASCII *out_ptr; /* just after last character in |out_buf| */ +ASCII *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. + +The same caveat that applies to |ASCII_write| applies to |c_line_write|. + +@d c_line_write(c) = fflush(tex_file),write(fileno(tex_file),out_buf+1,c)@; +@d tex_putxchar(c) = putc(xchr[c],tex_file)@; +@d tex_new_line = putc('\n',tex_file)@; +@d tex_printf(c) = fprintf(tex_file,c)@; + +@u flush_buffer(b,per_cent) +ASCII *b; +boolean per_cent; /* outputs from |out_buf+1| to |b|,where |b<=out_ptr| */ +{ + ASCII *j; j=b; /* pointer into |out_buffer| */ + if (! per_cent) /* remove trailing blanks */ + while (j>out_buf && *j==' ') j--; + c_line_write(j-out_buf); + if (per_cent) tex_putxchar('%'); + tex_new_line; out_line++; + if (b<out_ptr) strncpy(out_buf+1,b+1,out_ptr-b); + out_ptr-=b-out_buf; +} + +@ When we are copying \TeX\ source material, we retain line breaks +that occur in the input, except that an empty line is not +output when the \TeX\ source line was nonempty. For example, a line +of the \TeX\ file that contains only an index cross-reference entry +will not be copied. The |finish_line| routine is called just before +|get_line| inputs a new line, and just after a line break token has +been emitted during the output of translated \cee\ text. + +@u finish_line() /* do this at the end of a line */ +{ + ASCII *k; /* pointer into |buffer| */ + if (out_ptr>out_buf) flush_buffer(out_ptr,0); + else { + for (k=buffer; k<=limit; k++) + if (*k!=' ' && *k!=tab_mark) return; + flush_buffer(out_buf,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 a command +to read in the macro file. + +@<Set init...@>= +out_ptr=out_buf+1; out_line=1; +@<Set |out_ptr| and do a |tex_printf| to read the macros@> + +@ 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, +or |out_str_del(s,t)|, where |s| and |t| point to the same array of +characters; characters from |s| to |t-1|, inclusive, are output. + +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;} + +@u out_str_del(s,t) /* output characters from |s| to |t-1| */ +ASCII *s, *t; +{ + while (s<t) out(*s++); +} + +out_str(s) /* output characters from |s| to end of string */ +ASCII *s; +{ + while (*s) out(*s++); +} + +@ The |break_out| routine is called just before the output buffer is about +to overflow. To make this routine a little faster, we initialize position +0 of the output buffer to `\.\\'; this character isn't really output. + +@<Set init...@>= +out_buf[0]='\\'; + +@ A long line is broken at a blank space or just before a backslash that isn't +preceded by another backslash. In the latter case, a |'%'| is output at +the break. + +@u break_out() /* finds a way to break the output line */ +{ + ASCII *k=out_ptr; /* pointer into |out_buf| */ + while (1) { + if (k==out_buf) @<Print warning message, break the line, |return|@>; + if (*k==' ') { + flush_buffer(k,0); return; + } + if (*(k--)=='\\' && *k!='\\') { /* we've decreased |k| */ + flush_buffer(k,1); return; + } + } +} + +@ We get to this module only in unusual cases that the entire output line +consists of a string of backslashes followed by a string of nonblank +non-backslashes. In such cases it is almost always safe to break the +line by putting a |'%'| just before the last character. + +@<Print warning message...@>= +{ + printf("\n! Line had to be broken (output l. %d):\n",out_line); +@.Line had to be broken@> + ASCII_write(out_buf+1, out_ptr-out_buf-1); + new_line; mark_harmless; + flush_buffer(out_ptr-1,1); return; +} + +@ Here is a macro that outputs a module number in decimal notation. +The number to be converted by |out_mod| is known to be less than +|def_flag|, so it cannot have more than five decimal digits. If +the module is changed, we output `\.{\\*}' just after the number. + +@u out_mod(n) sixteen_bits n; +{ + ASCII s[6]; + sprintf(s,"%d",n); out_str(s); + if(changed_module[n]) out_str ("\\*"); +} + +@ The |out_name| procedure is used to output an identifier or index +entry, enclosing it in braces. + +@u out_name(p) name_pointer p; { + ASCII *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */ + out('{'); + for (k=p->byte_start; k<k_end; k++) { + if (*k=='$') {out('\\'); out('D'); out('O'); out(' ');} + else if (*k=='&') {out('\\'); out('a'); out('m'); out('p');} + else { + if (*k=='_' || *k=='%' || *k=='#' || *k=='^' || *k=='{' || *k=='}') + out('\\'); + out(*k); + } + } + out('}'); +} + +@* Routines that copy \TeX\ material. +During phase two, we use the 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. + +The |copy_limbo| routine, for example, takes \TeX\ material that is not +part of any module and transcribes it almost verbatim to the output file. +No `\.{@@}' signs should occur in such material except in `\.{@@@@}' +pairs; such pairs are replaced by singletons. + +@u copy_limbo() +{ + ASCII c; + while (1) { + if (loc>limit && (finish_line(), get_line()==0)) return; + *(limit+1)=at_sign; + while (*loc!=at_sign) out(*(loc++)); + if (loc++<=limit) { + c=*loc++; + if (ccode[c]==new_module) break; + if (c!='z' && c!='Z') { + out(at_sign); + if (c!=at_sign) err_print("! Double @@ required outside of sections"); +@.Double \AT! required...@> + } + } + } +} + + +@ The |copy_TeX| routine processes the \TeX\ code at the beginning of a +module; 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. + +@<Global...@>= eight_bits next_control; /* control code found */ + +@ @u eight_bits copy_TeX() +{ + ASCII c; /* current character being copied */ + while (1) { + if (loc>limit && (finish_line(), get_line()==0)) return(new_module); + *(limit+1)=at_sign; + while ((c=*(loc++))!=vertical_char && c!=at_sign) { + out(c); + if (out_ptr==out_buf+1 && (c==' ' || c==tab_mark)) out_ptr--; + } + if (c==vertical_char) return(vertical_bar); + if (loc<=limit) return(ccode[*(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. +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. + +Copies to end and then follows end of comment with a right brace. + +@d app_tok(c) = {if (tok_ptr+2>tok_mem_end) stat_overflow("token"); *(tok_ptr++)=c;} + +@u +copy_comment(bal) /* copies \TeX\ code in comments */ +int bal; /* brace balance */ +{ + ASCII c; /* current character being copied */ + while (1) { + if (loc>limit) + if (comments_end_with_newline) { + loc++; if(bal==1) {if (phase==2) app_tok('}'); return(0);} + else { + err_print("! Braces don't balance in comment"); +@.Braces don't balance in comment@> + @<Clear |bal| and |return|@>; + } + } else { + if (get_line()==0) { + err_print("! Input ended in mid-comment"); +@.Input ended in mid-comment@> + loc=buffer+1; @<Clear |bal| and |return|@>; + } + } + + c=*(loc++); + if (c==vertical_char) return(bal); + @<Check for end of comment@>; + if (phase==2) app_tok(c); + @<Copy special things when |c==at_sign, '\\', '{', '}'|; |return| at end@>; + } +} + + + +@ @<Copy special things when |c==at_sign...@>= +if (c==at_sign) { + if (*(loc++)!=at_sign) { + err_print("! Illegal use of @@ in comment"); +@.Illegal use of \AT!...@> + loc-=2; if (phase==2) tok_ptr--; @<Clear |bal|...@>; + } +} +else if (c=='\\' && *loc!=at_sign && phase==2) app_tok(*(loc++))@; +else if (c=='{') bal++; +else if (c=='}') bal--; + +@ When the comment has terminated abruptly due to an error, we output +enough right braces to keep \TeX\ happy. + +@<Clear |bal|...@>= +app_tok(' '); /* this is done in case the previous character was `\.\\' */ +while (bal-- >0) app_tok('}'); +/* |if (see_end_of_line) next_control=end_of_line;| */ +return(0); + +@* Parsing. +The most intricate part of \.{WEAVE} 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 \.{WEAVE} 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 find 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 is +$$open\ math\ semi\ \RA\ open\ math$$ +and it means that three consecutive scraps whose respective categories are +|open|, |math|, and |semi| are con\-verted to two scraps whose categories +are |open| and |math|. This production also has an associated rule that +tells how to combine the translation parts: +$$\eqalign{O_2&=O_1\cr +M_2&=M_1\,S\,\.{\\,}\,\hbox{|opt|\thinspace\tt5}\cr}$$ +This means that the |open| scrap has not changed, while the new |math| scrap +has a translation $M_2$ composed of the translation $M_1$ of the original +|math| scrap followed by the translation |S| of the |semi| scrap followed +by `\.{\\,}' followed by `|opt|' followed by `\.5'. (In the \TeX\ file, +this will specify an additional thin space after the semicolon, followed +by an optional line break with penalty 50.) Translation rules use subscripts +to distinguish between translations of scraps whose categories have the +same initial letter; these subscripts are assigned from left to right. + +$\.{WEAVE}$ also has the production rule +$$\hbox{|semi|$\;\RA\;$|terminator|}$$ +(meaning that a semicolon can terminate a \cee\ statement). Since +productions are applied from left to right, this rule will be activated +only if the |semi| is not preceded by scraps that match other productions; +in particular, a |semi| that is preceded by `|open| |math|' will have +disappeared because of the production above, and such semicolons do not +act as statement terminators. + +The translation rule corresponding to $\hbox{|semi|$\;\RA\;$|terminator|}$ is +$$T=S$$ +but we shall not mention translation rules in the common case that the +translation of the new scrap on the right-hand side is simply the +concatenation of the disappearing scraps on the left-hand side. + + + +@ The token lists for translated \TeX\ output contain some special control +symbols as well as ordinary characters. These control symbols are +interpreted by \.{WEAVE} 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 |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| or |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} corresponding respectively to +|indent|, |outdent|, |opt|, |backup|, |break_space|, |force|, and +|big_force|. 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 tokens |math_rel| and |math_bin| will be translated into +\.{\\mathrel\{} and \.{\\mathbin\{}, respectively. +Also |math_op| to \.{\\mathop\{}. +Other control sequences in the \TeX\ output will be `\.{\\\\\{}$\,\ldots\,$\.\}' +surrounding identifiers, `\.{\\\&\{}$\,\ldots\,$\.\}' surrounding +reserved words, `\.{\\.\{}$\,\ldots\,$\.\}' surrounding strings, +`\.{\\cee\{}$\,\ldots\,$\.\}$\,$|force|' surrounding comments, and +`\.{\\X$n$:}$\,\ldots\,$\.{\\X}' surrounding module names, where +|n| is the module number. + +@d math_bin = @'205 /* should these be octal or decimal? */ +@d math_rel = @'206 +@d math_op = @'207 +@d big_cancel = @'210 /* like |cancel|, also overrides spaces */ +@d cancel = @'211 /* overrides |backup|, |break_space|, |force|, |big_force| */ +@d indent = cancel+1 /* one more tab (\.{\\1}) */ +@d outdent = cancel+2 /* one less tab (\.{\\2}) */ +@d opt = cancel+3 /* optional break in mid-statement (\.{\\3}) */ +@d backup = cancel+4 /* stick out one unit to the left (\.{\\4}) */ +@d break_space = cancel+5 /* optional break between statements (\.{\\5}) */ +@d force = cancel+6 /* forced break between statements (\.{\\6}) */ +@d big_force = cancel+7 /* forced break with additional space (\.{\\7}) */ +@d end_translation = big_force+1 /* special sentinel token at end of list */ + +@ Here is a table of all the productions. The reader can best get a feel for +@^productions, table of@> +how they work by trying them out by hand on small examples; no amount of +explanation will be as effective as watching the rules in action. +Parsing can also be watched by debugging with `\.{@@2}'. + +@i grammar.web + +@* Implementing the productions. +More specifically, a scrap is a structure consisting of a category +|cat| and a |text_pointer| |trans|, which points to the translation in +|tok_start|. When \cee\ text is to be processed with the grammar above, +we form an array |scrap_info| containing the initial scraps. +Our production rules have the nice property that the right-hand side is never +longer than the left-hand side. Therefore it is convenient to use sequential +allocation for the current sequence of scraps. Five pointers are used to +manage the parsing: + +\yskip\hang |pp| is a pointer into |scrap_info|. We will try to match +the category codes |pp->cat@,(pp+1)->cat|$\,\ldots\,$ to the left-hand sides +of productions. + +\yskip\hang |scrap_base|, |lo_ptr|, |hi_ptr|, and |scrap_ptr| are such that +the current sequence of scraps appears in positions |scrap_base| through +|lo_ptr| and |hi_ptr| through |scrap_ptr|, inclusive, in the |cat| and +|trans| arrays. Scraps located between |scrap_base| and |lo_ptr| have +been examined, while those in positions |>=hi_ptr| have not yet been +looked at by the parsing process. + +\yskip\noindent Initially |scrap_ptr| is set to the position of the final +scrap to be parsed, and it doesn't change its value. The parsing process +makes sure that |lo_ptr>=pp+3|, since productions have as many as four terms, +by moving scraps from |hi_ptr| to |lo_ptr|. If there are +fewer than |pp+3| scraps left, the positions up to |pp+3| are filled with +blanks that will not match in any productions. Parsing stops when +|pp=lo_ptr+1| and |hi_ptr=scrap_ptr+1|. + +Since the |scrap| structure will later be used for other purposes, we +declare its second element as unions. + +@<Type...@>= +typedef struct { + eight_bits cat; + eight_bits mathness; + union { + text_pointer Trans; + ===> @<Rest of |trans_plus| union@>@; + } trans_plus; +} scrap; +typedef scrap *scrap_pointer; + +@ @d trans = trans_plus.Trans /* translation texts of scraps */ +@d no_math = 2 +@d yes_math = 1 +@d maybe_math = 0 +@d left_math(A) = ((A)->mathness %4) +@d right_math(A) = (((A)->mathness/4)%4) +@d make_math(LM,RM) = ((eight_bits) (LM+4*(RM))) + + +@<Global...@>= +scrap scrap_info[max_scraps]; /* memory array for scraps */ +scrap_pointer scrap_info_end=scrap_info+max_scraps -1; /* end of |scrap_info| */ +scrap_pointer pp; /* current position for reducing productions */ +scrap_pointer scrap_base; /* beginning of the current scrap sequence */ +scrap_pointer scrap_ptr; /* ending of the current scrap sequence */ +scrap_pointer lo_ptr; /* last scrap that has been examined */ +scrap_pointer hi_ptr; /* first scrap that has not been examined */ +#ifdef STAT +scrap_pointer max_scr_ptr; /* largest value assumed by |scrap_ptr| */ +#endif STAT + +@ @<Set init...@>= +scrap_base=scrap_info+1; +#ifdef STAT +max_scr_ptr= +#endif STAT +scrap_ptr=scrap_info; + +@ Token lists in |@!tok_mem| are composed of the following kinds of +items for \TeX\ output. + +\yskip\item{$\bullet$}ASCII 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$}|mod_flag+p| represents module 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 mod_flag = 3*id_flag /* signifies a module name */ +@d tok_flag = 4*id_flag /* signifies a token list */ +@d inner_tok_flag = 5*id_flag /* signifies a token list in `\pb' */ + +@u +#ifdef DEBUG +print_text(p) /* prints a token list */ +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("\\{"); print_id((name_dir+r)); printf("}"); break; + /* |id_flag| */ + case 2: printf("\\&{"); print_id((name_dir+r)); printf("}"); break; + /* |res_flag| */ + case 3: printf("<"); print_id((name_dir+r)); printf(">"); break; + /* |mod_flag| */ + case 4: printf("[[%d]]",r); break; /* |tok_flag| */ + case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */ + default: @<Print token |r| in symbolic form@>; + } + } +} +#endif DEBUG + +@ @<Print token |r|...@>= +switch (r) { + case math_bin: printf("\\mathbin{"); break; + case math_op: printf("\\mathop{"); break; + case math_rel: printf("\\mathrel{"); break; + case big_cancel: printf("[ccancel]"); break; + case cancel: printf("[cancel]"); break; + case indent: printf("[indent]"); break; + case outdent: printf("[outdent]"); break; + case backup: printf("[backup]"); break; + case opt: printf("[opt]"); break; + case break_space: printf("[break]"); break; + case force: printf("[force]"); break; + case big_force: printf("[fforce]"); break; + case end_translation: printf("[quit]"); break; + default: putxchar(r); +} + +@ The production rules listed above are embedded directly into the \.{WEAVE} +program, 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 translations 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 `|simp@,math| $\RA$ |math|' would be represented by +`|(pp,2,math,-1)|'; in this case the pointer |pp| should decrease by 1 +after the production has been applied, because some productions with +|math| in their second positions might now match, but no productions have +|math| in the third or 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. Consider the further example +`|var_head@,math@,colon| $\RA$ |var_head@,intro|', which is represented by +`|(pp+1,2,intro,+1)|'; the $+1$ here is deduced by looking at the +grammar and seeing that no matches could possibly occur at positions |<=pp| +after this production has been applied. 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 of each production, so that additional +information is available when debugging. For example, the program below +contains the statement `|reduce(pp+1,2,intro,+1,52)|' 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, |small_app2(pp)| will append the +translations of two consecutive scraps, |trans[pp]| and |trans[pp+1]|, to +the current token list. If the entire new translation is formed in this +way, we write `|squash(j,k,c,d)|' instead of `|reduce(j,k,c,d)|'. For +example, `|squash(pp,2,math,-1)|' is an abbreviation for `|small_app2(pp); +reduce(pp,2,math,-1)|'. + +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 app2(a) = app1(a);app1(a+1)@; +@d app3(a) = app2(a);app1(a+2)@; +@d app4(a) = app3(a);app1(a+3)@; +@d small_app(a) = *(tok_ptr++)=a@; +@d small_app1(a) = *(tok_ptr++)=tok_flag+(a)->trans-tok_start@; + +@<Global...@>= +int init_mathness, last_mathness; + +@ @u app_str(s) +ASCII *s; +{ + while (*s) small_app(*(s++)); +} + +app(a) +token a; +{ + if (a==' ' || a>=big_cancel && a<=big_force) /* non-math token */ { + if (last_mathness==maybe_math) init_mathness=no_math; + else if (last_mathness==yes_math) small_app('$'); + last_mathness=no_math; + } + else { + if (last_mathness==maybe_math) init_mathness=yes_math; + else if (last_mathness==no_math) small_app('$'); + last_mathness=last_mathness=yes_math; + } + small_app(a); +} +app1(a) +scrap_pointer a; +{ + switch (left_math(a)) { /* left boundary */ + case (no_math): + if (last_mathness==maybe_math) init_mathness=no_math; + if (last_mathness==yes_math) small_app('$'); + last_mathness = right_math(a); /* right boundary */ + break; + case (yes_math): + if (last_mathness==maybe_math) init_mathness=yes_math; + else if (last_mathness==no_math) small_app('$'); + last_mathness = right_math(a); /* right boundary */ + break; + case (maybe_math): /* no changes */ + break; + } + small_app(tok_flag+(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. + +@<Match a production at |pp|, or increase |pp| if there is no match@>= { + /* |ignore_scrap| becomes part of the grammar */ + @<Test for all of the productions@>@; + pp++; /* if no match was found, we move to the right */ +} + +@ It may be that during phase two we discover from some arrangement +of the scraps that an identifier should be treated as a defining instance, +meaning its index entry should be underlined. +Since we're in phase two, the identifier is buried inside some scrap, +which may contain other things as well. +Using Spider to {\em star} a scrap causes the first identifier in that +scrap's translation to get an underlined index entry. +The starring generates a call to |make_underlined|, which +finds the first identifier with |first_id| and then underlines it +with |underline_xref|. +@u +@<Definition of |first_id|@>@; +make_underlined(p) + /* underline the entry for the first identifier in |p->trans| */ +scrap_pointer p; +{ + sixteen_bits tok_value; /* a token: + the name of this identifier, plus its flag */ + /* Assume |p->trans < text_ptr| */ + + /* attempt to set |tok_value| to the first identifier in |p->trans| */ + tok_value = first_id(p->trans); + if (tok_value==0) { +#ifdef DEBUG + if (tracing>0) { + printf("\n! I couldn't find an identifier to underline."); + mark_harmless; + } +#endif DEBUG + return; + } + if (tok_value<id_flag || tok_value>=res_flag) + fatal("", "! Internal error in first_id"); +@.Internal error in first_id@> + /* don't underline identifiers of length 1, even if starred --- force + the user to use |"@@!"| */ + if (length(tok_value-id_flag+name_dir)>1) + underline_xref(tok_value-id_flag+name_dir); +} + +@ |first_id| finds the first identifier in a translation. +It is indefatigable. +It returns a |token| value, or zero if it can't find an identifier. +@<Definition of |first_id|@>= + +sixteen_bits first_id(p) + text_pointer p; +{ + token_pointer tp; /* used to search for the first identifier */ + sixteen_bits r; /* remainder after modding out by |id_flag| */ + sixteen_bits the_id; /* the id we find, or zero otherwise */ + + for (tp=*p; tp<*(p+1); tp++) { + r=*tp%id_flag; + switch (*tp/id_flag) { + case 1: /* |id_flag| --- found it */ + return *tp; + break; + case 2: /* |res_flag| */ + case 3: /* |mod_flag| */ + goto next; + break; + case 4: /* |tok_flag| */ + case 5: /* |inner_tok_flag| */ + /* search the inner list */ + if ((the_id = first_id(tok_start+r))!=0) return the_id; + goto next; + break; + default: + goto next; + break; + } + next: continue; + } + return 0; +} + +@ 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. + +@u 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; + xref_switch=def_flag; + m=module_count+xref_switch; + while (q != xmem) { + n=q->num; + if (n==m) return; + else if (m==n+def_flag) { + q->num=m; return; + } + else if (n>=def_flag && n<m) break; + q=q->xlink; + } + @<Insert new cross-reference at |q|, not at beginning of list@>; +} + +@ We get to this module 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 modules, so in order +to preserve the numerical order of the entries in the index, we have +to insert the new cross-reference not at the beginning of the list +(namely, at |p->xref|), but rather right before |q|. + +@<Insert new cross-reference at |q|...@>= + append_xref(0); /* this number doesn't matter */ + xref_ptr->xlink=(xref_pointer)p->xref; + p->xref=(ASCII*)xref_ptr; + r=xref_ptr; + while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;} + r->num=m; /* everything from |q| on is left undisturbed */ + + + +@ 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@; + +@ @u 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=make_math(init_mathness,last_mathness); + freeze_text; + if (k>1) { + for (i=j+k, i1=j+1; i<=lo_ptr; i++, i1++) { + i1->cat=i->cat; i1->trans=i->trans; + i1->mathness=i->mathness; + } + lo_ptr=lo_ptr-k+1; + } + @<Change |pp| to $\max(|scrap_base|,|pp+d|)$@>; +#ifdef DEBUG + @<Print a snapshot of the scrap list if debugging @>; +#endif DEBUG + pp--; /* we next say |pp++| */ +} + +@ @<Change |pp| to $\max...@>= +if (pp+d>=scrap_base) pp=pp+d; +else pp=scrap_base; + +@ The `|squash|' +procedure takes advantage of the simplification that occurs when |k=1|. +{\bf `|squash|' isn't used in Spidery \.{WEB}.} +@u squash(j,k,c,d,n) +scrap_pointer j; +eight_bits c; +short k, d, n; +{ + scrap_pointer i; /* pointers into scrap memory */ + if (k==1) { + j->cat=c; @<Change |pp|...@>; +#ifdef DEBUG + @<Print a snapshot...@>; +#endif DEBUG + pp--; /* we next say |pp++| */ + return; + } + for (i=j; i<j+k; i++) app1(i); + reduce(j,k,c,d,n); +} + +@ Here now is the code that applies productions as long as possible. It +requires two local labels (|found| and |done|), as well as a local +variable (|i|). + +@<Reduce the scraps using the productions until no more rules apply@>= +while (1) { + @<Make sure the entries |pp| through |pp+highestposoverall-1| + of |cat| are defined@>; + if (tok_ptr+8>tok_mem_end || text_ptr+4>tok_start_end) { +#ifdef STAT + if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr; + if (text_ptr>max_text_ptr) max_text_ptr=text_ptr; +#endif STAT + stat_overflow("token/text"); + } + if (pp>lo_ptr) break; + init_mathness=last_mathness=maybe_math; + @<Match a production...@>; +} + +@ If we get to the end of the scrap list, category codes equal to zero are +stored, since zero does not match anything in a production. + +@<Make sure the entries...@>= +if (lo_ptr<pp+highestposoverall-1) { + while (hi_ptr<=scrap_ptr && lo_ptr!=pp+highestposoverall-1) { + (++lo_ptr)->cat=hi_ptr->cat; lo_ptr->mathness=(hi_ptr)->mathness; + lo_ptr->trans=(hi_ptr++)->trans; + } + for (i=lo_ptr+1;i<=pp+highestposoverall-1;i++) i->cat=0; +} + +@ If \.{WEAVE} is being run in debugging mode, the production numbers and +current stack categories will be printed out when |tracing| is set to 2; +a sequence of two or more irreducible scraps will be printed out when +|tracing| is set to 1. + +@<Global...@>= +#ifdef DEBUG +int tracing; /* can be used to show parsing details */ +#endif DEBUG + +@ @<Print a snapshot...@>= { + 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 (left_math(k) == yes_math) putchar('+'); + else if (left_math(k) == no_math) putchar('-'); + print_cat(k->cat); + if (right_math(k)== yes_math) putchar('+'); + else if (right_math(k) == 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 +appends a |terminator| scrap and begins to apply productions as much as +possible. The result is a token list containing the translation of +the given sequence of scraps. + +After calling |translate|, we will have |text_ptr+3<=max_texts| and +|tok_ptr+6<=max_toks|, so it will be possible to create up to three token +lists with up to six tokens without checking for overflow. Before calling +|translate|, we should have |text_ptr<max_texts| and |scrap_ptr<max_scraps|, +since |translate| might add a new text and a new scrap before it checks +for overflow. + +@u text_pointer translate() /* converts a sequence of scraps */ +{ + scrap_pointer i, /* index into |cat| */ + j; /* runs through final scraps */ + pp=scrap_base; lo_ptr=pp-1; hi_ptr=pp; + @<If tracing, print an indication of where we are@>; + @<Reduce the scraps...@>; + @<Combine the irreducible scraps that remain@>; +} + +@ If the initial sequence of scraps does not reduce to a single scrap, +we concatenate the translations of all remaining scraps, separated by +blank spaces, with dollar signs +placed according to the |mathness| of the scraps. + +@<Combine the irreducible...@>= { + @<If semi-tracing, show the irreducible scraps@>; + for (j=scrap_base; j<=lo_ptr; j++) { + if (j!=scrap_base) small_app(' '); + if ((left_math(j) == yes_math) && math_flag==0) small_app('$'); + if ((left_math(j) == no_math) && math_flag==1) { + small_app(' '); small_app('$');} + small_app1(j); + if ((right_math(j) == yes_math) && math_flag==0) small_app('$'); + if ((right_math(j) == no_math) && math_flag==1) {small_app('$'); + small_app(' ');} + if (tok_ptr+6>tok_mem_end) stat_overflow("token"); + } + freeze_text; return(text_ptr-1); +} + +@ @<If semi-tracing, show the irreducible scraps@>= +#ifdef DEBUG +if (lo_ptr>scrap_base && tracing==1) { + printf("\nIrreducible scrap sequence in section %d:",module_count); + mark_harmless; + for (j=scrap_base; j<=lo_ptr; j++) { + printf(" "); print_cat(j->cat); + } +} +#endif DEBUG + +@ @<If tracing,...@>= +#ifdef DEBUG +if (tracing==2) { + printf("\nTracing after l. %d:\n",cur_line); mark_harmless; + if (loc>buffer+50) { + printf("..."); + ASCII_write(loc-51,51); + } + else ASCII_write(buffer+1,loc-buffer); +} +#endif DEBUG + +@* 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. +The raw input is converted into scraps according to the following table, +which gives category codes followed by the translations. Sometimes a single +item of input produces more than one scrap. +\def\stars {\.{---}}% + +A comment in the input will be combined with the preceding +|omega| or |semi| scrap, or with the following |terminator| scrap, if +possible; otherwise it will be inserted as a separate |terminator| scrap. +An additional ``comment'' is effectively appended at the end of the +\PASCAL\ text, just before translation begins; this consists of a |cancel| +token in the case of \PASCAL\ text in \pb, otherwise it consists of a +|force| token. + +From this table it is evident that \.{WEAVE} will parse a lot of non-\PASCAL\ +programs. For example, the reserved words `\.{for}' and `\.{array}' are +treated in an identical way by \.{WEAVE} from a syntactic standpoint, +and semantically they are equivalent except that a forced line break occurs +just before `\&{for}'; \PASCAL\ programmers may well be surprised at this +similarity. The idea is to keep \.{WEAVE}'s rules as simple as possible, +consistent with doing a reasonable job on syntactically correct \PASCAL\ +programs. The production rules below have been formulated in the same +spirit of ``almost anything goes.'' + +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 +`\.\{' (begin comment symbol) , or until |next_control>=format|. The +scraps corresponding to what +it reads are appended into the |cat| and |trans| arrays, and |scrap_ptr| +is advanced. + +|C_parse| should never be called with |next_control| equal to +|begin_comment|, because the +upper routines should be screening those out. + +@u C_parse(see_v) /* creates scraps from \cee\ tokens */ + char see_v; +{ + name_pointer p; /* identifier designator */ + while (next_control<format) { + @<Append the scrap appropriate to |next_control|@>; + next_control=get_next(see_v); + if (next_control==vertical_bar || next_control==begin_comment) return; + } +} + +@ The following macro is used to append a scrap whose tokens have just +been appended: + +@d app_scrap(c,M) = (++scrap_ptr)->cat=c; scrap_ptr->trans=text_ptr; +scrap_ptr->mathness=make_math(M,M); +freeze_text; + +@ @<Append the scr...@>= +@<Make sure that there is room for at least four more scraps, six more +tokens, and four more texts@>; +switch (next_control) { + @<Cases for ordinary tokens@>@; + case string: case constant: case verbatim: @<Append a string or constant@>; + break; + case @`\n': @<Append a newline scrap@>; break; + case identifier: @<Append an identifier scrap@>; break; + case TeX_string: @<Append a \TeX\ string scrap@>; break; + case ignore: case vertical_bar: + break; +case xref_roman: case xref_wildcard: case xref_typewriter: + break; + case thin_space: app_str("\\,"); app_scrap(SP_ignore_scrap,yes_math); break; + case math_break: + small_app(opt); app_str("0"); app_scrap(SP_ignore_scrap,yes_math); break; + case line_break: + app_str("\\0"); app_scrap(SP_ignore_scrap,yes_math); break; + case line_force: + small_app(force); app_scrap(SP_ignore_scrap,no_math); break; + case big_line_break: + small_app(big_force); app_scrap(SP_ignore_scrap,no_math); break; + case no_line_break: + small_app(big_cancel); small_app(' '); small_app(big_cancel); + app_scrap(SP_ignore_scrap,no_math); break; + case pseudo_semi: +@<Append a |pseudo_semi| scrap@> +break; + case join: app_str("\\J"); app_scrap(SP_ignore_scrap,no_math); break; + default: small_app(next_control); app_scrap(SP_ignore_scrap,no_math); break; +} + +@ Since we haven't yet figured out how to compute the room required +by looking at the productions, let's be paranoid. +@d SCRAP_SLACK = 50 +@d TOK_SLACK = 50 +@d TEXT_SLACK = 50 +@<Make sure that there is room for at least four...@>= +if (scrap_ptr+SCRAP_SLACK>scrap_info_end || tok_ptr+TOK_SLACK>tok_mem_end || + text_ptr+TEXT_SLACK>tok_start_end) { +#ifdef STAT + 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; +#endif STAT + stat_overflow("scrap/token/text"); +} + +@ Some nonstandard ASCII characters may have entered \.{WEAVE} by means of +standard ones. They are converted to \TeX\ control sequences so that it is +possible to keep \.{WEAVE} from stepping beyond standard ASCII. + +@ The following code must use |app_tok| instead of |small_app| in order to +protect against overflow. Note that |tok_ptr+1<=max_toks| after |app_tok| +has been used, so another |small_app| is legitimate before testing again. + +Many of the special characters in a string must be prefixed by `\.\\' so that +\TeX\ will print them properly. +@^special string characters@> + +@<Append a string or...@>= +if (next_control==constant) app_str("\\O{"); +@.\\O@> +else if (next_control==string) app_str("\\.{"); +@.\\.@> +else app_str("\\={"); +@.\\=@> +while (id_first<id_loc) { + if (*id_first==at_sign) { + if (*(id_first+1)==at_sign) id_first++; + else err_print("! Double at_sign should be used in strings"); + } +@.Double at_sign should be used...@> + @<Cause \TeX's special characters to be preceded with |'\\'|@>@; + app_tok(*id_first++); +} +small_app('}'); +@<Do the |app_scrap| for a string or constant@>@; + +@ @<Cause \TeX's special characters to be preceded with |'\\'|@>= +switch (*id_first) { + case ' ':case '\\': + case '%':case '$': case '^':case '`': + case '#': + case '{': case '}': case '~': case '&': case '_': + small_app('\\'); break; + + } + +@ @<Append a \TeX\ string scrap@>= +app_str("\\hbox{"); while (id_first<id_loc) app_tok(*id_first++); +small_app('}'); +@<Do the |app_scrap| for a string or constant@>@; + + +@ 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. + +@u 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(1); /* get the scraps together */ + if (next_control!=vertical_bar) err_print("! Missing vertical_bar after C text"); +@.Missing vertical_bar...@> + app_tok(cancel); app_scrap(SP_ignore_scrap,no_math); + /* place a |cancel| token as a final ``comment'' */ + p=translate(); /* make the translation */ +#ifdef STAT + if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr; +#endif STAT + 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|. Thus, it takes care of embedded comments. +It will also do annotation duty. + + +@u outer_parse() /* makes scraps from \cee\ tokens and comments */ +{ + int bal; /* brace level in comment */ + text_pointer p, q; /* partial comments */ + while (next_control<format) { + if (next_control==begin_comment) { + @<Make sure that there is room for at least seven more + tokens, three more texts, and one more scrap@>; /* spider */ + @<Copy comment, including embedded program text@>; + } + else { + C_parse(0); + } +} +} + +@ @<Copy comment, including embedded program text@>= + small_app(break_space); app_str("\\C{"); +@.\\cee@> + bal=copy_comment(1); next_control=vertical_bar; + while (bal>0) { + p=text_ptr; freeze_text; q=C_translate(); + /* at this point we have |tok_ptr+6<=max_toks| */ /* spider */ + small_app(tok_flag+p-tok_start); small_app(inner_tok_flag+q-tok_start); + if (next_control==vertical_bar) bal=copy_comment(bal); + else bal=0; /* an error has been reported */ + } + small_app(force); + app_scrap(SP_ignore_scrap,no_math); + /* the full comment becomes a scrap */ + + +@ @<Make sure that there is room for at least seven more...@>= +if (tok_ptr+TOK_SLACK>tok_mem_end || text_ptr+TEXT_SLACK>tok_start_end + || scrap_ptr+SCRAP_SLACK>scrap_info_end) { +#ifdef STAT + 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; +#endif STAT + stat_overflow("token/text/scrap"); +} + +@i scraps.web + +@* Output of tokens. +So far our programs have only built up multi-layered token lists in +\.{WEAVE}'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. Three main considerations had to be kept in mind when +this part of \.{WEAVE} was designed: (a) There are two modes of output, +|outer| mode that translates tokens like |force| into line-breaking +control sequences, and |inner| mode that 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\\P}'. + +@ 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 modules */ + +@<Typed...@>= typedef int mode; +typedef struct { + token_pointer end_field; /* ending location of token list */ + token_pointer tok_field; /* present location within token list */ + boolean mode_field; /* interpretation of control tokens */ +} output_state; +typedef output_state *stack_pointer; + +@ @d cur_end = cur_state.end_field /* current ending location in |tok_mem| */ +@d cur_tok = cur_state.tok_field /* location of next output token in |tok_mem| */ +@d cur_mode = cur_state.mode_field /* current mode of interpretation */ +@d init_stack = stack_ptr=stack;cur_mode=outer /* initialize the stack */ + +@<Global...@>= +output_state cur_state; /* |cur_end|, |cur_tok|, |cur_mode| */ +output_state stack[stack_size]; /* info for non-current levels */ +stack_pointer stack_ptr; /* first unused location in the output state stack */ +stack_pointer stack_end=stack+stack_size-1; /* end of |stack| */ +#ifdef STAT +stack_pointer max_stack_ptr; /* largest value assumed by |stack_ptr| */ +#endif STAT + +@ @<Set init...@>= +#ifdef STAT +max_stack_ptr=stack; +#endif STAT + +@ 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. + +@u push_level(p) /* suspends the current level */ +text_pointer p; +{ + if (stack_ptr==stack_end) stat_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++; +#ifdef STAT + if (stack_ptr>max_stack_ptr) max_stack_ptr=stack_ptr; +#endif STAT + 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|. + +@u 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 |mod_name| if the next token is to be an identifier (typeset in +italics), a reserved word (typeset in boldface) or a module name (typeset +by a complex routine that might generate additional levels of output). +In these cases |cur_name| points to the identifier or module name in +question. + +@<Global...@>= +name_pointer cur_name; + +@ @d res_word = 0201 /* returned by |get_output| for reserved words */ +@d mod_name = 0200 /* returned by |get_output| for module names */ + +@u 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(mod_name); /* |a==mod_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 module name may include +embedded \cee\ text; however, the depth of recursion never exceeds one +level, since module names cannot be inside of module 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 module. +@^recursion@> + +@u +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=vertical_bar; p=C_translate(); + small_app(p-tok_start+inner_tok_flag); + make_output(); /* output the list */ +#ifdef STAT + if (text_ptr>max_text_ptr) max_text_ptr=text_ptr; + if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr; +#endif STAT + 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 \.{WEAVE}'s major output handler. + +@u 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 */ + ASCII *k, *k_limit; /* indices into |byte_mem| */ + ASCII *j; /* index into |buffer| */ + ASCII delim; /* first and last character of string being copied */ + ASCII *save_loc, *save_limit; /* |loc| and |limit| to be restored */ + name_pointer cur_mod_name; /* name of module being output */ + boolean save_mode; /* value of |cur_mode| before a sequence of breaks */ + small_app(end_translation); /* append a sentinel */ + freeze_text; push_level(text_ptr-1); + while (1) { + a=get_output(); + reswitch: switch(a) { + case end_translation: return; + case identifier: case res_word: @<Output an identifier@>; break; + case mod_name: @<Output a module name@>; break; + case math_bin: case math_rel: case math_op: + @<Output a \.{\\math} operator@>; break; + case cancel: c=0; while ((a=get_output())>=indent && a<=big_force) { + if (a==indent) c++; if (a==outdent) c--; + } + @<Output saved |indent| or |outdent| tokens@>; + goto reswitch; + case big_cancel: c=0; + while (((a=get_output())>=indent || a==' ') && a<=big_force) { + if (a==indent) c++; if (a==outdent) c--; + } + @<Output saved...@>; + goto reswitch; + case indent: case outdent: case opt: case backup: case break_space: + case force: case big_force: @<Output a control, + look ahead in case of line breaks, possibly |goto reswitch|@>; break; + default: out(a); /* otherwise |a| is an ASCII 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 `\.{\\\char'174a}' but +`\.{\\\\\{aa\}}'. + +BUG FIX: use |out_name| even for identifiers of length 1, so that +the single-character identifier |_| is properly escaped. +@<Output an identifier@>= +out('\\'); +if (a==identifier) + if (length(cur_name)==1) out('|')@; +@.\\|@> + else out('\\')@; +@.\\\\@> +else out('&')@; /* |a==res_word| */ +@.\\\&@> +out_name(cur_name); + +@ @<Output a \....@>= +if (a==math_bin) out_str("\\mathbin{"); +else if (a==math_rel) out_str("\\mathrel{"); +else out_str("\\mathop{"); + +@ The current mode does not affect the behavior of \.{WEAVE}'s output routine +except when we are outputting control tokens. + +@<Output a control...@>= +if (a<break_space) { + if (cur_mode==outer) { + out('\\'); out(a-cancel+'0'); + if (a==opt) out(get_output()); /* |opt| is followed by a digit */ + } + else if (a==opt) b=get_output(); /* ignore digit following |opt| */ + } +else @<Look ahead for strongest line break, |goto reswitch|@>@; + +@ If several of the tokens |break_space|, |force|, |big_force| occur in a +row, possibly mixed with blank spaces (which are ignored), +the largest one is used. A line break also occurs in the output file, +except at the very end of the translation. The very first line break +is suppressed (i.e., a line break that follows `\.{\\Y\\P}'). + +@<Look ahead for st...@>= { + b=a; save_mode=cur_mode; c=0; + while (1) { + a=get_output(); + if (a==cancel || a==big_cancel) { + @<Output saved |indent| or |outdent| tokens@>; + goto reswitch; /* |cancel| overrides everything */ + } + if ((a!=' ' && a<indent) || a==backup || a>big_force) { + if (save_mode==outer) { + if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\P",4)==0) + goto reswitch; + @<Output saved |indent| or |outdent| tokens@>; + out('\\'); out(b-cancel+'0'); + if (a!=end_translation) finish_line(); + } + else if (a!=end_translation && cur_mode==inner) out(' '); + goto reswitch; + } + if (a==indent) c++; + else if (a==outdent) c--; + else if (a>b) b=a; /* if |a==' '| we have |a<b| */ + } +} + +@ @<Output saved...@>= + for (;c>0;c--) out_str("\\1"); + for (;c<0;c++) out_str("\\2"); + +@ The remaining part of |make_output| is somewhat more complicated. When we +output a module name, we may need to enter the parsing and translation +routines, since the name may contain \cee\ code embedded in +\pb\ constructions. This \cee\ code is placed at the end of the active +input buffer and the translation process uses the end of the active +|tok_mem| area. + +@<Output a module name@>= { + boolean is_file; + cur_xref=(xref_pointer)cur_name->xref; + is_file = cur_xref->num >= file_flag; + + out_str((is_file? "\\XF":"\\X")); +@.\\X@> + if (cur_xref->num>=def_flag) { + out_mod(cur_xref->num-(is_file ? file_flag : def_flag)); + if (phase==3) { + cur_xref=cur_xref->xlink; + while (cur_xref->num>=def_flag) { + out_str(", "); + out_mod(cur_xref->num-(is_file ? file_flag : def_flag)); + cur_xref=cur_xref->xlink; + } + } + } + else out('0'); /* output the module number, or zero if it was undefined */ + out(':'); @<Output the text of the module name@>; + out_str((is_file? "\\XF":"\\X")); +} + +@ @<Output the text...@>= +k=cur_name->byte_start; k_limit=(cur_name+1)->byte_start; +cur_mod_name=cur_name; +while (k<k_limit) { + b=*(k++); + if (b==at_sign) @<Skip next character, give error if not `\.{@@}'@>@; + if (b!=vertical_char) out(b)@; + else { + @<Copy the \cee\ text into the |buffer| array@>@; + save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1; + *limit=vertical_char; output_C(); + loc=save_loc; limit=save_limit; + } +} + +@ @<Skip next char...@>= +if (*k++!=at_sign) { + printf("\n! Illegal control code in section name: <"); +@.Illegal control code...@> + print_id(cur_mod_name); printf("> "); mark_error; +} + +@ The \cee\ text enclosed in \pb\ should not contain `\v' characters, +except within strings. We put a `\v' at the front of the buffer, so that an +error message that displays the whole buffer will look a little bit sensible. +The variable |delim| is zero outside of strings, otherwise it +equals the delimiter that began the string being copied. + +@<Copy the \cee\ text into...@>= +j=limit+1; *j=vertical_char; delim=0; +while (1) { + if (k>=k_limit) { + printf("\n! C text in section name didn't end: <"); +@.C text...didn't end@> + print_id(cur_mod_name); printf("> "); mark_error; break; + } + b=*(k++); + if (b==at_sign) @<Copy a control code into the buffer@>@; + else { + if (b=='\'' || b=='"') + if (delim==0) delim=b; + else if (delim==b) delim=0; + if (b!=vertical_char || delim!=0) { + if (j>buffer+long_buf_size-3) stat_overflow("buffer"); + *(++j)=b; + } + else break; + } +} + +@ @<Copy a control code into the buffer@>= { + if (j>buffer+long_buf_size-4) stat_overflow("buffer"); + *(++j)=at_sign; *(++j)=*(k++); +} + +@* Phase two processing. +We have assembled enough pieces of the puzzle in order to be ready to specify +the processing in \.{WEAVE}'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 +\.{WEB} specifications. + +@u phase_two() { +reset_input(); printf("\nWriting the output file..."); +module_count=0; copy_limbo(); +math_flag=0; +finish_line(); flush_buffer(out_buf,0); /* insert a blank line, it looks nice */ +while (!input_has_ended) @<Translate the current module@>; +} + +@ The output file will contain the control sequence \.{\\Y} between non-null +sections of a module, 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 module. 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"); +@.\\Y@> + +@<Global...@>= +int save_line; /* former value of |out_line| */ +ASCII *save_place; /* former value of |out_ptr| */ + +@ @<Translate the current module@>= { + module_count++; + @<Output the code for the beginning of a new module@>; + save_position; + @<Translate the \TeX\ part of the current module@>; + @<Translate the definition part of the current module@>; + @<Translate the \cee\ part of the current module@>; + @<Show cross-references to this module@>; + @<Output the code for the end of a module@>; +} + +@ Modules beginning with the \.{WEB} control sequence `\.{@@\ }' start in the +output with the \TeX\ control sequence `\.{\\M}', followed by the module +number. Similarly, `\.{@@*}' modules lead to the control sequence `\.{\\N}'. +If this is a changed module, we put \.{*} just before the module number. + +@<Output the code for the beginning...@>= +if (*(loc-1)!='*') out_str("\\M"); +@.\\M@> +else { + out_str("\\N"); +@.\\N@> + printf("*%d",module_count); update_terminal; /* print a progress report */ +} +out_mod(module_count); out_str(". "); + +@ In the \TeX\ part of a module, we simply copy the source text, except that +index entries are not copied and \cee\ text within \pb\ is translated. + +@<Translate the \T...@>= do { + next_control=copy_TeX(); + switch (next_control) { + case vertical_bar: /* surround vertical bar with \.{\\CD...\\DC} */ + out_str("\\CD{}"); + init_stack; output_C(); + out_str("\\DC{}"); + break; + case at_sign: out(at_sign); break; + case octal: @<Translate an octal constant appearing in \TeX\ text@>; break; + case hex: @<Translate a hex constant appearing in \TeX\ text@>; break; + case TeX_string: case xref_roman: case xref_wildcard: case xref_typewriter: + case module_name: loc-=2; next_control=get_next(1); /* 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 line_break: case big_line_break: case no_line_break: case join: + case pseudo_semi: err_print("! You can't do that in TeX text"); break; +@.You can't do that...@> + } +} while (next_control<format); + +@ @<Translate an octal constant appearing in \TeX\ text@>= { +out_str("\\O{\\~"); + while ('0'<=*loc && *loc<'8') out(*loc++); +out('}'); +} + +@ @<Translate a hex constant appearing in \TeX\ text@>= { +out_str("\\O{\\^"); + while (isxdigit(*loc)) { + out(islower(*loc) ? toupper(*loc):*loc); + loc++; + } +out('}'); +} + + + +@ When we get to the following code we have |next_control>=format|, and +the token memory is in its initial empty state. + +@<Translate the d...@>= +if (next_control<=definition) { /* definition part non-empty */ + emit_space_if_needed; save_position; +} +while (next_control<=definition) { /* |format| or |definition| */ + init_stack; + if (next_control==definition) @<Start a macro definition@>@; + else @<Start a format definition@>; + outer_parse(); finish_C(); +} + +@ The |finish_C| procedure outputs the translation of the current +scraps, preceded by the control sequence `\.{\\P}' 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}. + +@u finish_C() /* finishes a definition or a \cee\ part */ +{ + text_pointer p; /* translation of the scraps */ + out_str("\\P"); app_tok(force); app_scrap(SP_ignore_scrap,no_math); + p=translate(); +@.\\P@> + small_app(p-tok_start+tok_flag); 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; /* suppress ordinary force?! */ + else if (*out_ptr=='7') *out_ptr='Y'; + out_str("\\par"); finish_line(); +#ifdef STAT + 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; +#endif STAT + tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info; + /* forget the tokens and the scraps */ +} + +@ +@<Start a macro...@>= { + small_app(backup); app_str("\\D"); /* this will produce `\&{define}' */ +@.\\D@> +@<Set |next_control| to the first non-newline token@>@; + if (next_control!=identifier) + err_print("! Improper macro definition"); +@.Improper macro definition@> + else { + small_app('$'); + small_app(id_flag+id_lookup(id_first, id_loc,normal)-name_dir); + @<Scan the parameter list (if any), + and set |next_control| to the non-newline + token following the parameter list@>; + if (next_control==@`=') { + small_app('\\'); small_app('S'); /* equivalence sign */ + @<Set |next_control| to the first non-newline token@>@; + } else { + err_print ("! Equals sign required in macro definition"); +@.Equals sign required...@> + } +punt_the_definition: + small_app('$'); small_app(break_space); + app_scrap(SP_ignore_scrap,no_math); + /* scrap won't take part in the parsing */ + } +} + +@ @<Quit scanning the macro definition@>=goto punt_the_definition; + +@ @<Scan the parameter list (if any), + and set |next_control| to the non-newline + token following the parameter list@>= +@<Set |next_control| to the first non-newline token@>@; +if (next_control==@`(') { + small_app(@`('); + do { + @<Set |next_control| to the first non-newline token@>@; + if (next_control==identifier) { + small_app(id_flag+id_lookup(id_first, id_loc,normal)-name_dir); + @<Set |next_control| to the first non-newline token@>@; + } else { + err_print("! Improper macro definition"); + @<Quit scanning the macro definition@>; + } + if (next_control==@`,' || next_control==@`)') + small_app(next_control); + } while (next_control==@`,'); + if (next_control != @`)') { + err_print("! Macro parameter list must end with )"); + @<Quit scanning the macro definition@>; + } + @<Set |next_control| to the first non-newline token@>@; + /* first token following parameter list */ +} + + + + +@ @<Start a format...@>= { + app_str("\\F"); app_scrap(SP_ignore_scrap,no_math); + /* this will produce `\&{format}' */ +@.\\F@> +@<Set |next_control| to the first non-newline token@>@; +/* claim at this point |scrap_ptr==scrap_info+1| */ + if (scrap_ptr!=scrap_info+1) { + err_print("! This can't happen -- bad scrap_ptr in format definition"); + printf("\n\tscrap_ptr-scrap_info==%d\n",scrap_ptr-scrap_info); + } + if (next_control==identifier) { + small_app(id_flag+id_lookup(id_first, id_loc,normal)-name_dir); + app_str(" "); + app_scrap(SP_ignore_scrap,no_math); /*spider*/ + /* this is syntactically separate from what follows */ + @<Set |next_control| to the first non-newline token@>@; + if (next_control==identifier) { + small_app(id_flag+id_lookup(id_first, id_loc,normal)-name_dir); + small_app(@`\n'); + app_scrap(SP_ignore_scrap,no_math); + @<Set |next_control| to the first non-newline token@>@; + } + } + /* if everything went well, we appended two scraps */ + if (scrap_ptr!=scrap_info+3) err_print("! Improper format definition"); +@.Improper format definition@> +} + +@ Finally, when the \TeX\ and definition parts have been treated, we have +|next_control>=begin_unnamed|. We will make the global variable |this_module| +point to the current module name, if it has a name. + +@<Global...@>= +name_pointer this_module; /* the current module name, or zero */ + +@ @<Translate the \cee...@>= +this_module=name_dir; +if (next_control<=module_name) { + emit_space_if_needed; init_stack; + if (next_control==begin_unnamed) next_control=get_next(0); + else { + this_module=cur_module; + @<Check that |=| follows this module name, and + emit the scraps to start the module definition@>; + } + while (next_control<=module_name) { + outer_parse(); + @<Emit the scrap for a module name if present@>; + } + finish_C(); +} + +@ @<Check that |=|...@>= +do next_control=get_next(0); + while (next_control=='+'); /* allow optional `\.{+=}' */ +if (next_control!='=') + err_print("! You need an = sign after the section name"); +@.You need an = sign...@> + else next_control=get_next(0); +if (out_ptr>out_buf+1 && *out_ptr=='Y' && *(out_ptr-1)=='\\') small_app(backup); + /* the module name will be flush left */ +@.\\Y@> +small_app(mod_flag+this_module-name_dir); +cur_xref=(xref_pointer)this_module->xref; +app_str("${}"); +if (cur_xref->num%def_flag!=module_count) { + app_str("+"); /*module name is multiply defined*/ + this_module=name_dir; /*so we won't give cross-reference info here*/ +} +app_str("\\S"); /* output an equivalence sign */ +@.\\S@> +app_str("{}$"); +small_app(force); +@<Call |app_scrap| for a module definition@> +/* this forces a line break unless `\.{@@+}' follows */ + +@ @<Emit the scrap...@>= +if (next_control<module_name) { + err_print("! You can't do that in C text"); +@.You can"t do that...@> + next_control=get_next(1); +} +else if (next_control==module_name) { + if (cur_module_char!='<') { + err_print("! You can't use a file like a module"); +@.You can't use a file like a module@> + next_control=get_next(1); + } else { + small_app(mod_flag+cur_module-name_dir); + @<Call |app_scrap| for a module use@> + next_control=get_next(1); + } +} + +@ Cross references relating to a named module are given after the module ends. + +@<Show cross...@>= +if (this_module>name_dir) { + @<Rearrange the list pointed to by |cur_xref|@>; + footnote(((((xref_pointer)this_module->xref)->num >= file_flag) + ? file_flag : def_flag)); + footnote(0); +} + +@ To rearrange the order of the linked list of cross-references, we need +four more variables that point to cross-reference entries. We'll end up +with a list pointed to by |cur_xref|. + +@<Global...@>= +xref_pointer next_xref, this_xref, first_xref, mid_xref; + /* pointer variables for rearranging a list */ + +@ We want to rearrange the cross-reference list so that all the entries with +|def_flag| come first, in ascending order; then come all the other +entries, in ascending order. There may be no entries in either one or both +of these categories. + +@<Rearrange the list...@>= + first_xref=(xref_pointer)this_module->xref; + this_xref=first_xref->xlink; /* bypass current module number */ + if (this_xref->num>def_flag) { + mid_xref=this_xref; cur_xref=0; /* this value doesn't matter */ + do { + next_xref=this_xref->xlink; this_xref->xlink=cur_xref; + cur_xref=this_xref; this_xref=next_xref; + } while (this_xref->num>def_flag); + first_xref->xlink=cur_xref; +} +else mid_xref=xmem; /* first list null */ +cur_xref=xmem; +while (this_xref!=xmem) { + next_xref=this_xref->xlink; this_xref->xlink=cur_xref; + cur_xref=this_xref; this_xref=next_xref; +} +if (mid_xref>xmem) mid_xref->xlink=cur_xref; +else first_xref->xlink=cur_xref; +cur_xref=first_xref->xlink; + +@ The |footnote| procedure gives cross-reference information about +multiply defined module names (if the |flag| parameter is |def_flag|), or about +the uses of a module name (if the |flag| parameter is zero). 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: +`\.{\\A\ section 101.}'; `\.{\\U\ sections 370 and 1009.}'; +`\.{\\A\ sections 8, 27\\*, and 64.}'. + +@u footnote(flag) /* outputs module cross-references */ +sixteen_bits flag; +{ + xref_pointer q; /* cross-reference pointer variable */ + if (cur_xref->num<=flag) return; + finish_line(); out('\\'); +@.\\A@> +@.\\U@> + if (flag==0) out('U')@;@+else out('A'); + out_str(" section"); + @<Output all the module numbers on the reference list |cur_xref|@>; + out('.'); +} + +@ The following code distinguishes three cases, according as the number +of cross-references is one, two, or more than two. Variable |q| points +to the first cross-reference, and the last link is a zero. + +@<Output all the module numbers...@>= +q=cur_xref; if (q->xlink->num>flag) out('s'); /* plural */ +out('~'); +while (1) { + out_mod(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 || cur_xref!=q->xlink) out(','); + /* not the last of two */ + out(' '); + if (cur_xref->xlink->num<=flag) out_str("and~"); /* the last */ +} + +@ @<Output the code for the end of a module@>= +out_str("\\fi"); finish_line(); +@.\\fi@> +flush_buffer(out_buf,0); /* insert a blank line, it looks nice */ + +@* Phase three processing. +We are nearly finished! \.{WEAVE}'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, module name list, and table of +contents. + +@<Glob...@>= +extern int no_xref; + +@ @u phase_three() { +if (no_xref) { + finish_line(); + out_str("\\vfill\\end"); + finish_line(); +} +else { + phase=3; printf("\nWriting the index..."); + if (change_exists) { + finish_line(); @<Tell about changed modules@>; + } + finish_line(); out_str("\\inx"); finish_line(); +@.\\inx@> + @<Do the first pass of sorting@>; + @<Sort and output the index@>; + out_str("\\fin"); finish_line(); +@.\\fin@> + @<Output all the module names@>; + out_str("\\con"); finish_line(); +@.\\con@> +} +printf("Done."); +check_complete(); /* was all of the change file used? */ +} + +@ Just before the index comes a list of all the changed modules, including +the index module itself. + +@<Global...@>= +sixteen_bits k_module; /* runs through the modules */ + +@ @<Tell about changed modules@>= { + /* remember that the index is already marked as changed */ + k_module=0; + while (!changed_module[++k_module]); + out_str("\\ch "); + out_mod(k_module); + while (1) { + while (!changed_module[++k_module]); + out_str(", "); out_mod(k_module); + if (k_module==module_count) break; + } + out('.'); +} + +@ A left-to-right radix sorting method is used, since this makes it easy to +adjust the collating sequence and since the running time will be at worst +proportional to the total length of all entries in the index. We put the +identifiers into 102 different lists based on their first characters. +(Uppercase letters are put into the same list as the corresponding lowercase +letters, since we want to have `$t<\\{TeX}<\&{to}$'.) The +list for character |c| begins at location |bucket[c]| and continues through +the |blink| array. + +@<Global...@>= +name_pointer bucket[128]; +name_pointer next_name; /* successor of |cur_name| when sorting */ +hash_pointer h; /* index into |hash| */ +name_pointer blink[max_names]; /* links in the buckets */ + +@ To begin the sorting, we go through all the hash lists and put each entry +having a nonempty cross-reference list into the proper bucket. + +@<Do the first pass...@>= { +int c; +for (c=0; c<=127; 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 (((xref_pointer)cur_name->xref)!=xmem) { + c=(cur_name->byte_start)[0]; + if (c<='Z' && c>='A') c=c+040; + blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name; + } + } +} +} + +@ During the sorting phase we shall use the |cat| and |trans| arrays from +\.{WEAVE}'s parsing algorithm and rename them |depth| and |head|. They now +represent a stack of identifier lists for all the index entries that have +not yet been output. The variable |sort_ptr| tells how many such lists are +present; the lists are output in reverse order (first |sort_ptr|, then +|sort_ptr-1|, etc.). The |j|th list starts at |head[j]|, and if the first +|k| characters of all entries on this list are known to be equal we have +|depth[j]=k|. + +@ @<Rest of |trans_plus| union@>= +name_pointer Head; + +@ +@d depth = cat /* reclaims memory that is no longer needed for parsing */ +@d head = trans_plus.Head /* ditto */ +@d sort_pointer = scrap_pointer /* ditto */ +@d sort_ptr = scrap_ptr /* ditto */ +@d max_sorts = max_scraps /* ditto */ + +@<Global...@>= +eight_bits cur_depth; /* depth of current buckets */ +ASCII *cur_byte; /* index into |byte_mem| */ +sixteen_bits cur_val; /* current cross-reference number */ +#ifdef STAT +sort_pointer max_sort_ptr; /* largest value of |sort_ptr| */ +#endif STAT + +@ @<Set init...@>= +#ifdef STAT +max_sort_ptr=scrap_info; +#endif STAT + + +@ The desired alphabetic order is specified by the |collate| array; namely, +|collate[0]<collate[1]<@t$\cdots$@><collate[100]|. + +@<Global...@>= +ASCII collate[102]; /* collation order */ + +@ We use the order $\hbox{null}<\.\ <\hbox{other characters}<\.\_< +\.A=\.a<\cdots<\.Z=\.z<\.0<\cdots<\.9.$ + +@<Set init...@>= +collate[0]=0; strcpy(collate+1," \1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\ +\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\ +!\42#$%&'()*+,-./:;<=>?@@[\\]^`{|}~_\ +abcdefghijklmnopqrstuvwxyz0123456789"); + +@ 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) */ + +@u unbucket(d) /* empties buckets having depth |d| */ +eight_bits d; +{ + ASCII c; /* index into |bucket| */ + for (c=100; c>= 0; c--) if (bucket[collate[c]]) { + if (sort_ptr>=scrap_info_end) stat_overflow("sorting"); + sort_ptr++; +#ifdef STAT + if (sort_ptr>max_sort_ptr) max_sort_ptr=sort_ptr; +#endif STAT + if (c==0) sort_ptr->depth=infinity; + else sort_ptr->depth=d; + sort_ptr->head=bucket[collate[c]]; bucket[collate[c]]=NULL; + } +} + +@ @<Sort and output...@>= +sort_ptr=scrap_info; unbucket(1); +while (sort_ptr>scrap_info) { + cur_depth=sort_ptr->depth; + if (blink[sort_ptr->head-name_dir]==0 || cur_depth==infinity) + @<Output index entries for the list at |sort_ptr|@>@; + else @<Split the list at |sort_ptr| into further lists@>; +} + +@ @<Split the list...@>= { + ASCII 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=*cur_byte; + if (c<='Z' && c>='A') c=c+040; + } + blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name; + } while (next_name); + --sort_ptr; unbucket(cur_depth+1); +} + +@ @<Output index...@>= { + cur_name=sort_ptr->head; + do { + out_str("\\:"); +@.\\:@> + @<Output the name at |cur_name|@>; + @<Output the cross-references at |cur_name|@>; + cur_name=blink[cur_name-name_dir]; + } while (cur_name); + --sort_ptr; +} + +@ @<Output the name...@>= +switch (cur_name->ilk) { + case normal: if (length(cur_name)==1) out_str("\\|"); + else out_str("\\\\"); break; +@.\\|@> +@.\\\\@> + case roman: break; + case wildcard: out_str("\\9"); break; +@.\\9@> + case typewriter: out_str("\\."); break; +@.\\.@> + default: out_str("\\&"); +@.\\\&@> +} +out_name(cur_name); + +@ Section numbers that are to be underlined are enclosed in +`\.{\\[}$\,\ldots\,$\.]'. + +@<Output the cross-references...@>= +@<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>; +do { + out_str(", "); cur_val=cur_xref->num; + if (cur_val<def_flag) out_mod(cur_val); + else {out_str("\\["); out_mod(cur_val%def_flag); out(']');} +@.\\[@> + cur_xref=cur_xref->xlink; +} while (cur_xref!=xmem); +out('.'); finish_line(); + +@ List inversion is best thought of as popping elements off one stack and +pushing them onto another. In this case |cur_xref| will be the head of +the stack that we push things onto. + +@<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>= +this_xref=(xref_pointer)cur_name->xref; cur_xref=xmem; +do { + next_xref=this_xref->xlink; this_xref->xlink=cur_xref; + cur_xref=this_xref; this_xref=next_xref; +} while (this_xref!=xmem); + +@ The following recursive procedure walks through the tree of module names and +prints them. +@^recursion@> + +@u mod_print(p) /* print all module names in subtree |p| */ +name_pointer p; +{ + boolean is_file; + if (p) { + mod_print(p->llink); + cur_xref=(xref_pointer)p->xref; + is_file=((cur_xref->num)>=file_flag); + if ((is_file && do_file)||(!is_file && !do_file)) { /* C has no xor */ + out_str("\\:"); +@.\\:@> + tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info; init_stack; + small_app(p-name_dir+mod_flag); make_output(); + footnote(0); /* |cur_xref| was set by |make_output| */ + finish_line(); + } + mod_print(p->rlink); + } +} + +@ Here we list files, then modules. +@<Global...@>=boolean do_file; +@ @<Output all the module names@>= +do_file=(1==1); +mod_print(root); +do_file=(1==0); +mod_print(root); + + + +@ @<Print statistics about memory usage@>= +printf( +"\nMemory usage statistics: %d of %d names, %d of %d cross-references,\n", + name_ptr-name_dir, name_dir_end-name_dir, + xref_ptr-xmem, xmem_end-xmem); +printf("\t %d of %d bytes;",byte_ptr-byte_mem,byte_mem_end-byte_mem); +printf("\nParsing required %d of %d(%d) scraps, %d of %d(%d) texts,\n", + max_scr_ptr-scrap_info, max_scraps, max_scraps-SCRAP_SLACK, + max_text_ptr-tok_start, max_texts, max_texts-TEXT_SLACK + ); +printf("\t %d of %d(%d) tokens, %d of %d levels;\n", + max_tok_ptr-tok_mem, max_toks, max_toks-TOK_SLACK, + max_stack_ptr-stack, stack_end-stack + ); +printf("\nSorting required %d levels\n", max_sort_ptr-scrap_info); + +@ @u +stat_overflow(s) + char *s; +{ + printf("\n! Sorry, capacity exceeded: %s",s); +#ifdef STAT + @<Print statistics about memory usage@>; +#endif STAT + history=fatal_message; wrap_up(); +} + +@* 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 modules 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 module 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/spiderweb/src/master/webhead b/web/spiderweb/src/master/webhead new file mode 100644 index 0000000000..3dfb208171 --- /dev/null +++ b/web/spiderweb/src/master/webhead @@ -0,0 +1,2 @@ +@*Example. +@c diff --git a/web/spiderweb/src/master/webtail b/web/spiderweb/src/master/webtail new file mode 100644 index 0000000000..3749661008 --- /dev/null +++ b/web/spiderweb/src/master/webtail @@ -0,0 +1 @@ +@*Index. diff --git a/web/spiderweb/src/nawk/make b/web/spiderweb/src/nawk/make new file mode 100644 index 0000000000..2fa9260a45 --- /dev/null +++ b/web/spiderweb/src/nawk/make @@ -0,0 +1,2 @@ +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=nawktangle THEWEAVE=nawkweave SPIDER=nawk.spider $* diff --git a/web/spiderweb/src/nawk/nawk.spider b/web/spiderweb/src/nawk/nawk.spider new file mode 100644 index 0000000000..45e2186bb9 --- /dev/null +++ b/web/spiderweb/src/nawk/nawk.spider @@ -0,0 +1,176 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language NAWK extension awk + +at_sign # + +module definition stmt use stmt +# use as stmt is unavoidable since tangle introduces line breaks + +comment begin <"##"> end newline +macros begin +\def\commentbegin{\#} % we don't want \#\# +macros end + +line begin <"#line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness yes +token number category math mathness yes +token newline category newline translation <> mathness maybe +token pseudo_semi category ignore_scrap mathness no translation <opt-0> + +token \ category backslash translation <> mathness maybe +token + category unorbinop +token - category unorbinop +token * category binop +token / category binop +token < category binop +token > category binop +token >> category binop translation <"\\GG"> +token = category equals translation <"\\K"> +token ~ category binop translation <"\\TI"> +token !~ category binop translation <"\\not\\TI"> +token & category binop translation <"\\amp"> +token % translation <"\\%"> category binop +token ( category open +token [ category lsquare +token ) category close +token ] category close +token { translation <"\\;\\{"-indent> category lbrace +token } translation <"\\}\\"-space> category close +token , category binop translation <",\\,"-opt-3> +token ^ category exponent translation <> + +token ; category semi translation <";"-space-opt-2> mathness no +# stuff with semi can be empty in for statements +open semi --> open +semi semi --> semi +semi close --> close +semi --> binop + +# token : category colon +# token | category bar +token != name not_eq translation <"\\I"> category binop +token <= name lt_eq translation <"\\L"> category binop +token >= name gt_eq translation <"\\G"> category binop +token == name eq_eq translation <"\\S"> category binop +token && name and_and translation <"\\W"> category binop +token || name or_or translation <"\\V"> category binop +# token -> name minus_gt translation <"\\MG"> category binop +token ++ name gt_gt category unop translation <"\\uparrow"> +token -- name lt_lt category unop translation <"\\downarrow"> +# preunop is for unary operators that are prefix only +token $ category preunop translation <"\\DO"> mathness yes + +default mathness yes translation <*> + +ilk pattern_like category math +reserved BEGIN ilk pattern_like +reserved END ilk pattern_like + +ilk if_like category if +reserved if +ilk else_like category else +reserved else + +ilk print_like category math +# math forces space between this and other math... +reserved print ilk print_like +reserved printf ilk print_like +reserved return ilk print_like + + +ilk functions category unop mathness yes +reserved length ilk functions +reserved substr ilk functions +reserved index ilk functions +reserved split ilk functions +reserved sqrt ilk functions +reserved log ilk functions +reserved exp ilk functions +reserved int ilk functions +reserved sprintf ilk functions + +ilk variables category math mathness yes +reserved NR ilk variables +reserved NF ilk variables +reserved FS ilk variables +reserved RS ilk variables +reserved OFS ilk variables +reserved ORS ilk variables + +ilk for_like category for +reserved for ilk for_like +reserved while ilk for_like + +ilk in_like category binop translation <math_bin-*-"}"> mathness yes +# translation <"\\"-space-*-"\\"-space> +reserved in ilk in_like + +ilk stmt_like category math +reserved break ilk stmt_like +reserved continue ilk stmt_like +reserved next ilk stmt_like +reserved exit ilk stmt_like + +ilk function_like category math translation <big_force-*> mathness no +reserved function ilk function_like + + +backslash newline --> math +# The following line must be changed to make a backslash +backslash <"\\backslash"> --> math + +math (binop|unorbinop) math --> math +<"\\buildrel"> (binop|unorbinop) <"\\over{"> equals <"}"> --> binop +equals --> binop +(unop|preunop|unorbinop) math --> math +# unorbinop can only act like unary op as *prefix*, not postfix +math unop --> math +math <"\\"-space> math --> math +# concatenation + +math newline --> stmt +newline --> ignore_scrap + +stmt <force> stmt --> stmt + +(open|lsquare) math close --> math + +# make exponentials superscripts +math <"^{"> exponent math <"}"> --> math + +math lbrace --> lbrace +lbrace <force> stmt --> lbrace +lbrace <outdent-force> close --> stmt + +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace <force> stmt --> ifbrace +ifbrace <outdent-force> close else <"\\"-space> if --> if +ifbrace <outdent-force> close else lbrace --> ifbrace +ifbrace <outdent-force> close else newline --> ifline +ifbrace <outdent-force> close --> stmt +(ifline|ifmath) <indent-force> stmt <outdent-force> else <"\\"-space> if --> if +(ifline|ifmath) <indent-force> stmt <outdent-force> else lbrace --> ifbrace +(ifline|ifmath) <indent-force> stmt <outdent-force> else newline --> ifline +(ifline|ifmath) <indent-force> stmt <outdent-force> else --> ifmath +(ifline|ifmath) <indent-force> stmt <outdent> --> stmt + +for <"\\"-space> math --> formath +formath lbrace --> forbrace +formath newline --> forline +forbrace <force> stmt --> forbrace +forbrace <outdent-force> close --> stmt +(forline|formath) <indent-force> stmt <outdent> --> stmt + + + +? ignore_scrap --> #1 + + + diff --git a/web/spiderweb/src/penelope/SpiderMakefile b/web/spiderweb/src/penelope/SpiderMakefile new file mode 100644 index 0000000000..9242c3ff9d --- /dev/null +++ b/web/spiderweb/src/penelope/SpiderMakefile @@ -0,0 +1,9 @@ +tangle: processed-a.spider +weave: processed-a.spider +processed-a.spider: a.spider scan_annotations.awk + awk -f scan_annotations.awk < a.spider > processed-a.spider + chmod -w processed-a.spider +clean: # do nothing + echo spider files need no cleaning + + diff --git a/web/spiderweb/src/penelope/a.spider b/web/spiderweb/src/penelope/a.spider new file mode 100644 index 0000000000..86694573ca --- /dev/null +++ b/web/spiderweb/src/penelope/a.spider @@ -0,0 +1,375 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language Ada extension ada + +at_sign @ + +module definition stmt use math + +comment begin <dash-dash-space> end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin <dash-dash-"line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness maybe +token number category math mathness yes +token newline category nl translation <> mathness maybe +# newline mathness must be no to work with busted_comment +token pseudo_semi translation <> category semi mathness maybe + +macros begin +\let\R\relax +macros end + +# Delimiters +token & category binop translation <"\\amp"> +token ( category open +token ) category close +token * category binop +token + category unorbinop +token , category binop translation <",\\,"-opt-3> +token - category unorbinop +token . category binop +token / category binop +token : category binop +token ; category semi translation <";"-space-opt-2> +token < category binop +token = category binop +token > category binop +token | category binop translation <"\\mid"> + +# Compound delimiters + +token => category arrow translation <"\\AR"> +token .. category binop translation <"\\.{..}"> +token ** category binop +token := category binop translation <"\\mathbin{:=}"> +token /= translation <"\\I"> category binop +token >= translation <"\\G"> category binop +token <= translation <"\\L"> category binop +token << translation <"\\LL"> category openlabel +token >> translation <"\\GG"> category closelabel +token <> translation <"\\LG"> category math + +# Hacks no ', and this becomes a binary op +token ' category binop mathness no + +token # category math translation <"\\#"> +token -- category busted_comment mathness no translation <"\\C{"> + + + + +default mathness maybe translation <*> + +reserved abort ilk math_like +reserved abs ilk unop_like +reserved accept ilk proc_like +reserved access ilk math_like +reserved all ilk math_like +reserved and ilk and_like +reserved array ilk math_like +reserved at ilk at_like +reserved begin ilk begin_like +reserved body ilk math_like +reserved case ilk case_like +reserved constant ilk math_like +reserved declare ilk decl_like +reserved delay ilk math_like +reserved delta ilk math_like +reserved digits ilk math_like +reserved do ilk is_like +reserved else ilk else_like +reserved elsif ilk elsif_like +reserved end ilk end_like +reserved entry ilk proc_like +reserved exception ilk ex_like +reserved exit ilk math_like +reserved for ilk math_like +reserved function ilk proc_like +reserved generic ilk gen_like +reserved goto ilk math_like +reserved if ilk if_like +reserved in ilk unorbinop_like +reserved is ilk is_like +reserved limited ilk math_like +reserved loop ilk loop_like +reserved mod ilk binop_like +reserved new ilk separate_like +reserved not ilk unop_like +reserved null ilk math_like +reserved of ilk math_like +reserved or ilk or_like +reserved others ilk math_like +reserved out ilk math_like +reserved package ilk proc_like +reserved pragma ilk math_like +reserved private ilk private_like +reserved procedure ilk proc_like +reserved raise ilk math_like +reserved range ilk math_like +reserved record ilk record_like +reserved rem ilk binop_like +reserved renames ilk math_like +reserved return ilk math_like +reserved reverse ilk math_like +reserved select ilk begin_like +reserved separate ilk separate_like +reserved subtype ilk math_like +reserved task ilk proc_like +reserved terminate ilk math_like +reserved then ilk then_like +reserved type ilk math_like +reserved use ilk math_like +reserved when ilk when_like +reserved while ilk math_like +reserved with ilk with_like +reserved xor ilk binop_like + +ilk and_like translation <*> category and +ilk at_like translation <*> category at +ilk begin_like translation <*-indent> category beginning +ilk binop_like translation <"\\"-space-*-"\\"-space> category binop +ilk case_like translation <*> category case +ilk decl_like translation <*-indent> category declaration +ilk else_like translation <*> category else +ilk elsif_like translation <*> category elsif +ilk end_like translation <*> category close +ilk ex_like translation <*> category exception +ilk gen_like translation <*-indent> category generic +ilk if_like translation <*> category if +ilk is_like translation <*> category is mathness no +ilk loop_like translation <*> category loop +ilk math_like translation <*> category math +ilk or_like translation <*> category or +ilk private_like translation <*> category private +ilk proc_like translation <*> category proc +ilk record_like translation <*> category record +ilk separate_like translation <*> category separate +ilk then_like translation <*> category then +ilk unop_like translation <*-"\\"-space> category unop +ilk unorbinop_like translation <"\\"-space-*-"\\"-space> category resunorbinop +ilk when_like translation <*> category when +ilk where_like category where +ilk with_like translation <*> category with + + +# \MC means ``math close'' and sets \MS to ``math set'' +macros begin +\def\MC{\ifmmode\global\let\MS$\else\global\let\MS\relax\fi\relax\MS} +\def\LG{\mathord{<}\mathord{>}} +\let\IG=\ignorespaces +macros end + + + +busted_comment <"\\MC}\\MS\\R"-force> nl --> ignore_scrap +busted_comment ? --> busted_comment + +beginning <outdent-force> continuation <outdent-force> ending --> stmt +beginning <outdent-force> ending --> stmt +beginning <force> (stmt|ignore_scrap) --> beginning + +case <"\\"-space> math <"\\"-space> is <indent-force> --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation <force> (stmt|ignore_scrap) --> continuation +continuation <outdent-force> continuation --> continuation + + +declaration <outdent-force> beginning <outdent-force> continuation <outdent-force> ending --> stmt +declaration <outdent-force> beginning <outdent-force> ending --> stmt +declaration <outdent-force> ending --> stmt +declaration <force> (stmt|ignore_scrap) --> declaration + +else <indent-force> --> continuation +elsif <"\\"-space> math <"\\"-space> then <indent-force> --> continuation + +exception <indent-force> --> continuation + +generic <outdent-force> declaration --> declaration +generic <force> (stmt|ignore_scrap) --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen <indent-force> stmt --> beginning +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> else --> ifthen +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> close <"\\"-space> if --> math +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> elsif --> if + + +is --> math + +loop <indent-force> --> beginning + +math [ <"\\"-space> and <"\\"-space> then <"\\"-space> ] --> math binop +math [ <"\\"-space> and <"\\"-space> ] --> math binop + +math (binop|unorbinop) math --> math +math <"\\"-space> resunorbinop <"\\"-space> math --> math +(unorbinop|unop) math --> math +resunorbinop <"\\"-space> math --> math +# This doesn't apply in Ada: math unop --> math + +math arrow --> math +math binop <"\\"-space> exception --> math +math <space> is --> math +math <"\\"-space> loop --> loop +math <"\\"-space> math --> math +math [ <"\\"-space> or <"\\"-space> else <"\\"-space> ] --> math binop +math [ <"\\"-space> or <"\\"-space> ] --> math binop +math <"\\"-space> private --> math +math <"\\"-space> separate --> math +math <indent-force> stmt <outdent-force> --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + +<force-backup> openlabel math closelabel <force> --> math + +or <indent-force> --> continuation + +private <indent-force> --> beginning + +proc <"\\"-space> math <space> is <"\\"-space> separate --> math +proc <"\\"-space> math <space> is <indent-force> --> declaration +proc <"\\"-space> math terminator --> stmt + +record <"\\"-space> at <"\\"-space> math terminator <indent-force> --> beginning +record <indent-force> --> beginning + +semi --> terminator + +stmt <force> stmt --> stmt + +when <"\\"-space> math arrow <indent-force> --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt <outdent-force> ending --> ending +whengroup stmt <outdent-force> whengroup --> whengroup + +where <indent> --> beginning + +with <"\\"-space> math --> math +with <"\\"-space> proc <"\\"-space> math --> math + +? ignore_scrap --> #1 + + +########################### Additional stuff for PolyAnna ################## + +# PolyAnna delimiters + +default mathness yes + +token --: category virtual translation <"\\R\\IG"> mathness no +token --| category annotation translation <"\\R\\IG"> mathness no +token <=> category arrow translation <"\\DA"> +token -> category binop translation <"\\RA"> + +# We might use these guys for PolyAnna + +# token [ category open +# token ] category close +# token { translation <"\\{"> category open +# token } translation <"\\}"> category close + + + +# Polyanna reserved words + +default mathness maybe translation <*> + +reserved based ilk math_like +reserved bound ilk math_like +reserved exists ilk math_like +reserved forall ilk math_like +reserved global ilk math_like +reserved mathforall ilk forall_like +reserved on ilk math_like +reserved such ilk math_like +reserved that ilk math_like +reserved trait ilk math_like +reserved virtual ilk separate_like +reserved where ilk where_like + +ilk forall_like translation <"\\forall"> category math mathness yes + + + +# The line below will cause scan_annotations.awk to generate code for +# scanning annotations and virtual text. The integer is the depth of nesting. +# (sp is short for "suspend parse", and is created when annotations are +# encountered in the midst of virtual text. +#scan_annotations 10 + +# recognize the end of a group of annotations +[ <"\\AN{"> annotation !(nl|sp) nl <"\\MC}\\MS\\R"> ] !annotation --> annotation_group !annotation + +# recognize the end of some lines of virtual text +[ <"\\VI{"> virtual !(nl|sp) nl <"\\MC}\\MS\\R"> ] !(virtual|annotation) --> virtual_group !(virtual|annotation) + +# ignore a group of annotations in the midst of virtual text +<"\\MC}\\MS\\R"> sp <force> annotation_group <force-"\\VI{"> virtual --> ignore_scrap +# if a virtual text terminates with a group of annotations, just turn the +# suspended parse into a newline---this terminates the virtual text. +[ sp ] annotation_group !virtual --> nl annotation_group !virtual + + +# put annotations or virtual text in a block by itself, and ignore it +# in other parsing. +<force> (annotation_group|virtual_group) <force> --> ignore_scrap + +# ignore newlines except in the special situations listed above +!(annotation|virtual|sp|busted_comment) nl --> #1 + + + + + + + +macros begin +\def\AN{\markpar{--|}} +\def\VI{\markpar{\frenchspacing--:}} +\let\AR=\Longrightarrow +\let\RA=\rightarrow +\let\DA=\Longleftrightarrow +\let\AS\K +\def\MG{\mathrel{\to}} + +\newbox\window +\newbox\icon +\newif\ifmarkdo +\newdimen\markh\markh=.83333333\baselineskip +\newdimen\saveindent +\newcount\saveind + +\def\markpar#1#2{\setbox\icon=\hbox{\.{#1 }}% +\saveindent=\hangindent +\saveind=\ind +\setbox\window=\vbox{\advance\hsize by -\wd\icon +\advance\hsize by -\saveindent +\global\ind=2\hangindent=\ind em +\hbox{This line will get peeled} +\noindent\kern\ind em\copy\bakk\ignorespaces#2}% +\hangindent=\saveindent +\global\ind=\saveind +\vbox{ +\splittopskip=\markh\vbadness=10000\setbox0=\vsplit\window to\markh +\loop \ifvoid\window\markdofalse\else\markdotrue\fi +\ifmarkdo +\hbox{\unhcopy\icon\vsplit\window to\markh} +\repeat +}} + +\input frames +macros end diff --git a/web/spiderweb/src/penelope/make b/web/spiderweb/src/penelope/make new file mode 100644 index 0000000000..d20e6ce373 --- /dev/null +++ b/web/spiderweb/src/penelope/make @@ -0,0 +1,5 @@ +#!/bin/csh -f +# awk -f scan_annotations.awk < a.spider > processed-a.spider +/bin/make -f SpiderMakefile $* +/bin/make -f ../master/WebMakefile \ + THETANGLE=adatangle THEWEAVE=adaweave SPIDER=processed-a.spider $* diff --git a/web/spiderweb/src/penelope/nesting.spider b/web/spiderweb/src/penelope/nesting.spider new file mode 100644 index 0000000000..ddf65041c5 --- /dev/null +++ b/web/spiderweb/src/penelope/nesting.spider @@ -0,0 +1,21 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +annotation [ !(nl|sp) nl annotation ] --> annotation #2 +annotation !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) #3 +annotation !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) #4 +annotation !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) !(nl|sp) #5 + + +# No nesting yet. + +virtual [ !(nl|sp) nl virtual ] --> virtual #2 +virtual !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) #3 +virtual !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) #4 +virtual !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) !(nl|sp) #5 + +virtual !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) sp annotation + diff --git a/web/spiderweb/src/penelope/processed-a.spider b/web/spiderweb/src/penelope/processed-a.spider new file mode 100644 index 0000000000..db6529bcbb --- /dev/null +++ b/web/spiderweb/src/penelope/processed-a.spider @@ -0,0 +1,418 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language Ada extension ada + +at_sign @ + +module definition stmt use math + +comment begin <dash-dash-space> end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin <dash-dash-"line"> end <""> + +default translation <*> mathness yes + +token identifier category math mathness maybe +token number category math mathness yes +token newline category nl translation <> mathness maybe +# newline mathness must be no to work with busted_comment +token pseudo_semi translation <> category semi mathness maybe + +macros begin +\let\R\relax +macros end + +# Delimiters +token & category binop translation <"\\amp"> +token ( category open +token ) category close +token * category binop +token + category unorbinop +token , category binop translation <",\\,"-opt-3> +token - category unorbinop +token . category binop +token / category binop +token : category binop +token ; category semi translation <";"-space-opt-2> +token < category binop +token = category binop +token > category binop +token | category binop translation <"\\mid"> + +# Compound delimiters + +token => category arrow translation <"\\AR"> +token .. category binop translation <"\\.{..}"> +token ** category binop +token := category binop translation <"\\mathbin{:=}"> +token /= translation <"\\I"> category binop +token >= translation <"\\G"> category binop +token <= translation <"\\L"> category binop +token << translation <"\\LL"> category openlabel +token >> translation <"\\GG"> category closelabel +token <> translation <"\\LG"> category math + +# Hacks no ', and this becomes a binary op +token ' category binop mathness no + +token # category math translation <"\\#"> +token -- category busted_comment mathness no translation <"\\C{"> + + + + +default mathness maybe translation <*> + +reserved abort ilk math_like +reserved abs ilk unop_like +reserved accept ilk proc_like +reserved access ilk math_like +reserved all ilk math_like +reserved and ilk and_like +reserved array ilk math_like +reserved at ilk at_like +reserved begin ilk begin_like +reserved body ilk math_like +reserved case ilk case_like +reserved constant ilk math_like +reserved declare ilk decl_like +reserved delay ilk math_like +reserved delta ilk math_like +reserved digits ilk math_like +reserved do ilk is_like +reserved else ilk else_like +reserved elsif ilk elsif_like +reserved end ilk end_like +reserved entry ilk proc_like +reserved exception ilk ex_like +reserved exit ilk math_like +reserved for ilk math_like +reserved function ilk proc_like +reserved generic ilk gen_like +reserved goto ilk math_like +reserved if ilk if_like +reserved in ilk unorbinop_like +reserved is ilk is_like +reserved limited ilk math_like +reserved loop ilk loop_like +reserved mod ilk binop_like +reserved new ilk separate_like +reserved not ilk unop_like +reserved null ilk math_like +reserved of ilk math_like +reserved or ilk or_like +reserved others ilk math_like +reserved out ilk math_like +reserved package ilk proc_like +reserved pragma ilk math_like +reserved private ilk private_like +reserved procedure ilk proc_like +reserved raise ilk math_like +reserved range ilk math_like +reserved record ilk record_like +reserved rem ilk binop_like +reserved renames ilk math_like +reserved return ilk math_like +reserved reverse ilk math_like +reserved select ilk begin_like +reserved separate ilk separate_like +reserved subtype ilk math_like +reserved task ilk proc_like +reserved terminate ilk math_like +reserved then ilk then_like +reserved type ilk math_like +reserved use ilk math_like +reserved when ilk when_like +reserved while ilk math_like +reserved with ilk with_like +reserved xor ilk binop_like + +ilk and_like translation <*> category and +ilk at_like translation <*> category at +ilk begin_like translation <*-indent> category beginning +ilk binop_like translation <"\\"-space-*-"\\"-space> category binop +ilk case_like translation <*> category case +ilk decl_like translation <*-indent> category declaration +ilk else_like translation <*> category else +ilk elsif_like translation <*> category elsif +ilk end_like translation <*> category close +ilk ex_like translation <*> category exception +ilk gen_like translation <*-indent> category generic +ilk if_like translation <*> category if +ilk is_like translation <*> category is mathness no +ilk loop_like translation <*> category loop +ilk math_like translation <*> category math +ilk or_like translation <*> category or +ilk private_like translation <*> category private +ilk proc_like translation <*> category proc +ilk record_like translation <*> category record +ilk separate_like translation <*> category separate +ilk then_like translation <*> category then +ilk unop_like translation <*-"\\"-space> category unop +ilk unorbinop_like translation <"\\"-space-*-"\\"-space> category resunorbinop +ilk when_like translation <*> category when +ilk where_like category where +ilk with_like translation <*> category with + + +# \MC means ``math close'' and sets \MS to ``math set'' +macros begin +\def\MC{\ifmmode\global\let\MS$\else\global\let\MS\relax\fi\relax\MS} +\def\LG{\mathord{<}\mathord{>}} +\let\IG=\ignorespaces +macros end + + + +busted_comment <"\\MC}\\MS\\R"-force> nl --> ignore_scrap +busted_comment ? --> busted_comment + +beginning <outdent-force> continuation <outdent-force> ending --> stmt +beginning <outdent-force> ending --> stmt +beginning <force> (stmt|ignore_scrap) --> beginning + +case <"\\"-space> math <"\\"-space> is <indent-force> --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation <force> (stmt|ignore_scrap) --> continuation +continuation <outdent-force> continuation --> continuation + + +declaration <outdent-force> beginning <outdent-force> continuation <outdent-force> ending --> stmt +declaration <outdent-force> beginning <outdent-force> ending --> stmt +declaration <outdent-force> ending --> stmt +declaration <force> (stmt|ignore_scrap) --> declaration + +else <indent-force> --> continuation +elsif <"\\"-space> math <"\\"-space> then <indent-force> --> continuation + +exception <indent-force> --> continuation + +generic <outdent-force> declaration --> declaration +generic <force> (stmt|ignore_scrap) --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen <indent-force> stmt --> beginning +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> else --> ifthen +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> close <"\\"-space> if --> math +ifthen <indent-force> <"\\"-space> math <"\\"-space> <outdent-force> elsif --> if + + +is --> math + +loop <indent-force> --> beginning + +math [ <"\\"-space> and <"\\"-space> then <"\\"-space> ] --> math binop +math [ <"\\"-space> and <"\\"-space> ] --> math binop + +math (binop|unorbinop) math --> math +math <"\\"-space> resunorbinop <"\\"-space> math --> math +(unorbinop|unop) math --> math +resunorbinop <"\\"-space> math --> math +# This doesn't apply in Ada: math unop --> math + +math arrow --> math +math binop <"\\"-space> exception --> math +math <space> is --> math +math <"\\"-space> loop --> loop +math <"\\"-space> math --> math +math [ <"\\"-space> or <"\\"-space> else <"\\"-space> ] --> math binop +math [ <"\\"-space> or <"\\"-space> ] --> math binop +math <"\\"-space> private --> math +math <"\\"-space> separate --> math +math <indent-force> stmt <outdent-force> --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + +<force-backup> openlabel math closelabel <force> --> math + +or <indent-force> --> continuation + +private <indent-force> --> beginning + +proc <"\\"-space> math <space> is <"\\"-space> separate --> math +proc <"\\"-space> math <space> is <indent-force> --> declaration +proc <"\\"-space> math terminator --> stmt + +record <"\\"-space> at <"\\"-space> math terminator <indent-force> --> beginning +record <indent-force> --> beginning + +semi --> terminator + +stmt <force> stmt --> stmt + +when <"\\"-space> math arrow <indent-force> --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt <outdent-force> ending --> ending +whengroup stmt <outdent-force> whengroup --> whengroup + +where <indent> --> beginning + +with <"\\"-space> math --> math +with <"\\"-space> proc <"\\"-space> math --> math + +? ignore_scrap --> #1 + + +########################### Additional stuff for PolyAnna ################## + +# PolyAnna delimiters + +default mathness yes + +token --: category virtual translation <"\\R\\IG"> mathness no +token --| category annotation translation <"\\R\\IG"> mathness no +token <=> category arrow translation <"\\DA"> +token -> category binop translation <"\\RA"> + +# We might use these guys for PolyAnna + +# token [ category open +# token ] category close +# token { translation <"\\{"> category open +# token } translation <"\\}"> category close + + + +# Polyanna reserved words + +default mathness maybe translation <*> + +reserved based ilk math_like +reserved bound ilk math_like +reserved exists ilk math_like +reserved forall ilk math_like +reserved global ilk math_like +reserved mathforall ilk forall_like +reserved on ilk math_like +reserved such ilk math_like +reserved that ilk math_like +reserved trait ilk math_like +reserved virtual ilk separate_like +reserved where ilk where_like + +ilk forall_like translation <"\\forall"> category math mathness yes + + + +# The line below will cause scan_annotations.awk to generate code for +# scanning annotations and virtual text. The integer is the depth of nesting. +# (sp is short for "suspend parse", and is created when annotations are +# encountered in the midst of virtual text. +#scan_annotations 10 + +# automatically generating productions... + + +# "annotation" expansion sequence + +annotation [ !(nl|sp) nl annotation ] --> annotation #2 +annotation !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) #3 +annotation !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) #4 +annotation !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) !(nl|sp) #5 +annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #6 +annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #7 +annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #8 +annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #9 +annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl annotation ] --> annotation !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #10 + +# "virtual" expansion sequence + +virtual [ !(nl|sp) nl virtual ] --> virtual #2 +virtual !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) #3 +virtual !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) #4 +virtual !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) !(nl|sp) #5 +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #6 +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #7 +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #8 +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #9 +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ !(nl|sp) nl virtual ] --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) #10 + +# "virtual" -- "annotation" expansion sequence + +virtual !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) sp annotation +virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) [ nl ] annotation --> virtual !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) !(nl|sp) sp annotation + + +# end of automatically generated productions + + +# recognize the end of a group of annotations +[ <"\\AN{"> annotation !(nl|sp) nl <"\\MC}\\MS\\R"> ] !annotation --> annotation_group !annotation + +# recognize the end of some lines of virtual text +[ <"\\VI{"> virtual !(nl|sp) nl <"\\MC}\\MS\\R"> ] !(virtual|annotation) --> virtual_group !(virtual|annotation) + +# ignore a group of annotations in the midst of virtual text +<"\\MC}\\MS\\R"> sp <force> annotation_group <force-"\\VI{"> virtual --> ignore_scrap +# if a virtual text terminates with a group of annotations, just turn the +# suspended parse into a newline---this terminates the virtual text. +[ sp ] annotation_group !virtual --> nl annotation_group !virtual + + +# put annotations or virtual text in a block by itself, and ignore it +# in other parsing. +<force> (annotation_group|virtual_group) <force> --> ignore_scrap + +# ignore newlines except in the special situations listed above +!(annotation|virtual|sp|busted_comment) nl --> #1 + + + + + + + +macros begin +\def\AN{\markpar{--|}} +\def\VI{\markpar{\frenchspacing--:}} +\let\AR=\Longrightarrow +\let\RA=\rightarrow +\let\DA=\Longleftrightarrow +\let\AS\K +\def\MG{\mathrel{\to}} + +\newbox\window +\newbox\icon +\newif\ifmarkdo +\newdimen\markh\markh=.83333333\baselineskip +\newdimen\saveindent +\newcount\saveind + +\def\markpar#1#2{\setbox\icon=\hbox{\.{#1 }}% +\saveindent=\hangindent +\saveind=\ind +\setbox\window=\vbox{\advance\hsize by -\wd\icon +\advance\hsize by -\saveindent +\global\ind=2\hangindent=\ind em +\hbox{This line will get peeled} +\noindent\kern\ind em\copy\bakk\ignorespaces#2}% +\hangindent=\saveindent +\global\ind=\saveind +\vbox{ +\splittopskip=\markh\vbadness=10000\setbox0=\vsplit\window to\markh +\loop \ifvoid\window\markdofalse\else\markdotrue\fi +\ifmarkdo +\hbox{\unhcopy\icon\vsplit\window to\markh} +\repeat +}} + +\input frames +macros end diff --git a/web/spiderweb/src/penelope/scan_annotations.awk b/web/spiderweb/src/penelope/scan_annotations.awk new file mode 100644 index 0000000000..a4b82ee8b3 --- /dev/null +++ b/web/spiderweb/src/penelope/scan_annotations.awk @@ -0,0 +1,81 @@ +# used to print the code that ignores <<nl annotation>> in annotations +# and ignores <<nl virtual>> in virtual text +# Assumes the following categories +# nl == newline token (closes virtual text and annotations) +# sp == suspend parse -- used to suspend parsing of virtual +# text while we scan an annotation +# virtual = --: (opens virtual text) +# annotation = --| (opens annotations) +# + +# copy everything +{ print } + +# Announce ourselves + +/^#scan_annotations [0-9]*$/ { + print "" + print "# automatically generating productions..." + print "" + } + +# +# ignore <<nl annotation>> in annotations +# +/^#scan_annotations [0-9]*$/ { + print "" + print "# \"annotation\" expansion sequence" + print "" + $nlsp = "" + for (i = 2; i <= $2; i++) + { + printf "annotation " $nlsp + printf "[ !(nl|sp) nl annotation ] --> annotation " + printf $nlsp "#" i + printf "\n" + $nlsp = $nlsp "!(nl|sp) " + } +} +# +# ignore <<nl virtual>> in virtual text +# +/^#scan_annotations [0-9]*$/ { + print "" + print "# \"virtual\" expansion sequence" + print "" + $nlsp = "" + for (i = 2; i <= $2; i++) + { + printf "virtual " $nlsp + printf "[ !(nl|sp) nl virtual ] --> virtual " + printf $nlsp "#" i + printf "\n" + $nlsp = $nlsp "!(nl|sp) " + } +} +# +# suspend parsing of virtual text when an annotation is encountered +# +/^#scan_annotations [0-9]*$/ { + print "" + print "# \"virtual\" -- \"annotation\" expansion sequence" + print "" + $nlsp = "" + for (i = 2; i <= $2; i++) + { + $nlsp = $nlsp "!(nl|sp) " + printf "virtual " $nlsp + printf "[ nl ] annotation --> virtual " + printf $nlsp "sp annotation" + printf "\n" + } + print "" +} + +# Announce our passing + +/^#scan_annotations [0-9]*$/ { + print "" + print "# end of automatically generated productions" + print "" + } diff --git a/web/spiderweb/src/penelope/stacks.web b/web/spiderweb/src/penelope/stacks.web new file mode 100644 index 0000000000..c37c65b9d0 --- /dev/null +++ b/web/spiderweb/src/penelope/stacks.web @@ -0,0 +1,445 @@ +\message{OK, entering \string\batchmode...} +\batchmode +\overfullrule0pt +%\magnification=\magstep2 +%\input awebmac +\input enumerate.sty +\def\VC#1#2{{\enumerate\item #1\endenumerate\par}{$>\!\!>$\ #2\par}} +%\parindent=0pt\parskip=0.5\baselineskip +\let\maps\rightarrow +\def\title{A Generic Stack Package} + +@*Stacks. +The idea is to implement, and to prove part of, a simple stack package. +We write a Larch trait for the stacks, +we use terms of that trait to specify our package. + In the package body we write down an explicit +representation invariant |invar| and an explicit abstraction function +|abstraction|, and we use them to prove the package \`a la Hoare. +The package specification refers only to the abstract trait, +and our software will automatically perform the translation required +to introduce explicit invariants and abstraction functions in the +package body. + +@*Theory of stacks. +We use the following theory: +%\input stacktrait.pretty + + +@*Specification. +We now use the |Stack_theory| trait to specify a package. +The phrase +|with trait Stack_theory| +makes the |Stack_theory| trait visible and +the phrase +|based on stack| +makes the sort |stack| from |Stack_theory| the abstract sort |stack'ABSTRACT|. +We also use the |element| sort to represent the private type |element|. +% ACK! What proof obligations does this give? + +In the package {\it specification}, all terms of type |stack| are +specified with terms of type |Stacks_theory.stack|. +In the package {\it body}, we will specify terms of type |stack| with +terms of a sort corresponding to the private type of stack (in this +instance, a record type). +We will provide an abstraction function from terms of the record trait +to terms of the stack trait, and an invariant function from terms of +the record trait to |boolean|. +@c@0 +generic + type element is private; --| based on element; + length: natural := 100; +package stacks is + --| with trait Stack_theory; + type stack is private; +@/ --| based on stack; + overflow, underflow: exception; +@# + function empty_stack return stack; + --| where return new_stack; end where; + +@# + function pushit(s:stack; e:element) return stack; + --| where + --| return push(s,e); + --| raise overflow <=> size(s) = length; + --| end where; +@# + function popit(s:stack) return stack; + --| where + --| return pop(s); + --| raise underflow <=> size(s) = 0; + --| end where; +@# + function topit(s:stack) return element; + --| where + --| return top(s); + --| raise underflow <=> size(s) = 0; + --| end where; +@# + function isEmpty(s:stack) return boolean; + --| where + --| return is_empty(s); + --| end where; + +private + subtype stack_range is natural range 0.. length - 1; + type stack_array is array(stack_range) of element; + type stack is + record + l: natural; -- length + a: stack_array; --stack + end record; + +end stacks; +@*Implementation. +We break the implementation into pieces so we can discuss them one at +a time. + +Within the hidden part of the package, |stack| will stand for the +concrete type (or sort), |stack'CONCRETE|. +Outside, in the specification, |stack| will stand for the abstract +type (or sort), |stack'ABSTRACT|. +We use types in actual Ada code, and sorts in annotations and virtual +functions. + +@c +generic + type element is private; + length: natural := 100; +package body stacks is +@<Abstraction and invariants@>@; +@<Implementation of |empty_stack|@>@; +@<Implementation of |pushit|@>@; +@<Implementation of |popit|@>@; +@<Implementation of |topit|@>@; +@<Implementation of |isEmpty|@>@; +end stacks; +@ Here we make explicit the representation invariant |invar| and the +abstraction function |abstraction|. +These are virtual functions, and templates for them will be generated +automatically from the package specification. +These functions will appear in the annotations for the operations of +the package, which will also have been translated from the package +specification. + +The invariant requires only that the length be within sensible bounds. +(I have ignored the problem of definedness throughout the example.) +The abstraction function works by peeling off the top element, and +pushing it onto the abstraction of what's left. +This works all the way down to |s.l=0|, for which the abstraction is +|new_stack|. + +The templates for |invar| and |abstraction| are generated +automatically. + +@<Abstraction...@>= +--:function invar(s:stack) return boolean +--| where +--| return 0<=s.l<=length; -- |and| some definedness condition +--| end where; +--:is virtual; + +--:function abstraction(s:stack) return stack'ABSTRACT +--| where +--| in invar(s); +--| return if s.l=0 then +--| new_stack@; +--| else +--| push(abstraction(s[l=>l-1]),s.a(s.l))@; +--| end if; +--| end where; +--:is virtual; + +@ To implement |empty_stack| we return a stack of length zero. + +@<Implementation of |empty_stack|@>= +function empty_stack return stack +--| where +--| return s:stack such that +--| invar(s) and +--| abstraction(s)=new_stack; +--| end where; +is + empty: stack; +begin + empty.l := 0; + return empty; +end empty_stack; + +@*Proof of |empty_stack|. +Here and elsewhere we will use the notation |@@return| to denote the return +value. +Predicate transformation of the postcondition leaves the following verification +condition: +\VC{|true|}{|invar(empty) and abstraction(empty)=new_stack|} + +We split and get +\VC{|true|}{|invar(empty)|} +and, expanding +\VC{|true|}{|0<=empty.l and empty.l <= length|} +and substituting for |empty.l| (on what basis?) +\VC{|true|}{|0<=0 and 0 <= length|} +from which +\VC{|true|}{|true|} +because of the property |0<=n| for any natural number |n|. + +The second verification condition is +\VC{|true|}{|abstraction(empty)=new_stack|} +We expand |abstraction|, spawning the new VC +\VC{|true|}{|invar(empty)|} +for which we can refer to the earlier proof. +We are left with +\VC{|true|}{|if empty.l=0 then new_stack else + push(abstraction(empty[l=>l-1]),empty.a(empty.l)); + end if = new_stack;|} +Which rewrites to +\VC{|true|}{|new_stack=new_stack|} + + +@ Here we have to check for overflow, but there are really no surprises. +@<Implementation of |pushit|@>= +function pushit(s:stack; e:element) return stack +--| where +--| in invar(s); +--| return r:stack such that +--| invar(r) and +--| abstraction(r)=push(abstraction(s),e); +--| end where; +is + t: stack; +begin + if s.l=length then raise overflow; end if; + t.l := s.l+1; + t.a := s.a; + t.a(t.l) := e; + return t; +end empty_stack; + +@*Predicate transformation of |pushit|. +Here we have ignored the possibility of abnormal termination. + +I've written intermediate conditions in between the statements to +which they apply. +The predicate transformation rules I've used are completely +informal. + + +@c +function pushit(s:stack; e:element) return stack +--| where +--| in invar(s); +--| return r:stack such that +--| invar(r) and +--| abstraction(r)=push(abstraction(s),e); +--| raise overflow <=> size(abstraction(s)) = length; +--| end where; +is + t: stack; +begin +--| s.l /= length and +--| invar(t[l=>s.l+1;a=>s.a;a(l)=>e]) and +--| abstraction(t[l=>s.l+1;a=>s.a;a(l)=>e])=push(abstraction(s),e); + if s.l=length then raise overflow; end if; +--| invar(t[l=>s.l+1;a=>s.a;a(l)=>e]) and +--| abstraction(t[l=>s.l+1;a=>s.a;a(l)=>e])=push(abstraction(s),e); + t.l := s.l+1; +--| invar(t[a=>s.a;a(l)=>e]) and +--| abstraction(t[a=>s.a;a(l)=>e])=push(abstraction(s),e); + t.a := s.a; +--| invar(t[a(l)=>e]) and +--| abstraction(t[a(l)=>e])=push(abstraction(s),e); + t.a(t.l) := e; +--| invar(t) and +--| abstraction(t)=push(abstraction(s),e); + return t; +--| invar(@@return) and +--| abstraction(@@return)=push(abstraction(s),e); +end empty_stack; + +@*Proof of |pushit|. +We're going to make heavy use of a (nonexistent) theory of records. +Record states are as in Anna; +informally they behave just as you would think. + +We first rewrite the term involving |t| into a simpler and more useful +form: +$$\vbox{\noindent +|t[l=>s.l+1;a=>s.a;a(l)=>e]| rewrites to +|s[l=>l+1;a(l)=>e]|. +}$$ + + +After this simplification we have this verification condition: +\VC{| +invar(s)|\item +|not (size(abstraction(s)) = length)|} +{| +s.l /= length and +invar(s[l=>l+1;a(l)=>e]) and +abstraction(s[l=>l+1;a(l)=>e])=push(abstraction(s),e) +|} +We'll tackle one conjunct at a time. + +@ {\it First conjunct.} +We begin by proving a lemma about |size|: +\VC{|invar(s)|} +{|size(abstraction(s))|$\simeq$|s.l|} +The proof is by type induction on the predefined type |natural|. +We omit it here. + +Once we have the |size| lemma we rewrite the VC for the first conjunct as: +\VC{| +invar(s)|\item +|not (s.l = length)|} +{|s.l /= length|} +The proof is by the laws (not stated) for |=| and |/=|. + +@ {\it Second Conjunct.} +Again we apply the |size| lemma. +\VC{| +invar(s)|\item +|not (s.l = length)|} +{| +invar(s[l=>l+1;a(l)=>e])|} +Expanding the definition of |invar| in the hypothesis and the conclusion yields +\VC{| +0<=s.l and s.l <= length|\item +|not (s.l = length)|} +{| +0<=s[l=>l+1;a(l)=>e].l and +s[l=>l+1;a(l)=>e].l<=length +|} +and we again exploit the theory of records to rewrite as +\VC{| +0<=s.l and s.l <= length|\item +|not (s.l = length)|} +{| +0<=s.l+1 and +s.l+1<=length +|} +And the proof follows by |and|-splitting hypotheses and conclusion and by +applying the laws of arithmetic. + +@ {\it Third conjunct.} +This is the interesting part. +We expand the definition of |abstraction| on the left hand side of the +conclusion. +This spawns a VC showing that the argument to |abstraction| satisfies +|invariant|, but we did that earlier. + +\VC{| +invar(s)|\item +|not (size(abstraction(s)) = length)|} +{| +if s[l=>l+1;a(l)=>e].l=0 then new_stack else +push(abstraction(s[l=>l+1;a(l)=>e;l=>l-1]), +s[l=>l+1;a(l)=>e].a(s[l=>l+1;a(l)=>e].l)) end if + =push(abstraction(s),e) +|} +and, rewriting according to the theory of records +(especially +|s[l=>l+1;a(l)=>e].a(s[l=>l+1;a(l)=>e].l)| +rewrites to +|s[l=>l+1;a(s.l+1)=>e].a(s.l+1)| +which rewrites to |e|): +\VC{| +invar(s)|\item +|not (size(abstraction(s)) = length)|} +{| +if s.l+1=0 then new_stack else +push(abstraction(s[a(l+1)=>e]),e) end if + =push(abstraction(s),e) +|} +Applying the laws of natural numbers we have +\VC{| +invar(s)|\item +|not (size(abstraction(s)) = length)|} +{| +push(abstraction(s[a(l+1)=>e]),e) = push(abstraction(s),e) +|} + + +And now we show by a lemma that +\VC{|invar(s)|\item |s.l/=length|} +{ +|abstraction(s[a(l+1)=>e])|$\simeq$|abstraction(s)| +} +which is sufficient. +The proof of the lemma is by induction over |l| (type induction of the +predefined type |natural|). + + + + +@ @<Implementation of |popit|@>= +function popit(s:stack) return stack +--| where +--| in invar(s); + --| return c:stack such that invar(c) and + --| abstraction(c)=pop(abstraction(s)); + --| raise underflow <=> size(abstraction(s)) = 0; +--| end where; +is + t: stack; +begin + if s.l=0 then raise underflow; end if; + t := s; + t.l := t.l-1; + return t; +end popit; + +@ @<Implementation of |topit|@>= +function topit (s:stack) return element +--| where +--| in invar(s); +--| return top(abstraction(s)); +--| end where; +is +begin + if s.l=0 then raise underflow; end if; + return s.a(s.l); +end topit; + +@ @<Implementation of |isEmpty|@>= + function isEmpty(s:stack) return boolean + --| where + --| in invariant(s); + --| return is_empty(abstraction(s)); + --| end where; + is + begin + return s.l=0; + end isEmpty; +@ Predicate transformation of isEmpty. +@c + function isEmpty(s:stack) return boolean + --| where + --| in invariant(s); + --| return is_empty(abstraction(s)); + --| end where; + is + begin + --| (s.l=0)=is_empty(abstraction(s)) + return s.l=0; + --| @@return=is_empty(abstraction(s)) + end isEmpty; + +@ Proof of isEmpty. +\VC{|invariant(s)|}{|s.l=0 =is_empty(abstraction(s))|} +Expanding |abstraction(s)|, +\VC{|invariant(s)|}{|s.l=0 =is_empty(if s.l=0 then nil + else cons(abstraction(s[l=>l-1]),l.a(s.l-1)))|} +Simplifying, +\VC{|invariant(s)|}{|(s.l=0)=if s.l=0 then is_empty(nil) + else is_empty(cons(abstraction(s[l=>l-1]),l.a(s.l-1)))|} +which we can rewrite as +\VC{|invariant(s)|}{|(s.l=0)=if s.l=0 then true + else is_empty(cons(abstraction(s[l=>l-1]),l.a(s.l-1)))|} +Simplifying, +\VC{|invariant(s)|}{|true|} + + +@*Index. +This is an index of all the identifiers used in the program. +The numbers are section numbers, not page numbers.
\ No newline at end of file diff --git a/web/spiderweb/src/postscript/README b/web/spiderweb/src/postscript/README new file mode 100644 index 0000000000..ab9885866e --- /dev/null +++ b/web/spiderweb/src/postscript/README @@ -0,0 +1,10 @@ +This is a Spider description and set of change files for a PostScript WEB +done by Dave Love, love@daresbury.ac.uk. Originally done as practice -- +is it useful? + +You need to alter the master/WebMakefile to incorporate change files and +not to zap them if you do `make clean'. My version is included here. + +outline.ps1 is a copy of the result of tangling outline.web, to be +included in the example. The name was changed since dvitops will make +me an outline.ps from the TeX. diff --git a/web/spiderweb/src/postscript/WebMakefile.new b/web/spiderweb/src/postscript/WebMakefile.new new file mode 100644 index 0000000000..2067064dda --- /dev/null +++ b/web/spiderweb/src/postscript/WebMakefile.new @@ -0,0 +1,147 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +# Modified by Dave Love, Daresbury Lab for local setup and to incorporate +# change files + +#HOME=/nfs/dlsa/usr10/fx# # Make no longer inherits environment vars +# (it does inherit env vars on my system!) +THETANGLE=tangle +THEWEAVE=weave +SPIDER=any.spider +WEAVECHANGEFILES= +TANGLECHANGEFILES= +# +DVI=dvi +CFLAGS=-DDEBUG -g -DSTAT + +# CPUTYPE is a grim hack that attempts to solve the problem of multiple +# cpus sharing a file system. In my environment I have to have different +# copies of object and executable for vax, sun3, next, iris, and other +# cpu types. If you will be using Spidery WEB in a homogenous processor +# environment, you can just set CPUTYPE to a constant, or eliminate it +# entirely. +# +# In my environment, the 'cputype' program returns a string that +# describes the current processor. That means that the easiest thing +# for you to do is to define a 'cputype' program that does something +# sensible. A shell script that says 'echo "vax"' is fine. + +CPUTYPE=`cputype` + +# Change the following three directories to match your installation +# +# the odd placement of # is to prevent any trailing spaces from slipping in + +WEBROOT=$(HOME)/spiderweb# # root of the WEB source distribution +DEST=$(HOME)/bin# # place where the executables go +MACROS=$(HOME)/tex/inputs# # place where the macros go + +MASTER=$(WEBROOT)/master# # master source directory +OBDIR=$(MASTER)/$(CPUTYPE)# # common object files + +TANGLESRC=tangle +CTANGLE=ceetangle -I$(MASTER) +CWEAVE=ceeweave -I$(MASTER) +AWKTANGLE=awktangle -I$(MASTER) +COMMONOBJS=$(OBDIR)/common.o $(OBDIR)/pathopen.o +COMMONC=$(MASTER)/common.c $(MASTER)/pathopen.c +COMMONSRC=$(COMMONC) $(MASTER)/spider.awk + + + +# Our purpose is to make tangle and weave + +web: tangle weave + +tangle: $(COMMONOBJS) $(TANGLESRC).o + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + +weave: $(COMMONOBJS) weave.o + cc $(CFLAGS) -o $(DEST)/$(THEWEAVE) $(COMMONOBJS) weave.o + + +source: $(TANGLESRC).c $(COMMONSRC) # make tangle.c and common src, then clean + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.web weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + +# Here is how we make the common stuff + +$(MASTER)/common.c: $(MASTER)/common.web # no change file + $(CTANGLE) $(MASTER)/common + +$(OBDIR)/common.o: $(MASTER)/common.c + cc $(CFLAGS) -c $(MASTER)/common.c + mv common.o $(OBDIR) + + +$(MASTER)/pathopen.c: $(MASTER)/pathopen.web # no change file + $(CTANGLE) $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +$(OBDIR)/pathopen.o: $(MASTER)/pathopen.c + cc $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(OBDIR) + + +## Now we make the tangle and weave source locally + +$(TANGLESRC).c: $(MASTER)/$(TANGLESRC).web $(MASTER)/common.h grammar.web $(TANGLECHANGEFILES) + -/bin/rm -f $(TANGLESRC).web + ln $(MASTER)/$(TANGLESRC).web $(TANGLESRC).web +# chmod -w $(TANGLESRC).web + $(CTANGLE) $(TANGLESRC) $(TANGLECHANGEFILES) + +weave.c: $(MASTER)/weave.web $(MASTER)/common.h grammar.web $(WEAVECHANGEFILES) + -/bin/rm -f weave.web + ln $(MASTER)/weave.web weave.web +# chmod -w weave.web + $(CTANGLE) weave $(WEAVECHANGEFILES) + +## Here's where we run SPIDER to create the source + +grammar.web: $(MASTER)/cycle.awk $(MASTER)/spider.awk $(SPIDER) + echo "date" `date` | cat - $(SPIDER) | awk -f $(MASTER)/spider.awk + cat $(MASTER)/transcheck.list trans_keys.unsorted | awk -f $(MASTER)/transcheck.awk + awk -f $(MASTER)/cycle.awk < cycle.test + sort *.unsorted | awk -f $(MASTER)/nodups.awk +# mv *web.tex $(MACROS) + +## We might have to make spider first. + +$(MASTER)/spider.awk: $(MASTER)/spider.web + $(AWKTANGLE) $(MASTER)/spider + mv cycle.awk nodups.awk transcheck.awk $(MASTER) + rm junk.list + + +# $(MASTER)/cycle.awk: $(MASTER)/cycle.web # making spider also makes cycle +# $(AWKTANGLE) $(MASTER)/cycle + + +# This cleanup applies to every language + +clean: + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.web weave.web common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + + + +# booting the new distribution +boot: + cd ../master; rm -f *.o; for i in $(COMMONC); do \ + cc $(CFLAGS) -c $$i; \ + mv *.o $(OBDIR) ; \ + done; cd ../c + cc $(CFLAGS) -c $(TANGLESRC).c; \ + cc $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + + diff --git a/web/spiderweb/src/postscript/local.guide b/web/spiderweb/src/postscript/local.guide new file mode 100644 index 0000000000..f5fb55995c --- /dev/null +++ b/web/spiderweb/src/postscript/local.guide @@ -0,0 +1,72 @@ +%-*-TeX-*- +% Copyright 1989, David Love, SERC Daresbury Laboratory +\def\ps{{\sc PostScript}} +\def\web{{\tt WEB}} +\font\sc=cmcsc10 +\centerline{{\bf Local guide for PS}\web} +\vskip5ex +\centerline{David Love, SERC Daresbury Laboratory ({\tt +love@daresbury.ac.uk})} +\vskip5ex +\noindent +This note describes the restrictions on the \ps\ code imposed by +this implementation of \web\ for \ps, the treatment of the \web\ +source by {\tt TANGLE} and {\tt WEAVE} and points out a useful piece +of self-referential treatment of the code. + +\beginsection Restrictions on names + +There are restrictions on the characters allowed in names. Apart from +alphamerics and underscores, only {\tt !\$\&*-} are allowed. These +should allow some messing around defining silly-looking private names +as well as allowing {\tt -} as a `word' separator. + +\beginsection {\tt WEAVE} treatment of code + +Only rather limited pretty-printing is possible as the semantics of a +\ps\ expression are so difficult to establish. What is done +is:\footnote{*}{This is like GNUEmacs' \ps\ grinding, I discover.} +\item{$\bullet$} Newlines in the source are obeyed. Consecutive +newlines are replaced by a `bigskip'---newline with extra vertical +space. +\item{$\bullet$} \ps\ names are printed in math, numbers in +roman, strings in {\tt \char'134ttex}. +\item{$\bullet$} The only keywords which are +recognised and to which meaning is attached are {\it def}, {\it +begin}, {\it end}. A literal name which is {\it def\/}ed has its +index entry underlined. +\item{$\bullet$} Blocks delimited by {\tt +begin} $\ldots$ {\tt end}, {\tt \char'173} $\ldots$ {\tt \char'175}, +{\tt [} $\ldots$ {\tt ]}, {\tt <} $\ldots$ {\tt >} are indented. +\item{$\bullet$} The indentation may be controlled using the special +tokens {\tt =>} and {\tt <=} respectively to increase and decrease the +indentation level by one. They tangle to nothing and are not valid +names anyway under the rules above. They should be placed (anywhere) +on the line {\it before} the one to be in/outdented. A typical use +might be to indent conditional code. Maybe these frigs should be replaced +by {\tt WEB} control codes at some stage, although you can always send +the control sequences through using {\tt @t}. + +\beginsection Demonstration of procedure results + +Remember that the {\tt \char'134psfig} macro allows you to include +\ps\ into \TeX\ documents (if you have a suitable {\tt DVI} to \ps\ +backend). Thus you can include the {\tt TANGLE}d {\tt WEB} into the +{\tt WEAVE}d output to show example results of your code. + +\beginsection \ps\ file conventions + +The {\tt \%!}\ comment often required at the beginning of a \ps\ file +is inserted automatically into the {\tt TANGLE}d output. There is no +other built-in support for the conventional structure of \ps\ files. +In particular, you may need to get a {\tt \%\%BoundingBox:}\ comment +in the output near the start---if you're using {\tt \char'134psfig}, +for instance. This can be achieved by using the {\tt @=} control +sequence. + +\beginsection Example + +An example of a literate re-write of a \ps\ exmaple is given in {\tt +outline.web}. It demonstrates inclusion of the results in the +documentation. +\bye diff --git a/web/spiderweb/src/postscript/make b/web/spiderweb/src/postscript/make new file mode 100644 index 0000000000..709f7d30cc --- /dev/null +++ b/web/spiderweb/src/postscript/make @@ -0,0 +1,5 @@ +#!/bin/csh -f +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=pstangle THEWEAVE=psweave SPIDER=ps.spider \ + WEAVECHANGEFILES=weave.ch TANGLECHANGEFILES=tangle.ch \ + HOME=$HOME CFLAGS='-DC_FLOATING_POINT' $* diff --git a/web/spiderweb/src/postscript/outline.ps1 b/web/spiderweb/src/postscript/outline.ps1 new file mode 100644 index 0000000000..070d410dee --- /dev/null +++ b/web/spiderweb/src/postscript/outline.ps1 @@ -0,0 +1,212 @@ +%! +%3: + +% 21 "bigtest.web" + +%%BoundingBox: 18 18 577 824 + +%:3 +%4: + +% 25 "bigtest.web" + +% 26 "bigtest.web" + /makeoutlinedict 7 dict def + +%:4 +%5: + +% 34 "bigtest.web" + +% 35 "bigtest.web" + /MakeOutlineFont +{makeoutlinedict begin +%6: + +% 50 "bigtest.web" + +% 51 "bigtest.web" + /uniqueid exch def + /strokewidth exch def + /newfontname exch def + /basefontname exch def + +%:6 + +% 37 "bigtest.web" + +%7: + +% 56 "bigtest.web" + +% 57 "bigtest.web" + /basefontdict basefontname findfont def + +%:7 + +% 38 "bigtest.web" + +%8: + +% 59 "bigtest.web" + +% 60 "bigtest.web" + /numentries basefontdict maxlength 1 add def + +%:8 + +% 39 "bigtest.web" + +%9: + +% 65 "bigtest.web" + +% 66 "bigtest.web" +basefontdict /UniqueID known not +{ /numentries numentries 1 add def}if + +%:9 + +% 40 "bigtest.web" + +%10: + +% 69 "bigtest.web" + +% 70 "bigtest.web" + /outfontdict numentries dict def + +%:10 + +% 41 "bigtest.web" + +%11: + +% 72 "bigtest.web" + +% 73 "bigtest.web" +basefontdict +{exch dup /FID ne +{exch outfontdict 3 1 roll put} +{pop pop} +ifelse +}forall + +%:11 + +% 43 "bigtest.web" + +%12: + +% 85 "bigtest.web" + +% 86 "bigtest.web" +outfontdict /FontName newfontname put +outfontdict /PaintType 2 put +outfontdict /StrokeWidth strokewidth put +outfontdict /UniqueID uniqueid put + +%:12 + +% 44 "bigtest.web" + +%13: + +% 93 "bigtest.web" + +% 94 "bigtest.web" +newfontname outfontdict definefont pop + +%:13 + +% 45 "bigtest.web" + +end +}def + +%:5 +%14: + +% 100 "bigtest.web" + +% 101 "bigtest.web" + /Helvetica-Bold /Helvetica-Outline1%15: + +% 110 "bigtest.web" + +% 111 "bigtest.web" + 1000 54 div + +%:15 + +% 101 "bigtest.web" + +%16: + +% 116 "bigtest.web" + +% 117 "bigtest.web" + /Helvetica-Bold findfont dup /UniqueID known +{ /UniqueID get 1 add} +{pop 1} +ifelse +%:16 + +% 102 "bigtest.web" + +MakeOutlineFont + +%:14 +%17: + +% 122 "bigtest.web" + +% 123 "bigtest.web" + /Helvetica-Outline1 findfont 36 scalefont setfont +72 504 moveto(outline)show + /Helvetica-Outline1 findfont 54 scalefont setfont +(outline)show + +%:17 +%18: + +% 133 "bigtest.web" + +% 134 "bigtest.web" + /Helvetica-Bold /Helvetica-Outline2 1000 36 div +%16: + +% 116 "bigtest.web" + +% 117 "bigtest.web" + /Helvetica-Bold findfont dup /UniqueID known +{ /UniqueID get 1 add} +{pop 1} +ifelse +%:16 + +% 135 "bigtest.web" + +MakeOutlineFont + +%:18 +%19: + +% 139 "bigtest.web" + +% 140 "bigtest.web" + /Helvetica-Outline2 findfont 36 scalefont setfont +72 444 moveto(outline)show + /Helvetica-Outline2 findfont 54 scalefont setfont +(outline)show + +%:19 +%20: + +% 146 "bigtest.web" + +% 147 "bigtest.web" +showpage + +%:20 + diff --git a/web/spiderweb/src/postscript/outline.web b/web/spiderweb/src/postscript/outline.web new file mode 100644 index 0000000000..b9f90b78ae --- /dev/null +++ b/web/spiderweb/src/postscript/outline.web @@ -0,0 +1,162 @@ +% Copyright 1989, David Love, SERC Daresbury Laboratory under the same +% conditions as the Spider distribution + +\def\title{PSWEB demonstration -- outline font} +\def\ps{{\sc PostScript}} + +@*Introduction. +As a simple example of the use of \ps\ \.{WEB} we'll do a +literate re-write of {\sl Program 16 / Making an Outline Font} from the +Adobe blue {\sl Cookbook}, p~199. Most of the text will be directly lifted +from that example. +Compare this with the original! +The \ps\ convention of writing, for instance, |MakeOutlineFont| instead +of the form |make_outline_font| has been carried over from the original +example just this once, contrary to Knuthian lore and my preference. + +@*2Purpose. +This program defines a general procedure to take one of the built-in +fonts and convert it to an outline font. +(This program will also work for downloadable fonts available from +Adobe Systems, Inc.). + +@ We need to write out a suitable bounding box comment for \.{\\psfig}. +@u +@=%%BoundingBox: 18 18 577 824@> + +@ Local storage for the procedure |MakeOutlineFont|. +@u +/makeoutlinedict 7 dict def + +@*2Function definition and use. +|MakeOutlineFont| takes one of the built-in filled fonts and makes an outlined +font out of it. +It takes four arguments: the name of the font on which to base the outline +version, the new name for the outline font, a stroke width to use on the +outline and a unique ID. +@u +/MakeOutlineFont =>% base\_name new\_name stroke\_width ID + { makeoutlinedict begin + @<stash the arguments@> + @<get dictionary of font on which outline version will be based@> + @<determine how large new font dictionary should be@> + @<make sure there is room for the unique ID field@> + @<create dictionary to hold description for outline font@> + @<copy entries in base font dictionary to outline dictionary, except + for the FID@> + @<miscellaneous inserts into the new dictionary@> + @<make new font@> + end +} def + +@ Four arguments as described above. +@<stash...@>= +/uniqueid exch def +/strokewidth exch def +/newfontname exch def +/basefontname exch def + +@ @<get dictionary...@>= +/basefontdict basefontname findfont def + +@ @<determine how large...@>= +/numentries basefontdict maxlength 1 add def + +@ (Not all fonts have unique ID fields initially. +In particlular, the built-in fonts in \ps\ version 23.0 don't.) + +@<make sure there is room...@>= +basefontdict /UniqueID known not => + {/numentries numentries 1 add def} if + +@ @<create dictionary...@>= +/outfontdict numentries dict def + +@ @<copy entries...@>= +basefontdict => + { exch dup /FID ne +{exch outfontdict 3 1 roll put} +{pop pop} % ignore the FID pair +ifelse +} forall + +@ We need to 1) insert the new name into the dictionary +2) change the paint type to outline +3) insert the stroke width into the dictionary +4) insert the new unique ID + +@<miscellaneous inserts...@>= +outfontdict /FontName newfontname put +outfontdict /PaintType 2 put +outfontdict /StrokeWidth strokewidth put +outfontdict /UniqueID uniqueid put + +@ In making the outline dictionary into a \ps\ font we ignore the +modified dictionary returned on the stack by |definefont|. +@<make new font@>= +newfontname outfontdict definefont pop + +@*Use of the procedure and determining new IDs. +We'll make a new font |Helvetica-Outline1| derived from |Helvetica-Bold|. +The results will appear below. + +@u +/Helvetica-Bold @!/Helvetica-Outline1 @<define stroke width@> +@<determine unique ID@> +MakeOutlineFont + +@ The stroke width is always specified in the character coordinate system +(1000 units). +The value specified here will yield a one point wide outline when the font is +scaled to 54 points in size. +Note that this outline width changes with different point sizes. +@^stroke width@> +@<define stroke width@>= +1000 54 div + +@ To determine the unique id: +If the `base' font already contains a unique ID, add a unique constant to it, +otherwise pick a unique integer and leave that value on the operand stack. +@<determine unique ID@>= +/Helvetica-Bold findfont dup /UniqueID known => + {/UniqueID get 1 add} +{pop 1} +ifelse +@ So here are two sizes with this stroke width. +@u +/Helvetica-Outline1 findfont 36 scalefont setfont => +72 504 moveto (outline) show <= +/Helvetica-Outline1 findfont 54 scalefont setfont => + (outline) show + +@ Now we'll do one with a different stroke width. +The width of 1000/36 used now yields a one point wide outline when the font +is scaled to 36 point in size. +It yields a 1.5 point outline when the font is scaled to 54 points +in size ($54/36=1.5$).@^stroke width@> +@u +/Helvetica-Bold @!/Helvetica-Outline2 1000 36 div +@<determine unique ID@> +MakeOutlineFont + +@ And use the different stroke width: +@u +/Helvetica-Outline2 findfont 36 scalefont setfont => +72 444 moveto (outline) show <= +/Helvetica-Outline2 findfont 54 scalefont setfont => + (outline) show + +@ Finish off the example: +@u +showpage + +@*1Results of the examples. +The results of including the \.{TANGLE}d version of this \.{WEB} source +into the \.{WEAVE} output using the \.{\\psfig} macro and a suitable +\.{DVI} to \ps\ converter are given here. The example has been shrunken +to get it on the page and may be faint on a write-white engine with the +stroke widths defined above.@^stroke width@>@^write-white@> +\input psfig.sty +\centerline{\psfig{figure=outline.ps1,height=6in}} + +@*Index. diff --git a/web/spiderweb/src/postscript/ps.spider b/web/spiderweb/src/postscript/ps.spider new file mode 100644 index 0000000000..b4a095bed3 --- /dev/null +++ b/web/spiderweb/src/postscript/ps.spider @@ -0,0 +1,77 @@ +# Copyright 1989 by David Love, SERC Daresbury Laboratory +# (love@daresbury.ac.uk) +# under the same conditions as the SPIDER distribution. +# For more information, see file COPYRIGHT in the parent directory + +language PostScript extension ps + +comment begin <"%"> end newline +macros begin +\def\commentbegin{\%} +\let\&=\\ % don't want bold reserved words (only begin, end, def used anyway) +\def\ps{\sc PostScript} +macros end + +line begin <"%"> end <""> + +default translation <*> mathness yes + +module definition math use math + +token identifier category math mathness yes +token number category number mathness yes +token newline category newline translation <> mathness maybe +token pseudo_semi category ignore_scrap mathness no translation <opt-0> + +token [ category open translation <break_space-*> +token ] category close translation <break_space-*> +token { translation <"\\{"> category open +token } translation <"\\}"> category close +token < category open translation <break_space-*> +token > category close translation <break_space-*> +token # category hash translation <"\\#"> +# use mathness no here to avoid extra space after / +token / category slash tangleto <space-"/"> mathness no +token = category math +token == category math + +# a frig to allow user to indent/outdent as required +# => and <= can't be used as PostScript names! +# this would be better done with new WEB control sequences +token => category dent translation <indent> tangleto <""> +token <= category dent translation <outdent> tangleto <""> + +ilk def_like category def mathness yes +reserved def ilk def_like +ilk begin_like category begin mathness yes +reserved begin ilk begin_like +ilk end_like category end mathness yes +reserved end ilk end_like + +# index def'd things with underline +slashed_math <break_space> math --> slashed_math +slashed_math* <break_space> def --> math +[ slashed_math ] (close|end) --> math (close|end) + +<big_force> newline newline --> ignore_scrap +<force> newline --> ignore_scrap + +# want indent inside open/close pairs +open <indent> math <outdent> close --> math +# could have empty procedure +open close --> math + +slash math --> slashed_math + +number hash number --> math +number --> math +math <break_space> math --> math + +begin <indent> --> math +<outdent> end --> math + +dent --> ignore_scrap + +ignore_scrap math --> math + +? ignore_scrap --> #1 diff --git a/web/spiderweb/src/reduce/INSTALL b/web/spiderweb/src/reduce/INSTALL new file mode 100644 index 0000000000..52aa82a432 --- /dev/null +++ b/web/spiderweb/src/reduce/INSTALL @@ -0,0 +1,26 @@ +In this directory you can find the stuff necessary for building RWEB, +the REDUCE version of SPIDERY WEB. + +Along with these files you need a version of SPIDERY WEB, which can be +obtained by anonymous ftp from princeton.edu (128.112.128.1). + +After you have installed SPIDERY WEB you know what it means to put the +files contained in this directory into a new directory $(WEBROOT)/reduce. +Do it. You might as well want to change the variable HOME in +$(WEBROOT)/reduce/Makefile (which is in fact an adapted version of +$(MASTER)/WebMakefile). + +In order to make RWEB, go to $(WEBROOT)/reduce and type 'make weave', +'make tangle' or 'make web', if you want to make rweave, rtangle or +both. The documentation needed for using RWEB is +$(WEBROOT)/doc/spiderwebman.tex. + +Have fun, + +Marcel Roelofs, +University of Twente, +Department of applied mathematics, +P.O. Box 217, +7500 AE Enschede, +The Netherlands. +E-mail: roelofs@math.utwente.nl diff --git a/web/spiderweb/src/reduce/Makefile b/web/spiderweb/src/reduce/Makefile new file mode 100644 index 0000000000..ec100b3bcb --- /dev/null +++ b/web/spiderweb/src/reduce/Makefile @@ -0,0 +1,152 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates. +# Not to be sold, but may be used freely for any purpose. +# For more information, see file COPYRIGHT in the parent directory. + +HOME=/users/redusers# # Make no longer inherits environment vars + +THETANGLE=tangle +THEWEAVE=weave +SPIDER=any.spider +# +DVI=dvi +CFLAGS=-DDEBUG -g -DSTAT + +# CPUTYPE is a grim hack that attempts to solve the problem of multiple +# cpus sharing a file system. In my environment I have to have different +# copies of object and executable for vax, sun3, next, iris, and other +# cpu types. If you will be using Spidery WEB in a homogenous processor +# environment, you can just set CPUTYPE to a constant, or eliminate it +# entirely. +# +# In my environment, the 'cputype' program returns a string that +# describes the current processor. That means that the easiest thing +# for you to do is to define a 'cputype' program that does something +# sensible. A shell script that says 'echo "vax"' is fine. + +CPUTYPE=`cputype` + +# Change the following three directories to match your installation +# +# the odd placement of # is to prevent any trailing spaces from slipping in + +WEBROOT=$(HOME)/spider# # root of the WEB source distribution +DEST=$(HOME)/bin# # place where the executables go +MACROS=$(HOME)/tex/inputs# # place where the macros go + +MASTER=$(WEBROOT)/master# # master source directory +OBDIR=$(MASTER)/$(CPUTYPE)# #common object files + +TANGLESRC=tangle +CTANGLE=ceetangle -I$(MASTER) +CWEAVE=ceeweave -I$(MASTER) +AWKTANGLE=awktangle -I$(MASTER) +COMMONOBJS=$(OBDIR)/common.o $(OBDIR)/pathopen.o +COMMONC=$(MASTER)/common.c $(MASTER)/pathopen.c +COMMONSRC=$(COMMONC) $(MASTER)/spider.awk + + +# Our purpose is to make tangle and weave + +web: tangle weave + +tangle: mktangle underscore + +mktangle: $(COMMONOBJS) $(TANGLESRC).o + $(CC) $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + +weave: $(COMMONOBJS) weave.o + $(CC) $(CFLAGS) -o $(DEST)/$(THEWEAVE) $(COMMONOBJS) weave.o + +underscore: $(DEST)/underscore underscore.web + +$(DEST)/underscore: + $(CTANGLE) underscore.web + $(CC) $(CFLAGS) -o $(DEST)/underscore underscore.c + cp rtangle $(DEST)/rtangle + +source: $(TANGLESRC).c $(COMMONSRC) # make tangle.c and common src, then clean + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.web weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + +# Here is how we make the common stuff + +$(MASTER)/common.c: $(MASTER)/common.web # no change file + $(CTANGLE) $(MASTER)/common + +$(OBDIR)/common.o: $(MASTER)/common.c + $(CC) $(CFLAGS) -c $(MASTER)/common.c + mv common.o $(OBDIR) + + +$(MASTER)/pathopen.c: $(MASTER)/pathopen.web # no change file + $(CTANGLE) $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +$(OBDIR)/pathopen.o: $(MASTER)/pathopen.c + $(CC) $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(OBDIR) + +$(OBDIR): + if /bin/test ! -d $(OBDIR) ; then mkdir $(OBDIR) ; fi + +## Now we make the tangle and weave source locally + +$(TANGLESRC).c: $(MASTER)/$(TANGLESRC).web $(MASTER)/common.h grammar.web rtangle.ch + -/bin/rm -f $(TANGLESRC).web + ln $(MASTER)/$(TANGLESRC).web $(TANGLESRC).web +# chmod -w $(TANGLESRC).web + $(CTANGLE) $(TANGLESRC) rtangle.ch + +weave.c: $(MASTER)/weave.web $(MASTER)/common.h grammar.web rweave.ch + -/bin/rm -f weave.web + ln $(MASTER)/weave.web weave.web +# chmod -w weave.web + $(CTANGLE) weave rweave.ch + +## Here's where we run SPIDER to create the source + +grammar.web: $(MASTER)/cycle.awk $(MASTER)/spider.awk $(SPIDER) + echo "date" `date` | cat - $(SPIDER) | awk -f $(MASTER)/spider.awk + cat $(MASTER)/transcheck.list trans_keys.unsorted | awk -f $(MASTER)/transcheck.awk + awk -f $(MASTER)/cycle.awk < cycle.test + sort *.unsorted | awk -f $(MASTER)/nodups.awk + mv *web.tex $(MACROS) + +## We might have to make spider first. + +$(MASTER)/spider.awk: $(MASTER)/spider.web + $(AWKTANGLE) $(MASTER)/spider + mv cycle.awk nodups.awk transcheck.awk $(MASTER) + rm junk.list + + +# $(MASTER)/cycle.awk: $(MASTER)/cycle.web # making spider also makes cycle +# $(AWKTANGLE) $(MASTER)/cycle + + +# This cleanup applies to every language + +clean: + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual + -rm -f tangle.* weave.* common.* # remove links that may be obsolete + -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web + -rm -f cycle.test spider.slog + -rm -f *.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + + + +# booting the new distribution +boot: + cd ../master; rm -f *.o; for i in $(COMMONC); do \ + $(CC) $(CFLAGS) -c $$i; \ + mv *.o $(OBDIR) ; \ + done; cd ../c + $(CC) $(CFLAGS) -c $(TANGLESRC).c; \ + $(CC) $(CFLAGS) -o $(DEST)/$(THETANGLE) $(COMMONOBJS) $(TANGLESRC).o + + diff --git a/web/spiderweb/src/reduce/README b/web/spiderweb/src/reduce/README new file mode 100644 index 0000000000..0545d0e17d --- /dev/null +++ b/web/spiderweb/src/reduce/README @@ -0,0 +1,69 @@ +REDUCE is a lisp based system for symbolic computation by A. Hearn. +The real lisp is hidden for the user by a pascal like language, called +rlisp, which is parsed and converted to ordinary lisp, when read. +Due to the nature of lisp any expression that returns a value may +appear at almost any place, for instance + +b:=for i:=1:if x then y else z sum a(i)+if c then d else e+ + while x do begin ...; return ...; ... end; + +is a perfectly correct rlisp expression. REDUCE itself and all +available libraries are written in rlisp. Users can also write their +own packages in rlisp, containing both low and high level REDUCE +procedures. + +Besides the ordinary stuff available in almost any computer algebra +program, there are user written packages available for differential +geometry, determining symmetries of differential equations, lie +algebras etc., possibly using non standard data structures based on +lisp objects. + +It will be clear from the rlisp expression given above that one has to +be very careful about what has to appear in math mode and what in text +mode. Moreover some additional indentation for complicated expressions +may be desirable. +The second problem can be solved by carefully implementing the +production rules, the first one we solved by putting everything in +text mode except for the unary and binary operators like +, -, :=, +etc., and applying some tricks to get spaces that cannot be removed by +a cancel. + +Changes necessary to weave and tangle in order to parse rlisp source +code correctly are the following: +- rlisp only knows one kind of string, namely the one surrounded by double + quotes ", whereas a single quote ' is explicitly used as a 'quote'. + This means that the parsing of strings had to be adapted. +- rlisp has an escape character '!', which means that an identifier + may contain any character if it is preceded by an exclamation mark + (in this way identifiers may even contain spaces), hence the parsing + of identifiers had to be altered. +- we changed some things which seemed to be bugs: a) in the debug part of + the weave code we replaced "\\{" by "\\\\{" since our compiler + complained about it, b) "+\equiv" isn't TeX'ed in a very nice way so + we replaced it by a new TeX macro "\PS" to be used for multiply + defined modules. +- a minor change: we like tangle also to print the newlines in macros, so + we #define'd NEWLINES_IN_MACROS. +- rlisp doesn't allow underscores to occur in identifiers, unless + preceded by '!'. Therefore, we postprocess the tangled file in order + to remove the underscores. Indeed this can also be done by changing + tangle.web in the appropriate place, but I think it is more work to + find the exact place where the change has to be made, than writing a + C program that does a similar job. However, if you are more familiar + with tangle than we are and know exactly where to make the change, + feel free to do so (underscores preceded by '!' and in strings + should stay). + +Moreover, previewing the weaved & TeX'ed tangle I discovered what +seems to be a bug in your set of production rules of ceeweave, namely +'extern' followed by two simps seems to be missing a space, whereas +'extern' followed by one simp gives no problem. + +I hope this 'blurb' about REDUCE and the necessary changes is +satisfactory. I have put all necessary files tarred, compressed and +uuencoded at the end of this mail. It is also available by anonymous +ftp from utmfu0.math.utwente.nl (130.89.60.149). + +If you have comments or suggestions on our work, feel free to react. + +Marcel Roelofs. diff --git a/web/spiderweb/src/reduce/make b/web/spiderweb/src/reduce/make new file mode 100644 index 0000000000..73a59fa56a --- /dev/null +++ b/web/spiderweb/src/reduce/make @@ -0,0 +1,3 @@ +#!/bin/csh -f +/bin/make -f ../reduce/Makefile CPUTYPE=`cputype`\ + THETANGLE=rtangle.exe THEWEAVE=rweave SPIDER=reduce.spider $* diff --git a/web/spiderweb/src/reduce/reduce.spider b/web/spiderweb/src/reduce/reduce.spider new file mode 100644 index 0000000000..3a6f407cf4 --- /dev/null +++ b/web/spiderweb/src/reduce/reduce.spider @@ -0,0 +1,283 @@ +# Copyright (c): Marcel Roelofs and Peter Gragert +# University of Twente, Enschede, The Netherlands +# +# @(#) reduce.spider (91/03/11) + +language REDUCE extension r + +at_sign @ + +comment begin <"%"> end <"%"> + +default translation <*> mathness no + +line begin <"%line"> end <> + +token identifier category simp +token number category simp +token newline category newline translation <> +token pseudo_semi category terminator translation <"\\rx"> + +module definition stmt use module_scrap + +default translation <"\\ro"-*> mathness no + +token * category binop translation <"\\eo*"> +token / category binop translation <"\\eo/"> +token < category binop +token > category binop +token = category binop +token . category binop tangleto <space-"."-space> + +token .^ category binop translation <"\\ro{.\\^}"> tangleto <space-".^"-space> +token .* category binop translation <"\\ro{.*}"> tangleto <space-".*"-space> +token .+ category binop translation <"\\ro{.+}"> tangleto <space-".+"-space> +token ./ category binop translation <"\\ro{./}"> tangleto <space-"./"-space> +token ^ category binop translation <"\\eo\\^"> +token ** category binop translation <"\\eo\\^"> +token := category binop translation <"\\ro\\leftarrow"> +token != category binop translation <"\\ro\\NEQ"> tangleto <space-"neq"-space> +token <> category binop translation <"\\ro\\NEQ"> tangleto <space-"neq"-space> +token <= category binop translation <"\\ro\\leq"> +token >= category binop translation <"\\ro\\geq"> + +default translation <*> mathness no + +token + category unorbinop +token - category unorbinop +token ' category quote tangleto <space-"'"> +token '( category listopen translation <"'("> tangleto <space-"'("> +token '[ category listopen translation <"'["> tangleto <space-"'["> +token ( category open +token ) category close +token [ category simpopen +token ] category close +token { category simpopen translation <"$\\{$"> +token } category close translation <"$\\}$"> +token , category comma translation <"\\comma"-opt-1> +token ; category terminator translation <";"-break_space> +token $ category terminator translation <"\\$"-break_space> +token : category colon +token << category progn_begin translation <"\\LL"> tangleto <space-"<<"> +token >> category end translation <"\\RR"> tangleto <">>"-space> + +ilk bool_like category simp +ilk goto_like category simp + +default translation <*-space> + +ilk begin_like category begin +ilk if_like category if +ilk then_like category then +ilk else_like category else +ilk for_like category for +ilk do_like category do +ilk step_like category step +ilk repeat_like category repeat +ilk until_like category until +ilk on_like category switch +ilk return_like category return +ilk modedef_like category mode +ilk procmode_like category procmode +ilk proc_like category proc +ilk where_like category where +ilk decl_like category decl +ilk clear_like category clear +ilk end_like category end translation <*> + +ilk not_like category unop translation <"\\R"> +ilk neq_like category binop translation <"\\ro\\NEQ"> +ilk and_like category binop translation <"\\ro\\W"> +ilk or_like category binop translation <"\\ro\\V"> + +reserved not ilk not_like +reserved neq ilk neq_like +reserved and ilk and_like +reserved or ilk or_like + +reserved begin ilk begin_like +reserved end ilk end_like + +reserved if ilk if_like +reserved then ilk then_like +reserved else ilk else_like + +reserved for ilk for_like +reserved each ilk for_like +reserved foreach ilk for_like +reserved all ilk for_like +reserved forall ilk for_like + +reserved do ilk do_like +reserved sum ilk do_like +reserved product ilk do_like +reserved collect ilk do_like +reserved conc ilk do_like +reserved let ilk do_like + +reserved in ilk step_like +reserved step ilk step_like +reserved such ilk step_like +reserved that ilk step_like + +reserved repeat ilk repeat_like +reserved until ilk until_like + +reserved on ilk on_like +reserved off ilk on_like + +reserved go ilk goto_like +reserved to ilk goto_like +reserved goto ilk goto_like + +reserved return ilk return_like +reserved while ilk for_like + +reserved algebraic ilk modedef_like +reserved symbolic ilk modedef_like +reserved lisp ilk modedef_like + +reserved expr ilk procmode_like +reserved fexpr ilk procmode_like +reserved macro ilk procmode_like +reserved smacro ilk procmode_like + +reserved procedure ilk proc_like + +reserved where ilk where_like + +reserved scalar ilk decl_like +reserved integer ilk decl_like +reserved real ilk decl_like +reserved operator ilk decl_like +reserved array ilk decl_like +reserved matrix ilk decl_like +reserved linear ilk decl_like +reserved symmetric ilk decl_like +reserved antisymmetric ilk decl_like +reserved clear ilk clear_like + +reserved nil ilk bool_like +reserved t ilk bool_like + +################################## +# The production rules +################################## + +# Emergency rules, WEAVE commands & comments +newline ? --> #2 +<cancel-"\\rx"> ignore_scrap ? --> #2 +<cancel> ignore_scrap --> terminator +terminator --> stmt +end --> simp + +# Simple expressions +simp <"\\Rs"-opt-3> simp --> simp +simp binop simp --> simp +simp <"\\bo"> unorbinop simp --> simp +<"\\uo"> (unop|unorbinop) simp --> simp + +simp <"\\Rs"-indent-cancel> stmt <outdent> --> stmt +simp binop <indent-cancel> stmt <outdent> --> stmt +simp <"\\bo"> unorbinop <indent-cancel> stmt <outdent> --> stmt +<"\\uo"> (unop|unorbinop) <indent-cancel> stmt <outdent> --> stmt + +quote <cancel> ? <cancel> --> simp +simp comma simp --> simp +simp terminator --> stmt +stmt stmt --> stmt + +# Lists and vectors +open <cancel> simp <cancel> close --> simp + +listopen simp [ open ] --> listopen simp simpopen +listopen [ open ] --> listopen simpopen +listopen <"$\\,$"> close --> simp +listopen simp close --> simp + +simpopen <"$\\,$"> close --> simp +simpopen <"\\Ri"-cancel> simp <cancel-"\\Ro"> close --> simp + +# Function calls +simp open <"$\\,$"> close --> simp +simp open <"\\Ri"-cancel> simp <cancel-"\\Ro"> close --> simp + +# Procedure definitions +(mode|procmode) proc --> proc +proc stmt* <force-indent> stmt <outdent-force> --> stmt +(simp|stmt) <force> proc --> proc + +# Declarations +mode <cancel> (terminator|open) --> #2 +mode stmt --> stmt +proc stmt begin [ decl stmt* <force> ] --> proc stmt begin stmt +(decl|clear|switch|do) stmt* <force> --> stmt + +# Blocks +[ simp <break_space> ] end --> stmt end +<force> begin <force> end --> simp +<force> begin <opt-7> stmt <force> end terminator <force> --> stmt +[ <force> begin <opt-7> stmt <force> end ] !terminator --> simp !terminator +progn_begin end --> simp +<force> progn_begin <indent-cancel> stmt <cancel-outdent> end terminator <force> --> stmt +[ <force> progn_begin <indent-cancel> stmt <cancel-outdent> end ] !terminator --> simp !terminator + +# For statements in all flavours +for for --> for +for [ simp colon <opt-3> simp ] --> for simp +for [ simp <"\\Rs"> (step|until|switch) <opt-3> simp ] --> for simp +[ <force> for simp <"\\Rs"> do <opt-1-indent> simp <outdent> ] (comma|close|else|end) --> simp (comma|close|else|end) +<force> for simp <"\\Rs"> do <opt-1-indent> simp terminator <outdent-force> --> stmt +<force> for simp <"\\Rs"> do <opt-1-indent> stmt <outdent> --> stmt + +# If statements +if simp <"\\Rs"> then <opt-1> --> ifthen +ifthen <indent> simp <"\\Rs"-outdent-force> else <opt-1> --> ifelse +[ <force> ifelse <indent> simp <outdent> ] (comma|close|else|end) --> simp (comma|close|else|end) +[ <force> (if|ifthen) <indent> simp <outdent> ] (comma|close|end) --> simp (comma|close|end) +<force> (ifthen|ifelse) <indent> simp terminator <outdent-force> --> stmt +<force> (ifthen|ifelse) <indent> stmt <outdent> --> stmt + +# Where +[ simp <"\\Rs"-opt-1> where simp ] (close|else|end) --> simp (close|else|end) +simp <"\\Rs"-opt-1> where simp terminator <force> --> stmt + +# Return statement +[ <force> return <indent> simp <outdent> ] (close|else|end) --> simp (close|else|end) +<force> return <indent> simp terminator <outdent-force> --> stmt +<force> return <indent> stmt <outdent> --> stmt + +# Repeat statements +[ <force> repeat <"\\Rs"-opt-7-indent> simp <outdent-force> until <indent> simp <outdent> ] (comma|close|else|end) --> simp (comma|close|else|end) +<force> repeat <"\\Rs"-opt-7-indent> simp <outdent-force> until <indent> simp terminator <outdent-force> --> stmt + +# Labels +!for [ <force-backup> simp colon <"\\Rs"-cancel> (simp|end) ] --> !for #4 + +# Module use +stmt <force> module_scrap terminator <force> --> stmt +module_scrap --> simp + +macros begin +\def\commentbegin{\{} +\def\commentend{\}} +\def\comma{$,{}$} +\def\uo#1{$#1$} +\def\ro#1{${}\mathrel{#1}{}$} +\def\bo#1{${}\mathbin{#1}{}$} +\def\eo#1{$#1$} +\def\NEQ{\hbox{$\ne$}} +\def\LL{$\ll\,$} +\def\RR{$\,\gg$} +\def\PS{\joinrel{+\equiv}} +\let\rx\relax +\newcount\extraindent +\def\Ri{\global\advance\extraindent by1} +\def\Ro{\global\advance\extraindent by-1} +\def\Rs{{ }} +\def\startline{\noindent\count255=\ind + \ifnum\extraindent=0\advance\count255by-2\fi + \hskip\count255 em} +\def\3#1{\hfil\ifnum#1=0\penalty-100\else\penalty#10\fi\hfilneg} +macros end + diff --git a/web/spiderweb/src/reduce/rtangle b/web/spiderweb/src/reduce/rtangle new file mode 100644 index 0000000000..6c32919c89 --- /dev/null +++ b/web/spiderweb/src/reduce/rtangle @@ -0,0 +1,10 @@ +#!/bin/ksh +# Copyright (c): Marcel Roelofs and Peter Gragert +# University of Twente, Enschede, The Netherlands +# +# @(#) rtangle (91/03/11) + +webfile=$1 +shift +rtangle.exe ${webfile} $* +underscore <${webfile}.r > ${webfile}.red diff --git a/web/spiderweb/src/reduce/rtangle.ch b/web/spiderweb/src/reduce/rtangle.ch new file mode 100644 index 0000000000..b6edbe8e19 --- /dev/null +++ b/web/spiderweb/src/reduce/rtangle.ch @@ -0,0 +1,135 @@ +% Copyright (c): Marcel Roelofs and Peter Gragert +% University of Twente, Enschede, The Netherlands +% @@(#) rtangle.ch (91/03/11) + +@x +@u +@<Include files@>@; +@<Common code for \.{WEAVE} and \.{TANGLE}@>@; +@<Typedef declarations@>@; +@<Global variables@>@; +@y +@u +#define NEWLINES_IN_MACROS +@<Include files@>@; +@<Common code for \.{WEAVE} and \.{TANGLE}@>@; +@<Typedef declarations@>@; +@<Global variables@>@; +@z + +@x + if (isdigit(c) || c=='\\' || c=='.') @<Get a constant@>@;/*spider*/ + else if (isalpha(c) || c=='_' || c=='$') @<Get an identifier@>@;/*spider*/ + else if (c=='\'' || c=='\"') @<Get a string@>@;/*spider*/ +@y + if (isdigit(c)) @<Get a constant@>@;/*spider*/ + else if (isalpha(c) || c=='_' || c=='!') @<Get an identifier@>@;/*spider*/ + else if (c=='\"') @<Get a string@>@;/*spider*/ +@z + +@x +@ @<Get an identifier@>= {/*spider*/ + id_first=--loc; + while (isalpha(*++loc) || isdigit(*loc) || *loc=='_'); + if (*loc=='$') while (isdigit(*++loc)||*loc=='$'); + /* make room for \$\$ and \$nnn suffixes */ + id_loc=loc; return(identifier); +} +@y +@ @<Get an identifier@>= {/*spider*/ + id_first=--loc; + if (c=='!') ++loc; + while (isalpha(*++loc) || isdigit(*loc) || *loc=='_' || *loc=='!') + if (*loc=='!') ++loc; + id_loc=loc; return(identifier); +} +@z + +@x +@ \cee\ strings and character constants, delimited by double and single +quotes, respectively, can contain newlines or instances of their own +delimiters if they are protected by a backslash. We follow this +convention, but do not allow the string to be longer than |longest_name|. + +@<Get a string@>= {/*spider*/ + ASCII delim = c; /* what started the string */ +@# +/* if it's not a single-character literal, it's a tick mark or an |at_sign| */ + if (delim=='\'' && (loc+1>=limit || + (*loc != '\\' && *loc!=at_sign && loc[1]!='\'') || + (*loc=='\\' && (loc+2>=limit||loc[2]!='\'')) || + (*loc==at_sign && + (loc+2>=limit||loc[1]!=at_sign||loc[2]!='\'')) + )) goto mistake; + id_first = mod_text+1; + id_loc = mod_text; *++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<=mod_text_end) *id_loc=@`\n'; /* will print as + \.{"\\\\\\n"} */ + } + if ((c=*loc++)==delim) { + if (++id_loc<=mod_text_end) *id_loc=c; + break; + } + if (c=='\\') { + if (loc>=limit) continue; + if (++id_loc<=mod_text_end) *id_loc = '\\'; + c=*loc++; + } + if (++id_loc<=mod_text_end) *id_loc=c; + } + if (id_loc>=mod_text_end) { + printf("\n! String too long: "); +@.String too long@> + ASCII_write(mod_text+1,25); + printf("..."); mark_error; + } + id_loc++; + return(string); +} +@y +@ \cee\ strings are delimited by double quotes and must be restricted +to one line. Double quotes in strings must be doubled and we allow no +string to be longer than |longest_name|. + +@<Get a string@>= {/*spider*/ + ASCII delim = c; /* what started the string */ +@# + id_first = mod_text+1; + id_loc = mod_text; *++id_loc=delim; + while (1) { + if (loc>=limit) { + err_print("! String didn't end"); loc=limit; +@.String didn't end@> + if (get_line()==0) { + err_print("! Input ended in middle of string"); loc=buffer; +@.Input ended in middle of string@> + } + break; + } + if ((c=*loc++)==delim) { + if (++id_loc<=mod_text_end) *id_loc=c; + if (*loc==delim) loc++; + else break; + } + if (++id_loc<=mod_text_end) *id_loc=c; + } + if (id_loc>=mod_text_end) { + printf("\n! String too long: "); +@.String too long@> + ASCII_write(mod_text+1,25); + printf("..."); mark_error; + } + id_loc++; + return(string); +} +@z diff --git a/web/spiderweb/src/reduce/rweave.ch b/web/spiderweb/src/reduce/rweave.ch new file mode 100644 index 0000000000..857cfe2d41 --- /dev/null +++ b/web/spiderweb/src/reduce/rweave.ch @@ -0,0 +1,149 @@ +% Copyright (c): Marcel Roelofs and Peter Gragert +% University of Twente, Enschede, The Netherlands +% @@(#) rweave.ch (91/03/11) + +@x + if (isdigit(c)) @<Get a constant@>@; /*spider*/ + else if (isalpha(c) || c=='_') @<Get an identifier@>@;/*spider*/ + else if (c=='\'' || c=='"') @<Get a string@>@;/*spider*/ +@y + if (isdigit(c)) @<Get a constant@>@;/*spider*/ + else if (isalpha(c) || c=='_' || c=='!') @<Get an identifier@>@;/*spider*/ + else if (c=='\"') @<Get a string@>@;/*spider*/ +@z + +@x +@ @<Get an identifier@>= {/*spider*/ + id_first=--loc; + while (isalpha(*++loc) || isdigit(*loc) || *loc=='_'); + id_loc=loc; return(identifier); +} +@y +@ @<Get an identifier@>= {/*spider*/ + id_first=--loc; + if (c=='!') ++loc; + while (isalpha(*++loc) || isdigit(*loc) || *loc=='_' || *loc=='!') + if (*loc=='!') ++loc; + id_loc=loc; return(identifier); +} +@z + +@x +@ \cee\ strings and character constants, delimited by double and single +quotes, respectively, can contain newlines or instances of their own +delimiters if they are protected by a backslash. We follow this +convention, but do not allow the string to be longer than |longest_name|. + +@<Get a string@>= {/*spider*/ + ASCII delim = c; /* what started the string */ + id_first = mod_text+1; + id_loc = mod_text; + if (delim=='`' && *(loc-2)==at_sign) { + /* make string begin with |"@@`"| */ + *++id_loc=at_sign; + *++id_loc=at_sign; + } + /* this is hack for ascii constant */ +@# +/* if it's not a single-character literal, it's a tick mark or an |at_sign| */ + if ((delim=='\'' || delim == '`') && + (loc+1>=limit || + (*loc != '\\' && *loc!=at_sign && loc[1]!='\'') || + (*loc=='\\' && (loc+2>=limit||loc[2]!='\'')) || + (*loc==at_sign && + (loc+2>=limit||loc[1]!=at_sign||loc[2]!='\'')) + ) + ) goto mistake; + *++id_loc=delim; + if (delim=='`') delim='\''; /* for |ascii_constant|s */ + 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<=mod_text_end) *id_loc=c; + break; + } + if (c=='\\') if (loc>=limit) continue; + else if (++id_loc<=mod_text_end) { + *id_loc = '\\'; c=*loc++; + } + if (++id_loc<=mod_text_end) *id_loc=c; + } + if (id_loc>=mod_text_end) { + printf("\n! String too long: "); +@.String too long@> + ASCII_write(mod_text+1,25); + printf("..."); mark_error; + } + id_loc++; + return(string); +} +@y +@ \cee\ strings are delimited by double quotes and must be restricted +to one line. Double quotes in strings must be doubled and we allow no +string to be longer than |longest_name|. + +@<Get a string@>= {/*spider*/ + ASCII delim = c; /* what started the string */ +@# + id_first = mod_text+1; + id_loc = mod_text; *++id_loc=delim; + while (1) { + if (loc>=limit) { + err_print("! String didn't end"); loc=limit; +@.String didn't end@> + if (get_line()==0) { + err_print("! Input ended in middle of string"); loc=buffer; +@.Input ended in middle of string@> + } + break; + } + if ((c=*loc++)==delim) { + if (++id_loc<=mod_text_end) *id_loc=c; + if (*loc==delim) loc++; + else break; + } + if (++id_loc<=mod_text_end) *id_loc=c; + } + if (id_loc>=mod_text_end) { + printf("\n! String too long: "); +@.String too long@> + ASCII_write(mod_text+1,25); + printf("..."); mark_error; + } + id_loc++; + return(string); +} +@z + +@x + case 1: printf("\\{"); print_id((name_dir+r)); printf("}"); break; + /* |id_flag| */ + case 2: printf("\&{"); print_id((name_dir+r)); printf("}"); break; +@y + case 1: printf("\\\\{"); print_id((name_dir+r)); printf("}"); break; + /* |id_flag| */ + case 2: printf("\\&{"); print_id((name_dir+r)); printf("}"); break; +@z + +@x +if (cur_xref->num%def_flag!=module_count) { + app_str("+"); /*module name is multiply defined*/ + this_module=name_dir; /*so we won't give cross-reference info here*/ +} +app_str("\\S"); /* output an equivalence sign */ +@y +if (cur_xref->num%def_flag!=module_count) { + app_str("\\PS"); /*module name is multiply defined*/ + this_module=name_dir; /*so we won't give cross-reference info here*/ +} +else app_str("\\S"); /* output an equivalence sign */ +@z diff --git a/web/spiderweb/src/reduce/underscore.web b/web/spiderweb/src/reduce/underscore.web new file mode 100644 index 0000000000..310de4fdac --- /dev/null +++ b/web/spiderweb/src/reduce/underscore.web @@ -0,0 +1,32 @@ +% Copyright (c): Marcel Roelofs and Peter Gragert +% University of Twente, Enschede, The Netherlands +% @@(#) underscore.web (91/03/11) + +@* Filter to remove underscores from REDUCE source. REDUCE does not +allow sole underscores in identifiers. However, underscores preceded +by an exclamation mark are allowed. Also REDUCE strings may contain +underscores. The following C program is a filter that removes the +forbidden underscores. + +@u +#include <stdio.h> + +main (ac, av) +char **av; +{ +char c; +while ((c=getc(stdin)) != EOF) + if (c=='!') { + putc(c,stdout); + c=getc(stdin); + putc(c,stdout); + } + else + if (c=='\"') { + while (putc(c,stdout), (c=getc(stdin)) != '\"') ; + putc(c,stdout); + } + else + if (c != '_') putc(c,stdout); +} + diff --git a/web/spiderweb/src/sml/leavens.mail b/web/spiderweb/src/sml/leavens.mail new file mode 100644 index 0000000000..9c91b69aa4 --- /dev/null +++ b/web/spiderweb/src/sml/leavens.mail @@ -0,0 +1,548 @@ +# This for weave +token @ category binop translation <"\\ATSIGN"> + From leavens@cs.iastate.edu Wed Mar 11 20:35:11 1992 +Received: from Princeton.EDU (Princeton.EDU.) by fs.Princeton.EDU (4.0/1.105) + id AA20432; Wed, 11 Mar 92 20:35:09 EST +Received: from flash.cs.iastate.edu by Princeton.EDU (5.65b/2.86/princeton) + id AA26935; Wed, 11 Mar 92 20:34:59 -0500 +Received: from bambam.cs.iastate.edu by flash.cs.iastate.edu with SMTP + (16.7/16.2) id AA24210; Wed, 11 Mar 92 19:34:50 -0600 +Received: by bambam.cs.iastate.edu (4.1/SMI-4.1) + id AA29309; Wed, 11 Mar 92 19:34:49 CST +Date: Wed, 11 Mar 92 19:34:49 CST +From: leavens@cs.iastate.edu (Gary Leavens) +Message-Id: <9203120134.AA29309@bambam.cs.iastate.edu> +To: nr@Princeton.EDU +In-Reply-To: Norman Ramsey's message of Wed, 11 Mar 92 18:12:19 -0500 <9203112312.AA02296@cs.Princeton.EDU> +Subject: Literate programming for SML? +Status: RO + +Norman, + I read your TOSE paper on noweb, and all I can say is: hooray! +Really, for giving students an introduction to literate programming, +and for getting started in a new language, etc., it seems like a great +idea. I guess I'm just echoing the points you make in the paper, but I've +been trying to think of how to make some literate programming stuff available +to graduate students, and this seems like it has more of a chance of catching +on than anything else. + + As far as sml.spider goes, I had not planned on worrying about infix +for a while... I haven't done a lot of programming in SML, do you find you +use infix signficantly? Perhaps it's a personal style thing. + + I'm very happy to send you the sml.spider file, which follows. +The main problem I'm having with it at the moment is that in the formatting +I don't get anything combined in a big math format, instead I get lots of +little math shifts, which causes code to look pretty ugly. But I'm sure +you would see many, many other problems. My basic approach, which may not +be a good one, was to type in the grammar from the defintion of SML, +making changes along the way to make it left recursive, and adding context +and some formatting stuff. Clearly it needs work. So if you'd like to build +on that base, please do so... Anyway, the file follows. + Gary + +# sml.spider +# AUTHOR: Gary T. Leavens + +language SML extension sml version 1.4 + +at_sign @ + +comment begin <"(*"> end <"*)"> + +line begin <"(*"-space-"line"> end <"*)"> + +default mathness yes +default translation <*> + +token identifier category id +token number category scon +token newline category ignore_scrap mathness maybe translation <> +token pseudo_semi category semi mathness maybe translation <force> + +# web's idea of modules... +module definition topdec use id + + +# nonfix functions in standard basis +ilk functions category unop + +reserved map ilk functions +reserved rev ilk functions +reserved not ilk functions +token ~ category unop translation <"\\TI"> mathness yes +reserved abs ilk functions +reserved floor ilk functions +reserved real ilk functions +reserved sqrt ilk functions +reserved sin ilk functions +reserved cos ilk functions +reserved arctan ilk functions +reserved exp ilk functions +reserved ln ilk functions +reserved size ilk functions +reserved chr ilk functions +reserved ord ilk functions +reserved explode ilk functions +reserved implode ilk functions +token ! category unop translation <*> +reserved ref ilk functions + +# constants in the standard basis +ilk constants category con + +reserved true ilk constants +reserved false ilk constants +reserved nil ilk constants + +# infix functions in the standard basis +ilk infixfun category binop + +# precedence 7 +token / category binop +reserved div ilk infixfun +reserved mod ilk infixfun +token * category star translation <"\\times"> +# precedence 6 +token + category binop +token - category binop +token ^ category binop +# precedence 5 +token :: category binop +token @ category binop +# precedence 4 +token = category equals +token <> category binop translation <"\\I"> +token < category binop +token > category binop +token <= category binop translation <"\\L"> +token >= category binop translation <"\\G"> +# precedence 3 +token := category binop translation <"\\leftarrow"> +ilk compose category binop translation <"\\circ"> +reserved o ilk compose + +default translation <*-"\\"-space> + +# core ilks +ilk abstype_like category abstype +ilk and_like category and +ilk andalso_like category andalso +ilk as_like category as +ilk case_like category case +ilk do_like category do +ilk datatype_like category datatype +ilk else_like category else +ilk end_like category end +ilk exception_like category exception +ilk fn_like category fn +ilk fun_like category fun +ilk handle_like category handle +ilk if_like category if +ilk in_like category in +ilk infix_like category infix +ilk let_like category let +ilk local_like category local +ilk nonfix_like category nonfix +ilk of_like category of +ilk op_like category op +ilk open_like category open +ilk orelse_like category orelse +ilk raise_like category raise +ilk rec_like category rec +ilk then_like category then +ilk type_like category type +ilk val_like category val +ilk with_like category with +ilk withtype_like category withtype +ilk while_like category while + +# modules ilks +ilk eqtype_like category eqtype +ilk functor_like category functor +ilk include_like category include +ilk sharing_like category sharing +ilk sig_like category sig +ilk signature_like category signature +ilk struct_like category struct +ilk structure_like category structure +ilk use_like category use + +default translation <*> + +# core reserved words +reserved abstype ilk abstype_like +reserved and ilk and_like +reserved andalso ilk andalso_like +reserved as ilk as_like +reserved case ilk case_like +reserved do ilk do_like +reserved datatype ilk datatype_like +reserved else ilk else_like +reserved end ilk end_like +reserved exception ilk exception_like +reserved fn ilk fn_like +# reserved fn translation <\\lambda> +reserved fun ilk fun_like +reserved handle ilk handle_like +reserved if ilk if_like +reserved in ilk in_like +reserved infix ilk infix_like +reserved infixr ilk infix_like +reserved let ilk let_like +reserved local ilk local_like +reserved nonfix ilk nonfix_like +reserved of ilk of_like +reserved op ilk op_like +reserved open ilk open_like +reserved orelse ilk orelse_like +reserved raise ilk raise_like +reserved rec ilk rec_like +reserved then ilk then_like +reserved type ilk type_like +reserved val ilk val_like +reserved with ilk with_like +reserved withtype ilk withtype_like +reserved while ilk while_like + +# modules reserved words +reserved eqtype ilk eqtype_like +reserved functor ilk functor_like +reserved include ilk include_like +reserved sharing ilk sharing_like +reserved sig ilk sig_like +reserved signature ilk signature_like +reserved struct ilk struct_like +reserved structure ilk structure_like +reserved use ilk use_like + +token ( category lparen +token ) category rparen +token [ category lsqbracket +token ] category rsqbracket +token { category lcurly translation <"\\{"> +token } category rcurly translation <"\\}"> +token , category comma translation <",\\,"> +token : category colon +token ; category semi +token ... category dotdotdot translation <"\\ldots"> +token | category vertbar +token => category reducesto translation <"\\Rightarrow"> +token -> category arrow translation <"\\rightarrow"> +token # category sharp translation <"\\#"> +token . category dot +token ' category prime + + +# +? ignore_scrap --> #1 + +# lexical rules +id --> longvar +longvar dot id --> longvar +longvar dot con --> longvar +longvar prime --> longvar + +prime id --> tyvar +prime tyvar --> tyvar + +# core language syntax +scon --> atexp +longvar --> atexp +unop --> atexp +op (longvar|binop|equals|star|unop) --> atexp +lcurly exprow rcurly --> atexp +sharp id --> atexp +lparen rparen --> atexp +lparen <indent> exptupling <outdent> rparen --> atexp +lsqbracket rsqbracket --> atexp +lsqbracket <indent> explist <outdent> rsqbracket --> atexp +lparen expblock rparen --> atexp +let dec in exp end --> atexp +lparen exp rparen --> atexp + +exp comma <opt-9> exp --> exptupling +exptupling comma <opt-9> exp --> exptupling + +exp semi <opt-1> exp --> expblock +expblock semi <opt-1> exp --> expblock + +lsqbracket [ exp ] --> lsqbracket explist +lsqbracket [ explist comma <opt-9> exp ] --> lsqbracket explist + +id equals exp --> exprow +exprow comma <opt-8> id equals exp --> exprow + +atexp --> appexp +appexp <"\\"-space> atexp --> appexp + +appexp --> infexp +infexp (binop|equals|star) infexp --> infexp + +infexp --> exp +exp colon ty --> exp +exp andalso exp --> exp +exp orelse exp --> exp +exp handle <indent> match <outdent> --> exp +raise exp --> exp +if exp <opt-2> then <indent> exp <outdent-opt-1> else <indent> exp <outdent> --> exp +while exp do <indent> exp <outdent> --> exp +case exp of <indent> match <outdent> --> exp +fn <indent> match <outdent> --> exp + +mrule --> match +match vertbar mrule --> match + +pat reducesto exp --> mrule + +val valbind* --> dec +fun fvalbind* --> dec +type typbind* --> dec +datatype datbind* --> dec +datatype datbind* <force> withtype typbind --> dec +abstype datbind* <force> with dec end --> dec +abstype datbind* <force> withtype typbind <force> with dec end --> dec +exception exbind* --> dec +local <opt-1-indent> dec <outdent-opt-1> in <opt-1-indent> dec <outdent-opt-1> end --> dec +open longvarlist --> dec +dec <force> dec --> dec +dec semi <force> dec --> dec +infix scon idlist --> dec +infix idlist --> dec +nonfix idlist --> dec + +open [ longvar ] --> open longvarlist +open [ longvarlist longvar ] --> open longvarlist + +(infix|nonfix|include) [ id ] --> (infix|nonfix|include) idlist +(infix|nonfix|include) [ idlist id ] --> (infix|nonfix|include) idlist +infix scon [ id ] --> infix scon idlist +infix scon [ idlist id ] --> infix scon idlist + +pat* equals exp --> valbind +valbind and pat* equals exp --> valbind +rec valbind* --> valbind + +fun [ op id* atpatlist colon ty equals <opt-2-indent> exp <outdent> ] --> fun prefvalbind +fun [ id* atpatlist colon ty equals <opt-2-indent> exp <outdent> ] --> fun prefvalbind +fun [ prefvalbind vertbar op id atpatlist colon ty equals <opt-2-indent> exp <outdent> ] --> fun prefvalbind +fun [ prefvalbind vertbar id atpatlist colon ty equals <opt-2-indent> exp <outdent> ] --> fun prefvalbind +fvalbind and [ op id* atpatlist colon ty equals <opt-2-indent> exp <outdent> ] --> fvalbind and prefvalbind +fvalbind and [ vertbar id* atpatlist colon ty equals <opt-2-indent> exp <outdent> ] --> fvalbind and prefvalbind +fvalbind and [ prefvalbind vertbar op id atpatlist colon ty equals <opt-2-indent> exp <outdent> ] --> fvalbind and prefvalbind +fvalbind and [ prefvalbind vertbar id atpatlist colon ty equals <opt-2-indent> exp <outdent> ] --> fvalbind and prefvalbind + +fun [ prefvalbind ] (and|semi) --> fun fvalbind (and|semi) +fun [ fvalbind and prefvalbind ] --> fun fvalbind + +(fun|vertbar) op id [ atpat ] --> (fun|vertbar) op id atpatlist +(fun|vertbar) op id [ atpatlist atpat ] --> (fun|vertbar) op id atpatlist +(fun|vertbar) id [ atpat ] --> (fun|vertbar) id atpatlist +(fun|vertbar) id [ atpatlist atpat ] --> (fun|vertbar) id atpatlist + +tyvarseq longvar* equals ty --> typbind +typbind and tyvarseq longvar* equals ty --> typbind + +type [ tyvar ] --> type tyvarseq +type [ ] --> type tyvarseq +type lparen [ tyvarseq comma tyvar ] --> type lparen tyvarseq +type [ lparen tyvarseq rparen ] --> type tyvarseq +datatype [ tyvar ] --> datatype tyvarseq +datatype [ ] --> datatype tyvarseq +datatype lparen [ tyvarseq comma tyvar ] --> datatype lparen tyvarseq +datatype [ lparen tyvarseq rparen ] --> datatype tyvarseq +abstype [ tyvar ] --> abstype tyvarseq +abstype [ ] --> abstype tyvarseq +abstype lparen [ tyvarseq comma tyvar ] --> abstype lparen tyvarseq +abstype [ lparen tyvarseq rparen ] --> abstype tyvarseq +typbind and [ tyvar ] --> typbind and tyvarseq +typbind and [ ] --> typbind and tyvarseq +typbind and lparen [ tyvarseq comma tyvar ] --> typbind and lparen tyvarseq +typbind and [ lparen tyvarseq rparen ] --> typbind and tyvarseq + +tyvarseq longvar* equals conbind --> datbind +datbind and tyvarseq longvar* equals conbind --> datbind + +datatype tyvarseq id equals [ op id* of ty ] --> datatype tyvarseq id equals conbind +datatype tyvarseq id equals [ op id* ] --> datatype tyvarseq id equals conbind +datatype tyvarseq id equals [ id* of ty ] --> datatype tyvarseq id equals conbind +datatype tyvarseq id equals [ id* ] --> datatype tyvarseq id equals conbind + +conbind and op id* of ty --> conbind +conbind and op id* --> conbind +conbind and id* of ty --> conbind +conbind and id* --> conbind + +exception [ op id* of ty ] --> exception exbind +exception [ op id* ] --> exception exbind +exception [ id* of ty ] --> exception exbind +exception [ id* ] --> exception exbind +exception [ op id* equals op longvar ] --> exception exbind +exception [ op id* equals longvar ] --> exception exbind +exception [ id* equals op longvar ] --> exception exbind +exception [ id* equals longvar ] --> exception exbind + +exbind and op id* of ty --> exbind +exbind and op id* --> exbind +exbind and id* of ty --> exbind +exbind and id* --> exbind +exbind and op id* equals op longvar --> exbind +exbind and op id* equals longvar --> exbind +exbind and id* equals op longvar --> exbind +exbind and id* equals longvar --> exbind + +longvar --> atpat +scon --> atpat +op (longvar|unop) --> atpat +lcurly patrow rcurly --> atpat +lparen rparen --> atpat +lparen pattupling rparen --> atpat +lsqbracket rsqbracket --> atpat +lparen pat rparen --> atpat + +pat comma pat --> pattupling +pattupling comma pat --> pattupling + +lsqbracket [ pat ] --> lsqbracket patlist +lsqbracket [ patlist comma pat ] --> lsqbracket patlist + +dotdotdot --> patrow +id equals pat --> patrow +id colon ty as pat --> patrow +id as pat --> patrow +id colon ty --> patrow +patrow comma id equals pat --> patrow +patrow comma id colon ty as pat --> patrow +patrow comma id as pat --> patrow +patrow comma id colon ty --> patrow + +atpat --> pat +op longvar atpat --> pat +longvar atpat --> pat +pat (binop|equals|star) pat --> pat +pat colon ty --> pat +op id colon ty as pat --> pat +op id as pat --> pat +id colon ty as pat --> pat +id as pat --> pat + +tyvar --> ty +lcurly tyrow rcurly --> ty +longvar --> ty +lparen ty rparen longvar --> ty +lparen tyseq rparen longvar --> ty +tytuple --> ty +ty arrow ty --> ty +lparen ty rparen --> ty + +lparen [ ty comma ] --> lparen tyseq +tyseq comma ty --> tyseq + +id colon ty --> tyrow +tyrow comma id colon ty --> tyrow + +ty star ty --> tytuple +tytuple star ty --> tytuple + + +# modules, with permissive syntax +#struct strdec end --> strexp +struct <opt-1-indent> dec <outdent-opt-1> end --> exp + +# whereever the SML grammar has strdec, have to use dec too +structure strbind --> dec + +structure [ id* colon sigexp equals <opt-1-indent> exp <outdent-opt-1> ] --> structure strbind +structure [ id* colon id equals <opt-1-indent> exp <outdent-opt-1> ] --> structure strbind +structure [ id* equals <opt-1-indent> exp <outdent-opt-1> ] --> structure strbind +strbind <force> and id* colon sigexp equals <opt-1-indent> exp <outdent-opt-1> --> strbind +strbind <force> and id* colon id equals <opt-1-indent> exp <outdent-opt-1> --> strbind +strbind <force> and id* equals <opt-1-indent> exp <outdent-opt-1> --> strbind + +# whereever the SML grammar has sigexp, have to use id too +sig <opt-1-indent> spec <outdent-opt-1> end --> sigexp + +signature sigbind --> sigdec +sigdec <force> sigdec --> sigdec +sigdec semi <force> sigdec --> sigdec + +signature [ id* equals <opt-1-indent> sigexp <outdent> ] --> signature sigbind +signature [ id* equals id ] --> signature sigbind +sigbind <force> and id* equals <opt-1-indent> sigexp <outdent> --> sigbind +sigbind <force> and id* equals id --> sigbind + +val valdesc --> spec +type typdesc --> spec +eqtype typdesc --> spec +datatype datdesc --> spec +exception exdesc --> spec +structure strdesc --> spec +sharing shareq --> spec +local spec in spec end --> spec +open longvarlist --> spec +include idlist --> spec +sig [ ] end --> sig spec end +spec <force> spec --> spec +spec semi spec --> spec + +val [ id* colon ty ] --> val valdesc +valdesc <opt-1> and id* colon ty --> valdesc + +type [ tyvarseq id* ] --> type typdesc +typdesc <opt-1> and tyvarseq id* --> typdesc + +typdesc and [ tyvar ] --> typdesc and tyvarseq +typdesc and [ ] --> typdesc and tyvarseq +typdesc and lparen [ tyvarseq comma tyvar ] --> typdesc and lparen tyvarseq +typdesc and [ lparen tyvarseq rparen ] --> typdesc and tyvarseq + +tyvarseq id* equals condesc --> datdesc +datdesc <opt-1> and tyvarseq id* equals condesc --> datdesc + +datatype tyvarseq id equals [ id* of ty ] --> datatype tyvarseq id equals condesc +datatype tyvarseq id equals [ id* ] --> datatype tyvarseq id equals condesc + +condesc <opt-1> and id* of ty --> condesc +condesc <opt-1> and id* --> condesc + +exception [ id* of ty ] --> exception exdesc +exception [ id* ] --> exception exdesc + +exdesc <opt-1> and id* of ty --> exdesc +exdesc <opt-1> and id* --> exdesc + +structure [ id* colon sigexp ] --> structure strdesc +structure [ id* colon id ] --> structure strdesc +strdesc <opt-1> and id* colon sigexp --> strdesc +strdesc <opt-1> and id* colon id --> strdesc + +sharing [ longvar equals longvar ] --> sharing shareq +shareq equals longvar --> shareq +sharing type [ longvar equals longvar ] --> sharing type shareq +shareq equals longvar --> shareq +shareq <opt-1> and longvar equals longvar --> shareq +shareq <opt-1> and type longvar equals longvar --> shareq + +functor funbind --> fundec +fundec <force> fundec --> fundec +fundec semi fundec --> fundec + +functor [ id* lparen id colon sigexp rparen colon sigexp equals <force-indent> exp ] --> functor funbind +functor [ id* lparen id colon sigexp rparen equals <force-indent> exp ] --> functor funbind +funbind <opt-1> and id* lparen id colon sigexp rparen colon sigexp equals <force-indent> exp --> funbind +funbind <opt-1> and id* lparen id colon sigexp rparen equals <force-indent> exp --> funbind + +sigdec --> topdec +fundec --> topdec +dec --> topdec +use scon --> topdec + + +topdec <force> topdec --> topdec +topdec semi <force> topdec --> topdec + +macros begin +\let\LN\langle +\let\RN\rangle +macros end + diff --git a/web/spiderweb/src/sml/make b/web/spiderweb/src/sml/make new file mode 100644 index 0000000000..d376f72a64 --- /dev/null +++ b/web/spiderweb/src/sml/make @@ -0,0 +1,3 @@ +#!/bin/sh +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=smltangle THEWEAVE=smlweave SPIDER=sml.spider "$@" diff --git a/web/spiderweb/src/sml/mason.mail b/web/spiderweb/src/sml/mason.mail new file mode 100644 index 0000000000..081b209b6a --- /dev/null +++ b/web/spiderweb/src/sml/mason.mail @@ -0,0 +1,1031 @@ +From dmason@plg.uwaterloo.ca Wed Aug 5 17:08:26 1992 +Received: from Princeton.EDU by fs.Princeton.EDU (4.1/1.105) + id AA10701; Wed, 5 Aug 92 17:08:21 EDT +Received: from plg.uwaterloo.ca by Princeton.EDU (5.65b/2.93/princeton) + id AA23362; Wed, 5 Aug 92 17:07:44 -0400 +Received: by plg.uwaterloo.ca id <29115>; Wed, 5 Aug 1992 17:07:32 -0400 +From: Dave Mason <dmason@plg.uwaterloo.ca> +To: Norman Ramsey <nr@Princeton.EDU> +Subject: spiderweb +Message-Id: <92Aug5.170732edt.29115@plg.uwaterloo.ca> +Date: Wed, 5 Aug 1992 17:07:26 -0400 +Status: R + +I talked to you at PLDI about SML spiderweb. I haven't had any time to work +on it, so I decided to send you what I had. + +Included is a diff of weave.web to treat _ as a non-identifier, and to treat +' as part of an identifier if it immediately follows something that is +already treated as an identifier. + +Also included is sml.spider. It isn't perfect, but it works fairly well. +There are 3 special tokens: |: |= and |; that are useful to have different +paragraphs be working on a common function or datatype. Sorry I don't have +documentation, but I am not 100% happy with the system yet. BTW, the |; +could be removed, and the grammar made *much* simpler if there were a +special token for the END of a code block. + +Finally, I've included a web file for a denotational semantics that I wrote. +It exhibits the three special tokens. + +Are you, or anyone else, working on moving spiderweb so it would work with +LaTeX? I would *love* to be able to import small (or not so small) code +segments into my latex documents (particularly for overheads). + +I'm off for vacation most of the rest of the month. I plan to do the LaTeX +thing when I get back, if no-one else is working on it. I will also be +doing a fair bit of sml hacking in the fall, and I'm likely to be using web, +so the sml stuff will get cleaned up some. + + ../Dave + +------------------------------------start of diff------------------- +*** weave.web Sun Mar 29 02:54:59 1992 +--- weave.webO Wed Nov 13 19:48:26 1991 +*************** +*** 85,93 **** + @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 */ + + @i common.h +--- 85,93 ---- + @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 = 2000 /* number of phrases in \cee\ texts being parsed; + must be less than 10240 */ +! @d max_scraps = 1000 /* number of tokens in \cee\ texts being parsed */ + @d stack_size = 400 /* number of simultaneous output levels */ + + @i common.h +*************** +*** 543,549 **** + } + } + if (isdigit(c)) @<Get a constant@>@; /*spider*/ +! else if (isalpha(c) || (c=='_' && (*loc=='_' || isalpha(*loc)))) @<Get an +identifier@>@;/*spider*/ + else if (c=='\'' || c=='"') @<Get a string@>@;/*spider*/ + else if (c==at_sign) @<Get control code and possible module name@>@; + else if (c==' ' || c==tab_mark) continue; /* ignore spaces and tabs */ +--- 543,549 ---- + } + } + if (isdigit(c)) @<Get a constant@>@; /*spider*/ +! else if (isalpha(c) || c=='_') @<Get an identifier@>@;/*spider*/ + else if (c=='\'' || c=='"') @<Get a string@>@;/*spider*/ + else if (c==at_sign) @<Get control code and possible module name@>@; + else if (c==' ' || c==tab_mark) continue; /* ignore spaces and tabs */ +*************** +*** 557,563 **** + + @ @<Get an identifier@>= {/*spider*/ + id_first=--loc; +! while (isalpha(*++loc) || isdigit(*loc) || *loc=='_' || *loc=='\''); + id_loc=loc; return(identifier); + } + +--- 557,563 ---- + + @ @<Get an identifier@>= {/*spider*/ + id_first=--loc; +! while (isalpha(*++loc) || isdigit(*loc) || *loc=='_'); + id_loc=loc; return(identifier); + } + +------------------------------------end of diff------------------- +---------------------------------start of sml.spider------------- +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language SML extension sml + +at_sign % + +module definition codedef use codeuse + +comment begin <"(*"> end <"*)"> + +line begin <"(*line"> end <"*)"> + +default translation <*> mathness yes + +token identifier category id mathness maybe +token number category const mathness yes +token newline category ignore_scrap translation <> mathness maybe +token pseudo_semi translation <> category semi mathness maybe + +macros begin +\let\R\relax +\def\SS{\relax\ifmmode\>\else$\>$\fi} +\def\UL{\relax\ifmmode\_\!\_\,\else$\_\!\_\,$\fi} +\def\FL.#1#2#3(#4){\relax\ifmmode#4^{\rm{#2}}\else$#4^{\rm{#2}}$\fi} +\def\SL#1{\relax\ifmmode{}_{#1}\else${}_{#1}$\fi} +\def\LA{\relax\ifmmode\leftarrow\else$\leftarrow$\fi} +\def\GK#1#2{\if#2a\alpha\else\if#2b\beta\else\if#2c\gamma\else\if#2d\delta\else\if#2e\varepsilon\else\if#2f\zeta\else\if#2g\eta\fi\fi\fi\fi\fi\fi\fi^{^{#1}}} +\def\'#1#2#3{\relax\ifmmode\GK{#1}{#3}\else$\GK{#1}{#3}$\fi} +\def\"#1#2{\relax\ifmmode\GK{=}{#2}\else$\GK{=}{#2}$\fi} +\def\ST#1{\relax\ifmmode\times\else$\times$\fi} +macros end + +# Delimiters +#token & category binop translation <"\\amp"> +token ( category open +token ) category close +token [ category open +token ] category close +token { category ocurly translation <"\\{"> +token } category ccurly translation <"\\}"> +token [. category open tangleto <space-"sub("> translation <"\\SL{"> mathness maybe +token .] category close tangleto <")"> translation <"}"> mathness maybe +token [= category open tangleto <space-"assign("> translation <"\\SL{"> mathness maybe +token =] category close tangleto <")"> translation <"}\\LA"> mathness maybe +token * category star mathness maybe +token + category binop +token , category comma translation <",\\,"-opt-5> +token - category binop +token ^ category binop translation <"\\^"> +token ! category unop +token ~ category unop +token . category dot +token @ category binop +token # category unop translation <"\\FL."> +token / category binop +token : category tylook +token ; category semi +token < category binop +token = category equal +token > category binop +token | category choice translation <"\\mid"> +token |: category datam translation <"\\mid"> tangleto <"|"> +token |= category fun translation <"\\mid"> tangleto <"|"> +token |; category semi translation <""> tangleto <""> mathness maybe +token _ category underline translation <"\\UL"> mathness no +token ' category tick tangleto <space-"'"> translation <"\\'{"> mathness maybe +token '' category tick tangleto <space-"''"> translation <"\\'{="> mathness maybe +token ... category labpat translation <"\\cdots"> mathness yes + +# Compound delimiters + +token := category binop translation <"\\mathbin{:=}"> +token :: category binop translation <"\\mathbin{::}"> +token => category arrow translation <"\\Rightarrow"> +token -> category fnarrow translation <"\\mapsto"> +#token /= translation <"\\I"> category binop +token >= translation <"\\G"> category binop +token <= translation <"\\L"> category binop +#token << translation <"\\LL"> category openlabel +#token >> translation <"\\GG"> category closelabel +#token <> translation <"\\LG"> category math + +#token # category math translation <"\\#"> + +token && category binop tangleto <space-"andalso"-space> mathness yes translation <"\\wedge"> +token || category binop tangleto <space-"orelse"-space> mathness yes translation <"\\vee"> + + + +default mathness maybe translation <*> + +reserved abstraction ilk abstraction_like +reserved abstype ilk abstype_like +reserved and ilk and_like +reserved andalso ilk andalso_like +reserved array ilk math_like +reserved as ilk as_like +reserved case ilk case_like +reserved datatype ilk datatype_like +reserved do ilk do_like +reserved else ilk else_like +reserved end ilk end_like +reserved eqtype ilk type_like +reserved exception ilk ex_like +reserved false ilk const_like +reserved fn ilk fn_like +reserved fun ilk fun_like +reserved functor ilk functor_like +reserved handle ilk handle_like +reserved if ilk if_like +reserved in ilk in_like +reserved int ilk int_like +#reserved infix ilk infix_like +#reserved infixr ilk infix_like +reserved let ilk let_like +reserved list ilk list_like +reserved local ilk local_like +#reserved nonfix ilk infix_like +reserved not ilk unop_like +reserved nil ilk const_like +reserved of ilk of_like +#reserved op ilk op_like +reserved open ilk open_like +reserved orelse ilk orelse_like +reserved overload ilk overload_like +reserved raise ilk raise_like +reserved rec ilk rec_like +reserved ref ilk ref_like +#reserved sharing ilk sharing_like +reserved sig ilk sig_like +reserved signature ilk signature_like +reserved string ilk int_like +reserved struct ilk struct_like +reserved structure ilk structure_like +reserved then ilk then_like +reserved true ilk const_like +reserved type ilk type_like +reserved unit ilk int_like +reserved val ilk val_like +reserved while ilk while_like +reserved with ilk with_like +reserved withtype ilk withtype_like +reserved orelse ilk binop_like + +ilk overload_like translation <*> category keyword +ilk abstraction_like translation <*> category keyword + +ilk abstype_like translation <*> category abstype +ilk and_like translation <*> category and +ilk andalso_like category binop mathness yes translation <"\\wedge"> +ilk as_like translation <*> category id +ilk binop_like translation <"\\"-space-*-"\\"-space> category binop +ilk case_like translation <*> category case +ilk const_like translation <*> category const +ilk datatype_like translation <*> category datatype +ilk do_like translation <*> category do +ilk else_like translation <*> category else +ilk end_like translation <*> category end +ilk ex_like translation <*> category exception +ilk fn_like category fn mathness yes translation <"\\lambda\\"-space> + +ilk fun_like translation <*> category fun +ilk functor_like translation <*> category functor +ilk handle_like translation <*> category handle +ilk if_like translation <*> category if +ilk in_like translation <*> category in +ilk int_like translation <*> category ty +ilk let_like translation <*> category let +ilk list_like translation <*> category id +ilk local_like translation <*> category local +ilk math_like translation <*> category math +ilk of_like translation <*> category of +ilk open_like translation <*> category openop +ilk orelse_like category binop mathness yes translation <"\\vee"> +ilk raise_like translation <*> category raise +ilk rec_like translation <*> category rec +ilk ref_like translation <*> category id +ilk sig_like translation <*> category sig +ilk signature_like translation <*> category signature +ilk struct_like translation <*> category struct +ilk structure_like translation <*> category val +ilk then_like translation <*> category then +ilk type_like translation <*> category type +ilk unop_like translation <*-"\\"-space> category unop +#ilk unorbinop_like translation <"\\"-space-*-"\\"-space> category resunorbinop +ilk val_like translation <*> category val +ilk while_like translation <*> category while +ilk with_like translation <*> category with +ilk withtype_like translation <*> category withtype + + +# \MC means ``math close'' and sets \MS to ``math set'' +macros begin +\def\MC{\ifmmode\global\let\MS$\else\global\let\MS\relax\fi\relax\MS} +\def\LG{\mathord{<}\mathord{>}} +\let\IG=\ignorespaces +macros end + +codedef dec --> dec +[ codedef (math|multimath) ] semi --> dec semi +codeuse <force> codeuse --> codeuse +codeuse semi --> codeuse +!ignore_scrap [ codeuse ] !(codeuse|ignore_scrap|semi|val|fun|type|let|struct|openop|end|in) --> !ignore_scrap multimath !(codeuse|ignore_scrap|semi|val|fun|type|let|struct|openop|end|in) + [ codeuse ] (dec|end|in) --> dec (dec|end|in) + [ codeuse ] semi (dec|end|in) --> dec semi (dec|end|in) + +id dot id --> id +ty dot id --> ty + +sig <indent-force> dec <outdent-force> end --> sig_body +signature <"\\"-space> id* equal <indent-force> sig_body <outdent> --> dec +functor [ <"\\"-space> id* ] --> functor funhead +functor funhead pat equal <force-indent> struct_object <outdent> --> dec +struct <force-indent> dec <force-outdent> end --> struct_object +openop <"\\"-space> id --> dec + +exception <"\\"-space> --> exlook +exlook eb --> dec +exlook [ id* ] !(of|equal) --> exlook eb !(of|equal) +exlook [ id* <"\\"-space> of <"\\"-space> ] --> exlook tylook +exlook [ tylook <"\\"-space> ty ] --> exlook eb +exlook [ id* equal id ] --> exlook eb +eb and --> exlook + +(tylook|tyopen|tys|tya|datatop|datarest) [ id ] --> (tylook|tyopen|tys|tya|datatop|datarest) ty +(tylook|tyopen|tys|tya|datatop|datarest) [ ty <"\\"-space> id ] --> (tylook|tyopen|tys|tya|datatop|datarest) ty +(tylook|tyopen|tys|tya|datatop|datarest) [ ocurly labty ccurly ] --> (tylook|tyopen|tys|tya|datatop|datarest) ty +(tylook|tyopen|tys|tya|datatop|datarest) ocurly [ id tylook ty ] !id --> (tylook|tyopen|tys|tya|datatop|datarest) ocurly labty !id +(tylook|tyopen|tys|tya|datatop|datarest) [ ocurly labty comma ] --> (tylook|tyopen|tys|tya|datatop|datarest) ocurly +(tylook|tyopen|tys|tya|datatop|datarest) [ open ] --> (tylook|tyopen|tys|tya|datatop|datarest) tyopen +(tylook|tyopen|tys|tya|datatop|datarest) [ tyopen ty close ] --> (tylook|tyopen|tys|tya|datatop|datarest) ty +(tylook|tyopen|tys|tya|datatop|datarest) [ tys ty close <"\\"-space> id ] --> (tylook|tyopen|tys|tya|datatop|datarest) ty +tys ty comma --> tys +tys ty <"\\ST"> star --> tys +tys ty close --> ty +(tylook|tyopen|tys|tya|datatop|datarest) [ tyopen ty comma ] --> (tylook|tyopen|tys|tya|datatop|datarest) tys +(tylook|tyopen|tys|tya|datatop|datarest) [ tyopen ty <"\\ST"> star ] --> (tylook|tyopen|tys|tya|datatop|datarest) tys +tick const <"}"> id --> ty +tick <"}"> id --> ty +(tylook|tyopen|tys|tya|datatop|datarest) [ ty fnarrow ] --> (tylook|tyopen|tys|tya|datatop|datarest) tya +tya ty --> ty + +val <"\\"-space> rec --> val +val [ <"\\"-space> pat* <"\\"-space> equal <"\\"-space-indent-opt-1> math <outdent> ] (semi|val|fun|type|let|struct|openop|and|end|close|in|val) --> val valbody (semi|val|fun|type|let|struct|openop|and|end|close|in|val) +val [ <"\\"-space> pat* ] (semi|val|fun|type|let|struct|openop|and|end|close|in|val) --> val valbody (semi|val|fun|type|let|struct|openop|and|end|close|in|val) +val [ <"\\"-space> pat* <"\\"-space> equal <indent-force> multimath <outdent> ] (semi|val|fun|type|let|struct|openop|and|end|close|in) --> val valbody (semi|val|fun|type|let|struct|openop|and|end|close|in) +<force> val valbody <force> and --> val +<force> val valbody --> dec +datatop <"\\"-space-indent> codeuse <force> --> datahead +datatop <"\\"-space> ty* <"\\"-space-indent> equal <force> --> datat +datarest <"\\"-space> ty* <"\\"-space> equal <"\\"-space-indent-opt-2> id <"\\"-space> of <"\\"-space> --> datarest +(datat|datam) <"\\"-space> id <"\\"-space> of <"\\"-space> --> datarest +[ datat <"\\"-space> id* <"\\"-space-opt-1> choice ] id !of --> datat id !of +[ datat <"\\"-space> id* <force> choice ] id of --> datam id of +datam <"\\"-space> id* <force> choice --> datam +[ datat <"\\"-space> ty ] comma --> datahead comma +[ datat <"\\"-space> ty ] <"\\ST"> star --> datahead star +[ datarest ty ] !(equal|ignore_scrap) --> datahead !(equal|ignore_scrap) +datahead comma --> datarest +datahead <"\\ST"> star --> datarest +datahead <force> choice --> datam +[ (datat|datam) <"\\"-space> id <outdent-outdent> ] (semi|val|fun|type|datatype|let|struct|openop|end|in) --> dec (semi|val|fun|type|datatype|let|struct|openop|end|in) +[ datahead <outdent-outdent> ] (semi|val|fun|type|datatype|let|struct|openop|end|in) --> dec (semi|val|fun|type|datatype|let|struct|openop|end|in) +datat <"\\"-space> id <outdent-force> (and|withtype) --> datatop +datahead <outdent-force> (and|withtype) --> datatop +datatype <indent> --> datatop +abstype <indent> --> datatop +datahead <outdent-outdent-force> with <indent-force> dec <outdent-force> end --> dec +type <"\\"-space> ty --> type +type pat [ equal ] --> type pat tylook +[ type <"\\"-space> pat* tylook ty ] (semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) --> dec (semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) +[ type <"\\"-space> pat* ] (semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) --> dec (semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) + +(equal|arrow) [ <cancel-"\\SS"-space> let ] --> (equal|arrow) letf +!(ignore_scrap|equal|arrow) [ let ] --> !(ignore_scrap|equal|arrow) letf +letf <indent-force> dec <outdent-force> in <indent-force> (math|multimath) <outdent-force> end --> multimath +local <indent-force> dec <outdent-force> in <indent-force> dec <outdent-force> end --> dec + +dec <cancel> semi <force> --> dec +[ (math|multimath) <cancel> semi ] dec --> dec dec +[ (math|multimath) ] dec --> dec dec +dec [ <force> (math|multimath) ] (semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) --> dec dec (semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) +[ dec <force> dec ] !(semi|ignore_scrap) --> dec !(semi|ignore_scrap) + +[ case <"\\"-space> (math|multimath) <indent-force> of multimatch <outdent> ] (close|semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) --> multimath (close|semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) +[ <indent-force> fn (multimatch|match) <outdent> ] (close|semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) --> multimath (close|semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) +[ (math|multimath) <indent-indent-force> handle <indent-indent-indent> (multimatch|match) <outdent-outdent-outdent-outdent-outdent> ] (close|semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) --> multimath (close|semi|val|fun|type|datatype|let|struct|openop|end|in|with|withtype|and) + +[ <"\\"-space> pat <"\\"-space> arrow <indent-indent-"\\"-space-opt-3> math <outdent-outdent-opt-1> ] (choice|semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) --> match (choice|semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) +[ <"\\"-space> pat <"\\"-space> arrow <indent-indent-force> multimath <outdent-outdent> ] (choice|semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) --> multimatch (choice|semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) +(match|multimatch) <force-"\\"-space> choice (match|multimatch) --> multimatch +[ match ] (semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) --> multimatch (semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) + +fun [ <"\\"-space> id* ] --> fun funhead +fun funbody <force-"\\"-space-"\\"-space> choice <"\\"-space> --> fun +[ fun funbody ] (in|semi|val|fun|type|datatype|let|struct|openop|end) --> dec (in|semi|val|fun|type|datatype|let|struct|openop|end) +fun funbody <force> and --> fun +fun [ funhead <"\\"-space> pat <"\\"-space> equal <indent-indent-"\\"-space-opt-1> math <outdent-outdent> ] !(binop|handle|math|id|open|multimath|ignore_scrap) --> fun funbody !(binop|handle|math|id|open|multimath|ignore_scrap) +fun [ funhead <"\\"-space> pat <"\\"-space> equal <indent-indent-force> multimath <outdent-outdent-force> ] !(binop|handle|math|id|open|multimath|ignore_scrap) --> fun funbody !(binop|handle|math|id|open|multimath|ignore_scrap) + +equal [ <force> multimath ] --> equal math +[ if <"\\"-space> (math|multimath) <"\\"-space> then <indent-force> (math|multimath) <outdent-force> else <indent-force> (math|multimath) <outdent> ] (choice|semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) --> multimath (choice|semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) + +[ while <"\\"-space> (math|multimath) <"\\"-space> do <indent-force> <"\\"-space> (math|multimath) <outdent> ] (choice|semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) --> multimath (choice|semi|val|fun|type|datatype|let|struct|openop|end|close|in|with|withtype|and) + +apat --> pat +(choice|funhead|of|fn|handle|val|type) [ (pat|id) <"\\"-space> (apat|id) ] --> (choice|funhead|of|fn|handle|val|type) pat +[ pat tylook ty ] !(fnarrow|id|dot|ignore_scrap) --> pat !(fnarrow|id|dot|ignore_scrap) +pat (binop|star) (math|pat) --> pat +pat <"\\"-space> pat --> pat + +underline --> apat +(choice|funhead|of|fn|handle|val|type|opat|pat) [ id ] --> (choice|funhead|of|fn|handle|val|type|opat|pat) apat +(choice|funhead|of|fn|handle|val|type|opat|pat) [ const ] --> (choice|funhead|of|fn|handle|val|type|opat|pat) apat +(choice|funhead|of|fn|handle|val|type|opat|pat) [ open ] --> (choice|funhead|of|fn|handle|val|type|opat|pat) opat +(choice|funhead|of|fn|handle|val|type|opat|pat) [ open <"\\,"> close ] --> (choice|funhead|of|fn|handle|val|type|opat|pat) apat +opat close --> apat +opat pat close --> apat +opat pat comma --> opat +[ open ] pat --> opat pat + +ocurly id equal math --> ocmath +(ocurly|ocurlym) id equal multimath --> ocmulti +ocmath comma --> ocurly +ocmath ccurly --> math +ocmulti comma --> ocurlym +ocmulti ccurly --> multimath +ocurly ccurly --> const +(choice|funhead|of|fn|handle|val|type|opat|pat) [ ocurly labpat ccurly ] --> (choice|funhead|of|fn|handle|val|type|opat|pat) apat +(choice|funhead|of|fn|handle|val|type|opat|pat) ocurly id [ equal ] --> (choice|funhead|of|fn|handle|val|type|opat|pat) ocurly id choice +(choice|funhead|of|fn|handle|val|type|opat|pat) ocurly [ id choice pat ] --> (choice|funhead|of|fn|handle|val|type|opat|pat) ocurly labpat +(choice|funhead|of|fn|handle|val|type|opat|pat) ocurly [ id ] !equal --> (choice|funhead|of|fn|handle|val|type|opat|pat) ocurly labpat !equal +(choice|funhead|of|fn|handle|val|type|opat|pat) [ ocurly labpat comma ] --> (choice|funhead|of|fn|handle|val|type|opat|pat) ocurly + +raise <"\\"-space> math --> math +math comma math --> math +math (binop|star) math --> math +unop math --> math +(math|multimath) <cancel-space-force> comma <cancel> (multimath|math) --> multimath +(math|multimath) (binop|star) (math|multimath) --> multimath +unop (math|multimath) --> multimath +math <"\\"-space> math --> math +(math|multimath) <"\\"-space> (math|multimath) --> multimath + +open <"\\,"> close --> const +[ open <indent> math <outdent> close <opt-1> ] !(ignore_scrap|close|semi|val|fun|type|datatype|let|struct|openop|in|with|withtype|end) --> math !(ignore_scrap|close|semi|val|fun|type|datatype|let|struct|openop|in|with|withtype|end) +[ open <indent-opt-3> math <outdent> close ] (close|semi|val|fun|type|datatype|let|struct|openop|in|with|withtype|end) --> math (close|semi|val|fun|type|datatype|let|struct|openop|in|with|withtype|end) +[ (math|multimath) <force-backup-"\\SS\\SS"> semi <"\\SS"> (math|multimath) ] (semi|val|fun|type|datatype|let|struct|openop|close|end) --> multimath (semi|val|fun|type|datatype|let|struct|openop|close|end) +(then|semi|else|in|equal|arrow) [ open <indent-"\\"-space-"\\"-space> multimath <outdent-force-"\\SS\\SS"> close ] --> (then|semi|else|in|equal|arrow) multimath +!(then|semi|else|in|equal|arrow) [ open <indent-indent-force> multimath <outdent-force-"\\"-space-"\\"-space> close <outdent> ] --> !(then|semi|else|in|equal|arrow) multimath + +math [ equal ] --> math binop +[ math tylook ty ] !(ignore_scrap|id|dot|fnarrow) --> pat !(ignore_scrap|id|dot|fnarrow) +id <"\\"-space> math --> math +(multimath|semi|equal|dec|while|do|case|then|else|if|in|with|withtype|open|raise|arrow|comma|math|binop|star|unop) [ id ] !dot --> (multimath|semi|equal|dec|while|do|case|then|else|if|in|with|withtype|open|raise|arrow|comma|math|binop|star|unop) math !dot +(multimath|semi|equal|dec|while|do|case|then|else|if|in|with|withtype|open|raise|arrow|comma|math|binop|star|unop) [ const ] --> (multimath|semi|equal|dec|while|do|case|then|else|if|in|with|withtype|open|raise|arrow|comma|math|binop|star|unop) math + +? ignore_scrap --> #1 +ignore_scrap ? --> #2 + +macros begin +\let\AR=\Longrightarrow +macros end +---------------------------------end of sml.spider------------- +---------------------------------start of denote.web------------- +\def\topofcontents{\relax\ifodd\pageno\else\null\vfill\eject\null\fi\titletrue\null\vfill + \centerline{\titlefont Denotional Semantics and} + \centerline{\titlefont an {\ttitlefont ML} Interpreter} + \centerline{\titlefont for a Functional Programming Language} + \vfill + \centerline{Table of Contents} +} +\def\botofcontents{\null\vfill + \centerline{\copyright\ 1991, Dave Mason {\tt <dmason@plg.uwaterloo.ca>}} +} +\let\contentspagenumber=\pageno + +\def\ME#1{{\ifmmode\lbrack\!\lbrack#1\rbrack\!\rbrack\else$\lbrack\!\lbrack$#1$\rbrack\!\rbrack$\fi}} +\def\Me#1{{\bf Me}\ME{#1}} +\def\St{\relax\ifmmode\sigma\else$\sigma$\fi} +\def\Co{\relax\ifmmode\theta\else$\theta$\fi} +\def\CO{\relax\ifmmode\Theta\else$\Theta$\fi} +\def\IV{\relax\ifmmode\Xi\else$\Xi$\fi} +\def\En{\relax\ifmmode\rho\else$\rho$\fi} +\def\Ex{\relax\ifmmode\varepsilon\else$\varepsilon$\fi} +\def\Sy{\relax\ifmmode\xi\else$\xi$\fi} +\def\Nu{\relax\ifmmode\nu\else$\nu$\fi} +\def\Lo{\relax\ifmmode\phi\else$\phi$\fi} +\def\Tp#1#2{\langle{#1},{#2}\rangle} + %*Denotational Semantics. Denotational semantics is a formal method +to specify the meaning of programming languages. We define an +abstract syntax for the language (|Term|), a meaning function (|Me|), +a polymorphic store (|store|) and a polymorphic environment (|env|). + +The code is laid out in this document in a logical form (rather than +slavishly following the order the compiler wants), but we +must force the \.{ML} code into the right order to make sure that +things are defined before use. + %c + %<Type Definitions%> + %<Functions%> + %<Meaning Function%>; + %<Test Cases%> + + % This is the type of possible declarations, along with the start of +the definition of possible terms. They are mutually recursive +definitions so they must be connected by an |and|. The actual +declaration type are explained below in the definition of the semantic +function for declarations. + %<Type Definitions%>= +datatype Decl = + Var_Decl of string * Term + | Val_Decl of string * Term + | Rec_Decl of string * Term +and + %<Term Definition%>; + + %*|Term| and |Me|. We define the datatype for the abstract syntax +tree and the meaning function in parallel. \.{Web} will worry about +putting it all together in the right order. + +The meaning function has to have type: + + |Me : Term -> (Value env) -> (Value continuation) -> (Value store) -> (Value * (Value store)) |. + + That is, it maps abstract syntax trees, environments, continuations, +and stores to a value,store pair. + + % The denotational semantics are given in terms of the following: + \medskip + \itemitem {\bf Me} - this is the meaning function itself. + \itemitem {\IV} - is an invalid value + \itemitem {\Ex} - an expression + \itemitem {\Sy} - a symbol + \itemitem {\Nu} - a number + \itemitem {\En} - the environment (bindings from names to values) + \itemitem {\Co} - this is the continuation + \itemitem {\CO} - this is a null continuation that simply returns the value + \itemitem {\St} - this is the store of values + \itemitem {\Lo} - a location in the store + \itemitem {$x[e/v]$} - a substitution of the expression $e$ for the name +(or whatever) $v$, where $x$ is usually \En\ or \St + \itemitem {$x\ME{v}$} - $v$ in the context of $x$, where $x$ is {\bf Me}, +\En, \St, {\bf O} or {\bf V} + \itemitem {$\Tp{x}{y}$} - the tuple composed of $x$ and $y$ + \itemitem {$\{e\}$} - a continuation that evaluates $e$ in the current +context + \medskip + \noindent When either of the environment or store are omitted, the +environment or store from the enclosing environment is assumed. + + + % The first type of term is the name of a variable or constant. The +meaning of a name is the value that the environment contains for that +name. For variables, this value is the location in the store where +the value may be found. + %<Term Definition%>= + Term = Var of string + % $\Me{\Sy}\En\Co\St=\Co\Tp{\En\ME{\Sy}}{\St}$ + %<Meaning Function%>= + fun Me (Var x) e c s = c (lookup x e ,s) + |; + + % Integer constants. + %<Term Definition%>= + |: Numeral of int + % $\Me{\Nu}\En\Co\St=\Co\Tp{{\bf V}\ME{\Nu}}{\St}$ + %<Meaning Function%>= + |= Me (Numeral n) e c s = c (intValue n,s) + |; + + %*Declarations. + +Declarations come in 3 flavours: {\tt val}, {\tt rec}, and {\tt +var}. For all three, the declaration only holds for the evaluation of +the expression with which it is composed. {\tt val} introduces a +constant. {\tt rec} is similar but the symbol is introduced into the +environment of the expression (which must be a function) to allow for +recursive calls. {\tt var} introduces a variable. + %<Term Definition%>= + |: Decl of Decl * Term + % $\Me{{\tt var}~\Sy~{\tt =}~\Ex_1~{\tt ;}~\Ex_2}\En\Co\St=\Me{\Ex_2}\En[\Lo/\Sy]\Co\St[\Me{\Ex_1}\En\CO\St/\Lo]$ + %<Meaning Function%>= + |= Me (Decl (Var_Decl (x,V),E)) e c s = + Me V e (fn (R,_) => let + val (S,L) = new s R; + val nE = bind x (lvalueValue L) e; + in Me E nE c S end) s + |; + + % $\Me{{\tt val}~\Sy~{\tt =}~\Ex_1~{\tt ;}~\Ex_2}\En\Co\St=\Me{\Ex_2}\En[\Me{\Ex_1}\En\CO\St/\Sy]\Co\St$ + %<Meaning Function%>= + |= Me (Decl (Val_Decl (x,V),E)) e c s = + Me V e (fn (R,_) => Me E (bind x R e) c s)s + |; + + % The interpretation of the recursive declaration ($\Me{{\tt +rec}~\Sy~{\tt =}~\Ex_1~{\tt ;}~\Ex_2}\En\Co\St$) is fairly difficult +to describe, short of translating the ML code. There are a couple of +ways of doing this, but the one I chose is to implement the Y +combinator ({\tt fix}) in the language and then apply it to the +functional we want to make recursive. To bootstrap the process, we +put an entry for {\tt fix} into the environment as a var name with an +initial binding to an invalid value, which we replace once we have a +definition for the function proper. If we were looking for +efficiency, we'd put these in the initial environment and store. + %<Meaning Function%>= + |= Me (Decl (Rec_Decl (x,V),E)) e c s = let + val fixpoint=Proc ("fix-f", + Proc ("fix-x", App (App (Var "fix-f", + App (Deref (Var "fix"),Var "fix-f")) + ,Var "fix-x"))); + val (S,L) = new s invalidValue; + val nE = bind "fix" (lvalueValue L) e; + in + Me fixpoint nE ( + fn (FIX,_) => Me (App (Deref (Var "fix"),Proc(x,V))) nE ( + fn (funcValue R,S) => Me E (bind x (funcValue R) e) c S + |_=>raise NotFuncDecl) (update S L FIX) + ) S + end + + |; + + %*Function operations. + + Function abstraction. Define a function of one parameter bound in +the scope of the expression. + %<Term Definition%>= + |: Proc of string * Term + % $\Me{{\tt proc}~\Sy~{\tt =>}~\Ex}\En\Co\St=\Co\Tp{\lambda\Co'.\lambda\Tp{V}{\St'}.\Me{\Ex}\En[V/\Sy]\Co'\St'}{\St}$ + %<Meaning Function%>= + |= Me (Proc (x,E)) e c s = + c (funcValue (fn C => fn (V,S) => Me E (bind x V e) C S ),s) + |; + + % Function Application. Supply one parameter to the function and +execute the function. + %<Term Definition%>= + |: App of Term * Term + % The interpretation of function application +($\Me{\Ex_1{\tt(}\Ex_2{\tt)}}\En\Co\St$) is basically going to be a translation +of the ML code. + %<Meaning Function%>= + |= Me (App (E1,E2)) e c s = + Me E1 e (fn (funcValue f,_) => + Me E2 e (fn VS => f c VS) s + |_ =>raise NotFunc + ) s + |; + + % Call the specified function passing our continuation as a +functional parameter. + %<Term Definition%>= + |: Callcc of Term + + % The interpretation of function application +($\Me{{\tt callcc}~\Ex}\En\Co\St$) is basically going to be a translation +of the ML code. + %<Meaning Function%>= + |= Me (Callcc E) e c s = + Me E e (fn (funcValue f,_) => + f c (funcValue (fn (C:Value continuation) => c),s) + |_ =>raise NotFunc + )s + |; + + %*Operations on Pairs. + + Create a pair from the values of two expressions. + %<Term Definition%>= + |: Pair of Term * Term + % $\Me{{\tt <}\Ex_1{\tt ,}\Ex_2{\tt >}}\En\Co\St=\Co\Tp{\Me{\Ex_1}\En\CO\St}{\Me{\Ex_2}\En\CO\St}$ + %<Meaning Function%>= + |= Me (Pair (E1,E2)) e c s = + Me E1 e (fn (V1,_) => + Me E2 e (fn (V2,S) => c (pairValue (V1,V2),s)) s + ) s + |; + + % Get the first element from a pair. + %<Term Definition%>= + |: Fst of Term + % $\Me{{\tt fst}~\Ex}\En\Co\St=\Co\Tp{\pi_1(\Me{\Ex}\En\CO\St)}{\St}$ + %<Meaning Function%>= + |= Me (Fst T) e c s = + Me T e (fn + (pairValue (T1,T2),_) => c (T1,s) + | _ => raise NotPair) s + |; + + % Get the second element from a pair. + %<Term Definition%>= + |: Snd of Term + % $\Me{{\tt snd}~\Ex}\En\Co\St=\Co\Tp{\pi_2(\Me{\Ex}\En\CO\St)}{\St}$ + %<Meaning Function%>= + |= Me (Snd T) e c s = + Me T e (fn + (pairValue (T1,T2),_) => c (T2,s) + | _ => raise NotPair) s + |; + + %*Flow of control. + + Conditional execution. Only one of the then or else expressions +will be executed. + %<Term Definition%>= + |: Cond of Term * Term * Term + % $\Me{{\tt if}~\Ex_1~{\tt then}~\Ex_2~{\tt else}~\Ex_3~{\tt +fi}}\En\Co\St= +(if~\Me{\Ex_1}\En\CO\St={\tt true}~then~\Me{\Ex_2}~else~\Me{\Ex_3})\En\Co\St$ + %<Meaning Function%>= + |= Me (Cond (E1,E2,E3)) e c s = + Me E1 e (fn (boolValue true,_) => Me E2 e c s + |(boolValue false,_)=> Me E3 e c s + |_ => raise NotBool + ) s + |; + + % Expression composition. Execute the expressions sequentially. + %<Term Definition%>= + |: Seq of Term * Term + % $\Me{\Ex_1{\tt ;}\Ex_2}\En\Co\St=\Me{\Ex_1}\En\{\Me{\Ex_2}\En\Co\}\St$ + %<Meaning Function%>= + |= Me (Seq (E1,E2)) e c s = + Me E1 e (fn (V,S) => Me E2 e c S) s + |; + + % Indefinite iteration. Execute the second expression as long as the +first expression evaluates to {\tt true}. + %<Term Definition%>= + |: While of Term * Term + % $\Me{{\tt while}~\Ex_1~{\tt do}~\Ex_2~{\tt od}}\En\Co\St=(if~ +\Me{\Ex_1}\CO\St={\tt true}~then~\Me{\Ex_2}\En\{\Me{{\tt +while}\ldots}\En\Co\}~else~\Co)\St$ + %<Meaning Function%>= + |= Me (While (E1,E2)) e c s = + Me E1 e (fn (boolValue true,S) => Me E2 e (fn (V,S) => + Me (While (E1,E2)) e c S + ) S + |(boolValue false,S)=> c (invalidValue,S) + |_ => raise NotBool + ) s + |; + + %*Storage References and Updates. + + Allocate storage for a value and return the location of the value +in the store. + %<Term Definition%>= + |: Ref of Term + % $\Me{{\tt ref}~\Ex}\En\Co\St=\Co\Tp{\Lo}{\St[\Me{\Ex}\En\CO\St/\Lo]}$ + %<Meaning Function%>= + |= Me (Ref E) e c s = + Me E e (fn (V,_) => let + val (nS,L) = new s V; + in + c (lvalueValue L,nS) + end + ) s + |; + + % Given the location of a datum, get the value currently stored there. + %<Term Definition%>= + |: Deref of Term + % $\Me{{\tt .}\Ex}\En\Co\St=\Co\Tp{\St\ME{\Me{\Ex}\En\CO\St}}{\St}$ + %<Meaning Function%>= + |= Me (Deref E) e c s = + Me E e (fn + (lvalueValue V,S) => c (access S V,s) + |_=>raise NotLValue) s + |; + + % Modify the storage at the location specified by the first +expression to have the value of the second expression. + %<Term Definition%>= + |: Assign of Term * Term + % $\Me{\Ex_1{\tt :=}\Ex_2}\En\Co\St=\Co\Tp{\Me{\Ex_2}\En\CO\St}{\St[\Me{\Ex_2}\En\CO\St/\Me{\Ex_1}\En\CO\St]}$ + %<Meaning Function%>= + |= Me (Assign (E1,E2)) e c s = + Me E1 e (fn + (lvalueValue L,_) => Me E2 e (fn (V,_) => + c (V,update s L V)) s + |_=>raise NotLValue + + ) s + |; + + %*Integer Operations. + + Add two integers together. + %<Term Definition%>= + |: Add of Term * Term + % $\Me{\Ex_1{\tt +}\Ex_2}\En\Co\St=\Co\Tp{{\bf O}\ME{+}(\Me{\Ex_1}\En\CO\St,\Me{\Ex_2}\En\CO\St)}{\St}$ + %<Meaning Function%>= + |= Me (Add (E1,E2)) e c s = + Me E1 e (fn (intValue V1,_) => + Me E2 e (fn (intValue V2,_) => c (intValue (V1+V2),s) + |_ => raise NotInteger) s + |_ => raise NotInteger) s + |; + + % Multiply two integers. + %<Term Definition%>= + |: Mult of Term * Term + % $\Me{\Ex_1{\tt *}\Ex_2}\En\Co\St=\Co\Tp{{\bf O}\ME{\times}(\Me{\Ex_1}\En\CO\St,\Me{\Ex_2}\En\CO\St)}{\St}$ + %<Meaning Function%>= + |= Me (Mult (E1,E2)) e c s = + Me E1 e (fn (intValue V1,_) => + Me E2 e (fn (intValue V2,_) => c (intValue (V1*V2),s) + |_ => raise NotInteger) s + |_ => raise NotInteger) s + |; + + % Calculate the negative of an integer. + %<Term Definition%>= + |: Neg of Term + % $\Me{{\tt -}\Ex}\En\Co\St=\Co\Tp{-\Me{\Ex}\En\CO\St}{\St}$ + %<Meaning Function%>= + |= Me (Neg E) e c s = + Me E e ( fn (intValue V,_) => c (intValue (0-V),s) + |_ => raise NotInteger) s + |; + + %* Boolean Operations. +Determine if the first integer expression is lower in value than +the second. Return a boolean truth value. + %<Term Definition%>= + |: Less of Term * Term + % $\Me{\Ex_1{\tt <}\Ex_2}\En\Co\St=\Co\Tp{{\bf O}\ME{<}(\Me{\Ex_1}\En\CO\St,\Me{\Ex_2}\En\CO\St)}{\St}$ + %<Meaning Function%>= + |= Me (Less (E1,E2)) e c s = + Me E1 e (fn (intValue V1,_) => + Me E2 e (fn (intValue V2,_) => c (boolValue (V1<V2),s) + |_ => raise NotInteger) s + |_ => raise NotInteger) s + |; + + % Calculate the boolean complement of the expression. + %<Term Definition%>= + |: Not of Term + % $\Me{\neg\Ex}\En\Co\St=\Co\Tp{\neg\Me{\Ex}\En\CO\St}{\St}$ + %<Meaning Function%>= + |= Me (Not E) e c s = + Me E e ( fn (boolValue true,_) => c (boolValue false,s) + |(boolValue false,_) => c (boolValue true,s) + |_ => raise NotBool ) s + |; + + %*Environments. An environment captures the bindings of names to +values (in this case locations). This trivial implementation has +dreadful performance, but it is at least fairly obviously correct. + %<Type Definitions%>= +abstype 'a env = Env of string->'a with + exception unbound_variable of string; + val newenv = Env (fn x => raise unbound_variable x); + fun bind x t (Env f) = Env(fn y => if x=y then t else f y); + fun lookup x (Env f) = f x +end; + + %*Stores. A store binds locations to values. Once again, this is +just about the most inefficient implementation you could come up with +(although there actually was a bug in the first version). A store can +be thought of as a mapping from locations to values, where new +locations are created on demand. + %<Type Definitions%>= +abstype 'a store = Store of int * (int->'a) +and lvalue = lvalue of int +with + exception segmentation_violation; + val newstore = Store (0, fn x => raise segmentation_violation); + fun new (Store (avail,f)) v = + (Store (avail+1, fn l=>if l=avail then v else f l), lvalue(avail)); + fun access (Store (_,f)) (lvalue loc) = f loc; + fun update (Store (avail,f)) (lvalue loc) v = + Store (avail, fn l=>if l=loc then v else f l); + end; + + %*Values and Miscellaneous Definitions. Define a continuation to be +a mapping from a value,state pair to a resulting value,state. + %<Type Definitions%>= +type 'a continuation = ('a * 'a store) -> ('a * 'a store); + + % Values. These are the set of values that can result from a +computation. Only the first 3 of these were in the original problem +description. I added the others to make the language/interpreter more +useful and to catch and report errors. + %<Type Definitions%>= +datatype Value = + intValue of int + | lvalueValue of lvalue + | funcValue of Value continuation -> Value continuation + | boolValue of bool + | pairValue of Value*Value + | invalidValue + |Missing_Name of string + ; + + % These are exceptions that are raised by the semantic function when +values are inappropriate. + %<Type Definitions%>= + exception NotImplemented; + exception NotCorrect; + exception NotPair; + exception NotLValue; + exception NotBool; + exception NotInteger; + exception NotFunc; + exception NotFuncDecl; + + % Here is an \.{ML} version of the Y fix point operator. We could use it +for to implement recursion. It would only be a minor change to make +the semantic function use this rather than use \.{ML}'s builtin recursion. + %<Functions%>=fun fix f x = f (fix f) x; + + % The empty continuation. + %<Functions%>=fun nullContinuation x = x; + + %*Test of the Machine. Testing is no substitute for correct +implementation, but it is somewhat heartwarming to see such an +abstract interpreter actually work. + + First of all define a |test| function that will accept any program in +the language and execute it, returning the result. + %<Test Cases%>= + fun test n = let + val (V,S) =Me n newenv nullContinuation newstore handle + unbound_variable x => (Missing_Name x,newstore); + in V end; + % A few dead simple tests to show that integers and pairs work +properly. + %<Test Cases%>= + test (Numeral 3); + test (Neg (Add (Numeral 3,Numeral 39))); + test (Fst (Pair (Numeral 3,Numeral 4))); + test (Snd (Pair (Numeral 3,Numeral 4))); + test (Seq (Numeral 3,Numeral 4)); + + % Test binding names, both through value declarations and $\lambda$ +bindings. Also verify that function abstraction, function application, +and call-with-current-continuation work. + %<Test Cases%>= + val X="x";val Y="y";val FIX="fix" and F="f"; + test (Decl (Val_Decl (X,Numeral 29),Var X)); + test (App (Proc (X,Numeral 17),Numeral 7)); + test (App (Proc (X,Add (Var X,Numeral 1)),Numeral 7)); + test (Decl (Val_Decl (X,Proc (Y,Var Y)) + ,Add (Numeral 3,App (Var X,Numeral 55)))); + test (Decl (Val_Decl (X,Proc (Y, + Seq (App (Var Y,Numeral 33),Numeral 44))) + ,Add (Numeral 3,Callcc (Var X)))); + % Now for some real excitement: recursive functions. Surprise! +Surprise! They actually work. + %<Test Cases%>= + val fact=Rec_Decl (X,Proc (Y, + Cond (Less (Var Y + ,Numeral 2) + ,Numeral 1 + ,Mult (App (Var X + ,Add (Var Y + ,Neg (Numeral 1) + ) + ) + ,Var Y + ) + ))); + test (Decl (fact + ,App (Var X + ,Numeral 1))); + test (Decl (fact + ,App (Var X,Numeral 5))); + % Ok, so let's use some CPU time! Try fibonacci + %<Test Cases%>= + val fib=Rec_Decl (X,Proc (Y, + Cond (Less (Var Y + ,Numeral 2) + ,Numeral 1 + ,Add (App (Var X + ,Add (Var Y + ,Neg (Numeral 1) + ) + ) + ,App (Var X + ,Add (Var Y + ,Neg (Numeral 2) + ) + ) + ) + ))); + test (Decl (fib + ,App (Var X + ,Numeral 1))); + test (Decl (fib + ,App (Var X,Numeral 5))); + test (Decl (fib + ,App (Var X,Numeral 10))); + test (Decl (fib + ,App (Var X,Numeral 15))); + test (Decl (fib + ,App (Var X,Numeral 20))); + test (Decl (fib + ,App (Var X,Numeral 25))); + test (Decl (fib + ,App (Var X,Numeral 28))); + % Finally test that reference bindings and iteration work properly. + %<Test Cases%>= + test (Assign (Ref (Numeral 2),Numeral 3)); + test (Decl (Var_Decl (X,Numeral 1) + ,Deref (Var X))); + test (Decl (Var_Decl (X,Numeral 1) + ,Seq (Assign (Var X + ,Add (Numeral 22,Deref (Var X))) + ,Deref (Var X)))); + test (Decl (Var_Decl (X,Numeral 1) + ,(Decl (Var_Decl (Y,Numeral 0) + ,Seq (While + (Less (Deref (Var X),Numeral 11) + ,Seq (Assign (Var Y + ,Add (Deref (Var Y),Deref (Var X))) + ,(Assign (Var X + ,Add (Numeral 1,Deref (Var X))))) + ) + ,Deref (Var Y)) + )))); + + %*Index. +---------------------------------end of denote.web------------- + diff --git a/web/spiderweb/src/ssl/make b/web/spiderweb/src/ssl/make new file mode 100644 index 0000000000..115eb3d665 --- /dev/null +++ b/web/spiderweb/src/ssl/make @@ -0,0 +1,2 @@ +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype` \ + THETANGLE=stangle THEWEAVE=sweave SPIDER=s.spider $* diff --git a/web/spiderweb/src/ssl/s.spider b/web/spiderweb/src/ssl/s.spider new file mode 100644 index 0000000000..ba3ef93a10 --- /dev/null +++ b/web/spiderweb/src/ssl/s.spider @@ -0,0 +1,220 @@ +# Copyright 1989 by Norman Ramsey, Odyssey Research Associates +# Not to be sold, but may be used freely for any purpose +# For more information, see file COPYRIGHT in the parent directory +language Synthesizer extension ssl + +at_sign # + +comment begin <"/*"> end <"*/"> + +default translation <*> mathness yes + +token identifier category simp mathness yes +token number category literal mathness yes +token newline category ignore_scrap mathness maybe translation <> +token pseudo_semi category semi mathness maybe translation <> + +module definition decl use math + +token + category binop +token - category unorbinop +token * category star +token / category binop +token < category less translation <> +token > category greater translation <> +token = category binop +token . category binop +token ^ category at translation <"\\H"> +token ~ category unorbinop translation <"\\TI"> +token & category unop translation <"\\AMP"> +token ? translation <"\\?"> category question +token % translation <"\\%"> category binop +token @ category at mathness no +token .. category at translation <".."> +# following must tangleto " # " because # at beginning of line freaks +# The preprocessor -- this doesn't look like preproc directive... +token # translation <"\\SH"> category unorbinop tangleto <space-"#"-space> +token ( category open +token [ category lbrack +token ) category close +token ] category close +token { translation <"\\{"> category lbrace +token } translation <"\\}"> category close +token , category comma +token ; category semi +token : category colon +token | category bar +token $ category dollar translation <"\\DO"> +token != name not_eq translation <"\\I"> category binop +token <= name lt_eq translation <"\\L"> category binop +token >= name gt_eq translation <"\\G"> category binop +token == name eq_eq translation <"\\S"> category binop +token && name and_and translation <"\\W"> category binop +token || name or_or translation <"\\V"> category binop +token -> name minus_gt translation <"\\MG"> category binop +token >> name gt_gt translation <"\\GG"> category binop +token << name lt_lt translation <"\\LL"> category binop +token :: name double_colon translation <"::"> category binop +token ::= name produces translation <"\\CCE"> category colon + +macros begin +\def\AMP{{\sl\amp}} +\def\SH{\mathbin{\#}} +\def\CCE{::=} +\def\MG{\mathrel{\to}} +\def\GG{\mathrel{>\!>}} +\def\LL{\mathrel{<\!<}} +\let\LN\langle +\let\RN\rangle +\let\openbraces=\{ +\let\closebraces=\} +\def\{{\ifmmode\openbraces\else$\openbraces$\fi} +\def\}{\ifmmode\closebraces\else$\closebraces$\fi} +\let\dothickspace=\; +\def\;{\ifmmode\dothickspace\else\relax$\dothickspace$\relax\fi} +\let\domedspace=\> +\def\>{\ifmmode\domedspace\else\relax$\domedspace$\relax\fi} +\let\dothinspace=\, +\def\,{\ifmmode\dothinspace\else\relax$\dothinspace$\relax\fi} +\def\?{\mathrel?} +\def\MO{\mathord{}} % to fake out math ::= <force> +macros end + + +ilk and_like category and +ilk in_like category in +ilk let_like category let translation <*-indent-"\\"-space-opt-0> +ilk math_like category math +ilk on_like category on +ilk transform_like category transform +ilk with_like category with + +reserved and ilk and_like +reserved as ilk math_like +reserved class ilk math_like +reserved default ilk math_like +reserved demand ilk math_like +reserved exported ilk math_like +reserved ext_computers ilk math_like +reserved false ilk math_like +reserved foreign ilk math_like +reserved in ilk in_like +reserved inh ilk inh_like +ilk inh_like category math translation <"\\&{inherited}"> +reserved inherited ilk math_like +reserved left ilk math_like +reserved list ilk math_like +reserved let ilk let_like +reserved local ilk math_like +reserved nil ilk math_like +reserved nil_attr ilk math_like +reserved nonassoc ilk math_like +reserved on ilk on_like +reserved optional ilk math_like +reserved prec ilk math_like +reserved repeated ilk math_like +reserved right ilk math_like +reserved root ilk math_like +reserved store ilk math_like +reserved style ilk math_like +reserved syn ilk syn_like +ilk syn_like category math translation <"\\&{synthesized}"> +reserved synthesized ilk math_like +reserved transform ilk transform_like +reserved true ilk math_like +reserved typedef ilk math_like +reserved with ilk with_like + +at colon <opt-3> --> math +at <opt-5> --> math +decl <force> decl --> decl +decl <force> simp* colon <"\\MO"-indent-force> --> mbar +decl simp [ simp* ] --> decl simp math +dollar dollar --> math +dollar --> unop +<force> in open <indent-force> --> wbegin +in --> math +# following for semantic equations and attribute declarations +lbrace <indent-force> (decl) <force> close <outdent-force> --> math +# following for attribution expression +math lbrace close --> math +# following for function declaration MUST PRECEDE "open math close" +# we need (math|decl) because it might hit attribute decl too +open math close lbrace --> openfunc +open math [ close ignore_scrap ] --> open math close +openfunc <indent-force> (math|decl) <force> close <outdent-force> --> math +# Now in the hideous case where we have mistakenly confused an attribution +# expression for a function declaration, we correct our error +openfunc close --> math +# following for upward remote attribute reference +lbrace math close --> math + +lbrack <indent> math <outdent> close --> math + + + +math <force> bar --> math +math colon <"\\MO"> --> mcolon + +math open close --> math +# no space here +math <"\\;"-opt-0> lbrack --> lbrack + +[ star ] colon --> math colon +math star --> unop +star --> math + +math <"\\>"> math --> math +math (binop|unorbinop) math --> math +math unop --> math +(unop|unorbinop) math --> math + +math semi --> decl + +mbar math <force> bar --> mbar +mbar math <force> semi <outdent> --> decl + +mcolon <indent-force> math <force> semi <outdent> --> decl +mcolon <indent-force> math <outdent-force> close --> close +mcolon <indent-force> math comma --> mcmcom + +mcmcom math comma --> mbar +mcmcom <outdent-force> math colon <"\\MO"> --> mcolon + + +math comma <"\\,"> math --> math + + +on --> math +open math close --> math +open close --> math +# The following doesn't do indentation right +# <indent-force> question math <force> colon ? <outdent> - - > #4 +<indent-force> question math <force> colon --> condbegin +[ condbegin math <outdent> ] (semi|close|comma|colon) --> math (semi|close|comma|colon) + +less <"\\LN"> simp <"\\RN"> greater --> math +less <"<"> --> binop +greater <">"> --> binop + +literal <opt-5> --> math +simp --> math +tbegin <indent-force> decl <outdent> --> decl +transform <"\\;"> math --> tbegin +wbegin math close <outdent-force> --> math +wbegin close <outdent-force> --> math +# following for leaving commas in last clause in with statements +wbegin mcmcom <outdent-force> close <outdent-force> --> math +with math (math|semi) --> math +with math <"\\,"> open <indent-force> --> wbegin + +# let statements +math <"\\"-space-opt-3> and <"\\"-space> math --> math +(forcelet|let) math semi <force> --> forcelet +forcelet math <outdent-force> in <"\\"-space> open <indent-force> --> letopen +letopen math <force> close <outdent> --> math +let math in <"\\"-space> open <indent-force> --> letopen +# following recognizes semi as a possible terminator as well as separator +forcelet <backup> in <"\\"-space> open <force> --> letopen + +? ignore_scrap --> #1 diff --git a/web/spiderweb/src/turing+/example.mail b/web/spiderweb/src/turing+/example.mail new file mode 100644 index 0000000000..c1513a4b93 --- /dev/null +++ b/web/spiderweb/src/turing+/example.mail @@ -0,0 +1,195 @@ +From att!surya.ho.att.com!ko Fri Mar 22 10:31:23 1991 +Received: from Princeton.EDU (Princeton.EDU.) by fs.Princeton.EDU (4.0/1.105) + id AA21961; Fri, 22 Mar 91 10:31:21 EST +Received: from att.UUCP by Princeton.EDU (5.61++/2.69/princeton) + id AA18354; Fri, 22 Mar 91 10:31:17 -0500 +Received: from spark.ho.att.com by surya.ho.att.com (4.1/SMI-4.1) + id AA09832; Thu, 21 Mar 91 17:27:35 EST +Date: Thu, 21 Mar 91 17:27:35 EST +From: surya.ho.att.com!ko +Message-Id: <9103212227.AA09832@surya.ho.att.com> +Received: by spark.ho.att.com (4.1/SMI-4.1) + id AA06596; Thu, 21 Mar 91 17:35:07 EST +To: att!att.uucp, nr@Princeton.EDU +Subject: Example file +Status: RO + +Here is an example Turing Web file. Note: I have made a small +modification to "webkernel.tex" by adding \date and \author macros. +These are used in the file that follows. I include the modification +below: + +\def\rhead{\.{WEB} OUTPUT} % this running head is reset by starred sections +\def\title{} % an optional title can be set by the user +% The following two are optional, and can be set by the user. +% (Kostas Oikonomou, Nov. 1990.) +\def\author{} +\def\date{} +\def\topofcontents{\centerline{\titlefont\title}\vskip1cm\centerline{\author} + \vskip0.4cm\centerline{\date}\vfill} % this material will start the table of contents page +\def\botofcontents{\vfill} % this material will end the table of contents page + + + + +----------------------------- paths.web ---------------------------------------- + +\def \title {General Least-Cost Paths in Graphs} +\def \author {Kostas N. Oikonomou} +\def \date {August 1990} + + +% See the TeXbook, p.154 for this! +\font \bbb = msbm10 +\newfam\msbmfam +\textfont\msbmfam=\bbb +\def \Nat {{\fam\msbmfam N}} +\def \Real {{\fam\msbfam R}} +\def \c#1{\vert#1\vert} + +@* The {\it paths\/} module. + +Let $G$ be a complete directed graph on $V=\{0,1,\ldots,n\}$. The edges +are $E=\{(i,j)\mid i<j\}$. Let each edge have a cost (length) $\ell(i,j)$. +The cost of a {\it path\/} from $i$ to $j$ may be defined in various ways, +as a function of the costs (lengths) of the edges that make it up. For +example, it could be the sum of the lengths of the edges, it could be the +length of the longest edge, the length of the shortest edge, etc. We are +interested in finding best (least-cost) paths in $G$ from $i$ to $n$, with +a specified number $m$ of edges. + +We will be able to do this efficiently if the function $C$ defining the +cost of a path $i,i_1,\ldots,i_{m-1},j$ from $i$ to $j$ is s.t. it satisfies +the optimality principle of dynamic programming. That is $C$ must be s.t. +$$ +\min_{(i_1,\ldots,i_{m-1})} C(i,i_1,\ldots,i_{m-1},j) = \min_{i_1} +f \bigl( C(i,i_1), \min_{(i_2,\ldots,i_{m-1})} C(i_1,\ldots,i_{m-1},j) \bigr), \eqno (1) +$$ +where $f(\cdot,\cdot)$ is some function, e.g. ``$+$'', and where the +``min'' could be replaced by ``max''. (An interesting recent reference on +generalizations of the optimality principle and related subjects is {\sl +Generalized Dynamic Programming for Stochastic Combinatorial +Optimization\/}, Carraway et al., Op. Res., Vol. 37, No. 5, 1989.) +Although our $G$ is directed, so that the minima in (1) are to be taken +over sequences such as $i<i_1<\cdots<i_{m-1}<j$, it should be clear that +(1) also applies to a complete undirected $G$, if the minima are taken over +unconstrained paths. + +Module |paths| contains a procedure |least_cost| which, given the function +$f$ appearing in (1), returns in $c^*(1..m)$ the cost of the best 0-to-$n$ +paths in $G$ with $1,2,\dots,m$ edges. The function |relation| expresses a +relation between $c^*(k)$ and $c^*(k-1)$, for checking purposes; if no such +relation is known, define the function to be identically true. The module +also contains a procedure |least_cost_path|, which returns in $I(0 .. k)$ the +vertices on the best $k$-edge path from 0 to $n$, for any $k\le m$. + +@(paths.ch@> = +@t\% The ``include'' allows {\tt paths.ch} to be used unchanged by different parent modules:@> +include "paths.parent" +stub module paths +import (n, m) +export (least_cost, least_cost_path) +procedure least_cost (var c_star : array 1 .. * of real, function l(i,j : nat) : real, @| function f(c1,c2 : real) : real, function relation (c1,c2 : real) : boolean) +procedure least_cost_path (k : nat, var I : array 0 .. * of nat) +end paths + +@ To find the paths and their costs, define +$$ +c_k(i) = \min_{j:i<j<n} (\hbox{\rm cost of the best $i$-to-$n$ path with +$k\ge 1$ edges}). +$$ +It follows from (1) that $c_k(i)$ satisfies the recurrence +$$ +c_k(i) = \min_{j:i<j<n} f\bigl(\ell(i,j), c_{k-1}(j)\bigr), \qquad k\ge 2. +\eqno (2) +$$ +This recurrence can be solved by noting that +$$ +\forall i,\quad c_1(i) = \ell(i,n). +$$ +Using this in (2) allows us to compute $c_2(i)$ for all $i$, and so on. To +conserve memory space, note that we don't really need to have a matrix +$c(k,i)$, but just two arrays |c_k| and |c_k_1| to hold $c_k(\cdot)$ +and $c_{k-1}(\cdot)$. + +Besides computing the cost of the best 0-to-$n$ paths, we also want to know +what these paths are. To do this, it suffices to remember for each $i$ and +$k$ the $j=J(k,i)$ that minimizes the r.h.s. of (2). + +@ +@<Compute $c_k(i)$ and $J(k,i)$ for all $i$@> = +for i : 0 .. n-2 +c_k(i) := infinity +for j : i+1 .. n-1 +const c := f(l(i,j), c_k_1(j)) +if c < c_k(i) then +c_k(i) := c +J(k,i) := j +end if +end for +end for + +@ +@<Solve recurrence (2)@> = +const infinity := 10.0 ** 200 +for k : 2 .. m +@<Compute $c_k(i)$...@> +@<Remember $c_k(0)$ and check its relationship with $c_{k-1}(0)$@> +@<Set $c_{k-1}(\cdot)$ to $c_k(\cdot)$@> +end for + +@ +@<Procedure |least_cost|@> = +body procedure least_cost +c_star(1) := l(0,n) +@<The arrays |c_k| and |c_k_1|@> +@<Solve recurrence (2)@> +end least_cost + +@ Procedure |least_cost_path| calculates in $I_0,\dots,I_k$ the +vertices on the least-cost path from 0 to $n$ in $G$ with $k$ edges. It +uses the function $J(k,i)$ computed by procedure |least_cost|. +@<Procedure |least_cost_path|@> = +body procedure least_cost_path +I(0) := 0 +I(k) := n +for i : 1 .. k-1 +I(i) := J(k-(i-1), I(i-1)) +assert I(i) > I(i-1) +end for +assert I(k-1) < n +end least_cost_path + +@ +@(paths.ch@> += +body module paths +var J : array 2 .. m, 0 .. n-2 of nat +@<Procedure |least_cost|@> +@<Procedure |least_cost_path|@> +end paths + +@ We store $c_k(0)$, the cost of the best 0-to-$n$ $k$-edge path, in +$c^*(k)$. If we know a relationship between the cost of the best path with +$k$ edges and that of the one with $k-1$ edges, e.g. $c^*(k)>c^*(k-1)$, the +function |relation| allows us to check that it holds. +@<Remember...@> = +c_star(k) := c_k(0) +assert relation (c_star(k), c_star(k-1)) + +@ +@<The arrays |c_k| and |c_k_1|@> = +var c_k, c_k_1 : array 0 .. n-1 of real +for i : 0 .. n-1 % Here k = 2. +c_k_1(i) := l(i,n) +end for +c_k(n-1) := l(n-1,n) % Here k = 1 and this never changes. + +@ +@<Set $c_{k-1}(\cdot)$...@> = +for i : 0 .. n-2 +c_k_1(i) := c_k(i) +end for + + +@* Index. + diff --git a/web/spiderweb/src/turing+/make b/web/spiderweb/src/turing+/make new file mode 100644 index 0000000000..5c74e37aa9 --- /dev/null +++ b/web/spiderweb/src/turing+/make @@ -0,0 +1,3 @@ +#!/bin/sh +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=turing+tangle THEWEAVE=turing+weave SPIDER=turing+.spider "$@" diff --git a/web/spiderweb/src/turing+/turing+.spider b/web/spiderweb/src/turing+/turing+.spider new file mode 100644 index 0000000000..6c95ceaed8 --- /dev/null +++ b/web/spiderweb/src/turing+/turing+.spider @@ -0,0 +1,527 @@ +#------------------------------- turing+.spider -------------------------------- + +# Kostas N. Oikonomou, April 1990 and on ... +# Thanks to Norman Ramsey for helpful suggestions. + +# ******** +# Named types seem to be O.K. +# Unions have to be tested with named types. +# ******** + +# NOTE: newlines are important in the WeB file. They designate the end of statements. + + +language Turing extension t + +at_sign @ + +# This says how to treat "@<...@> =" and "@<...@>". See "Specifying the +# treatment of modules" in the Spider User's Guide. +module definition stmt use stmt + +comment begin <"%"> end newline +macros begin +\def \commentbegin {\%} +macros end + +# Line numbers are not necessary. The compiler handles the tangled output +# with no problem. However, there is no way to turn line numbers off! +line begin <"%"-"line"> end <""> + +default translation <*> mathness yes +default mathness yes translation <*> + +#---------------------------------------------------------------------------- +# Tokens +#---------------------------------------------------------------------------- + +token identifier category expn mathness yes +token number category expn mathness yes +# Note: newline's have to be treated carefully; for example, if they are +# found in math mode, webmac.tex ignores them. +token newline category newl translation <> mathness maybe +token pseudo_semi translation <> category semi mathness maybe + +token ( category open +token ) category close +token * category star +token + category binop +token . category binop +token , category comma translation <",\\,"-opt-3> +token - category unorbinop +token / category binop +# This definition seems to be needed for good formatting of labels of case statements. +token : category colon translation <"\\mathbin{:}"> mathness yes +token < category binop +token = category equal +token > category binop +token # category expn translation <"\\#"> +token -> category binop translation <"\\rightarrow"> +token .. category dotdot translation <"\\mathbin{..}"> +# We want the exponentiation operator "**" to be formatted as "^". However, +# "^" is defined in webmac.tex, so we need the following definition: +token ** category binop translation <"\\char`^"> +token := category assign translation <"\\mathbin{:=}"> mathness yes +token >= category binop translation <"\\ge"> +token <= category binop translation <"\\le"> + +# In the following, section references are to the Turing Report, in +# "The Turing Programming Language: Design and Definition", 1988. + +#---------------------------------------------------------------------------- +# Section 4.2: Programs and Declarations +#---------------------------------------------------------------------------- + +# 4.2.3, 4.2.4. Constant and variable declarations. See pp. 12-13 of the +# Spider User's Guide for the "*" s. +reserved var ilk varconst_like +reserved const ilk varconst_like +ilk varconst_like category varconst +reserved pervasive ilk pervasive_like +ilk pervasive_like category pervasive +varconst <"\\"-space> pervasive --> varconst +# For "var r := 3.141": +varconst <"\\"-space> expn* assign expn newl --> stmt +# "idtypespec" is an auxiliary category which we will also use later. +# (See 4.6.1b for the "id, id" part.) "typespec" is defined in sec. 4.3 on +# types. +[ expn colon (typespec|expn) ] !dotdot --> idtypespec !dotdot +# "vcidtypespec" is another auxiliary category, which is also used later. +varconst <"\\"-space> idtypespec* --> vcidtypespec +# For "var r : real", or "var x : named_type": +vcidtypespec newl --> stmt +# For "var r : real := 3.141": +vcidtypespec assign expn newl --> stmt +# Initializing value: +reserved init ilk init_like +ilk init_like category init +# The context is so that the "init" rule in 4.4.6 can work. +[ init <"\\,"> expn ] !assign --> expn !assign + +# 4.2.4. Collections: +reserved collection ilk collection_like +ilk collection_like category collection +reserved forward ilk forward_like +ilk forward_like category forward +reserved of ilk of_like +ilk of_like category of +forward <"\\"-space> expn --> typespec +collection <"\\"-space> of <"\\"-space> (typespec|expn) --> typespec + +# 4.2.5. Bindings: +reserved bind ilk bind_like +ilk bind_like category bind +# We introduce the auxiliary category "binding". To correctly parse +# "bind a to A.a", etc, we need a context: +[ expn <"\\"-space> to <"\\"-space> expn ] !(binop|open) --> binding !(binop|open) +varconst <"\\"-space> binding --> binding +binding comma binding --> binding +bind <"\\"-space> binding newl --> stmt + + +#---------------------------------------------------------------------------- +# Section 4.3: Types +#---------------------------------------------------------------------------- + +# Type declaration: +reserved type ilk type_like +ilk type_like category type +type <"\\"-space> pervasive --> type +type <"\\"-space> idtypespec* newl --> stmt + +# Typespec: +# a. Standard type: +reserved boolean ilk typespec_like +reserved char ilk typespec_like +reserved int ilk typespec_like +reserved int1 ilk typespec_like +reserved int2 ilk typespec_like +reserved int4 ilk typespec_like +reserved nat ilk typespec_like +reserved real ilk typespec_like +reserved real4 ilk typespec_like +reserved real8 ilk typespec_like +ilk typespec_like category typespec +# Strings are tricky (see 4.4.4), so define a new category: +reserved string ilk strng_like +ilk strng_like category strng +[ strng ] !open --> typespec !open +strng <"\\,"> open (expn|star) close --> typespec +# To allow the typespec to be on a line by itself (e.g. ... newl record ... end record): +newl typespec --> typespec + +# b. Subrange type. This is tricky! If the context were not there, +# then, for example, "1..a+b" would be parsed as "typespec + b". +# Also, note that if spaces are not left around the "..", parsing will be +# confused because, e.g., "1..expn" is indistinguishable from "1.expn". +# Finally, see sec. 4.6.1 for "star". +[ expn dotdot (expn|star) ] !(binop|star|unorbinop|open) --> typespec !(binop|star|unorbinop|open) + +# c. Enumerated type: +reserved enum ilk enum_like +ilk enum_like category enum +enum <"\\,"> expn --> typespec + +# d. Array type: +reserved array ilk array_like +ilk array_like category array +typespec comma typespec --> typespec +array <"\\"-space> typespec <"\\"-space> of <"\\"-space> (typespec|expn) --> typespec + +# e. Set type: +reserved set ilk set_like +ilk set_like category set +set <"\\"-space> of <"\\"-space> typespec --> typespec + +# f. Record type. We use the auxiliary category "recordbody". +# Some of the productions are also used by union" and "case". +reserved record ilk record_like +ilk record_like category record +<force-indent-indent> record <force-indent> --> recordbody +# Eat up a newline, if present (this is to allow free formatting of the record). +(recordbody|unionbody|casebody) newl --> #1 +recordbody idtypespec <force> --> recordbody +# End rule for record, union, and case: +(recordbody|unionbody|casebody) <outdent-force> end <"\\"-space> (record|union|case) <outdent-outdent-force> --> typespec + +# g. Union type. Based on "record". +reserved union ilk union_like +ilk union_like category union +reserved label ilk label_like +ilk label_like category label +label <"\\"-space> expn colon <"\\"-space> --> labelexpn +label colon <"\\"-space> --> labelexpn +<force-indent-indent> union <"\\"-space> idtypespec <"\\"-space> of <force-indent> --> unionbody +<force-indent-indent> union colon typespec <"\\"-space> of <force-indent> --> unionbody +(unionbody|casebody) labelexpn <force> --> #1 +unionbody <indent> idtypespec <force-outdent> --> unionbody + +# h. Pointer type: +reserved pointer ilk pointer_like +ilk pointer_like category pointer +reserved to ilk to_like +ilk to_like category to +pointer <"\\"-space> to <"\\"-space> expn --> typespec + +# i. Named type: +# Named typed are taken care of by productions in 4.2.3, 4.2.4, and 4.3d. + + + +#---------------------------------------------------------------------------- +# Section 4.4: Subprograms and Modules. +#---------------------------------------------------------------------------- + +# 4.4.1. Subprogram declarations. +# We use the auxiliary category "subproghead". +# NOTES on the next production: +# 1. It is extended to Turing Plus. +# 2. It's too hard to handle the fact that a subprogram stub may be followed +# by an import list, which must be indented, but then we must outdent, with no +# matching "end"! So, for subprogram stubs, do the outdenting manually. Module +# stubs, however, are handled perfectly! See the Turing+ extensions section. +(forward|stub) <"\\"-space> subproghead --> subproghead +reserved body ilk body_like +ilk body_like category body +reserved procedure ilk subprog_like +reserved function ilk subprog_like +ilk subprog_like category subprog +body <"\\"-space> (subprog|module) <"\\"-space> expn* newl <force-indent> --> stmt + +# 2. Subprogram headers. We use the auxiliary category "parlist", defined in no. 3. +(subprog|module) <"\\"-space> expn* --> subproghead +# The following also handles functions that return named types. +subproghead colon (typespec|expn) --> subproghead +subproghead <"\\,"> open parlist close --> subproghead +subproghead <"\\"-space> idtypespec --> subproghead +subproghead newl <force-indent> --> stmt + +# 3. Parameter declarations: +open [ (idtypespec|vcidtypespec|subproghead) ] --> open parlist +parlist comma (idtypespec|vcidtypespec) --> parlist +[ parlist comma subproghead ] !(open|colon) --> parlist !(open|colon) + +# 4. Parameter types: +# Array parameters: see 4.3b and 4.3d. + +# 5. Import. This should not be so complicated! +reserved import ilk import_like +ilk import_like category import +import <"\\"-space> open --> importlist +importlist (expn|comma) --> importlist +importlist (varconst|forward) <"\\"-space> expn --> importlist +importlist close newl --> stmt + +# 6. Subprogram body: +reserved pre ilk result_like +reserved post ilk result_like +# We use the auxiliary category "initstmt". +init <"\\"-space> expn assign --> initstmt +initstmt (expn|comma|assign) --> initstmt +initstmt newl --> stmt +<outdent-force> end <"\\"-space> expn newl --> stmt + +# 4.4.2. Module declarations: +reserved module ilk module_like +ilk module_like category module +reserved export ilk import_like +reserved opaque ilk forward_like + + + +#---------------------------------------------------------------------------- +# Section 4.5: Statements and I/O. +#---------------------------------------------------------------------------- + +# Statements: +# a. Assignments. +expn assign expn newl --> stmt +# b. Procedure call on a line by itself. +expn newl --> stmt + +# c, e, h, k, l, n: +reserved assert ilk result_like +reserved result ilk result_like +reserved when ilk result_like +reserved new ilk result_like +reserved free ilk result_like +reserved tag ilk result_like +ilk result_like category result +# Note: if the "newl" were not there, the "assert i" part of "assert i > 0" +# would fire the production! +result <"\\"-space> expn newl --> stmt + +# d, h. Return and exit: +reserved exit ilk return_like +reserved return ilk return_like +ilk return_like category return +return newl --> stmt +return <"\\"-space> result <"\\"-space> expn newl --> stmt + +# j. Begin, end: +reserved begin ilk begin_like +ilk begin_like category begin +<force> begin <force-indent> --> stmt +reserved end ilk end_like +ilk end_like category end +<outdent-force> end newl --> stmt + +# f. If statements: +reserved if ilk if_like +ilk if_like category if +reserved then ilk then_like +ilk then_like category then +reserved else ilk else_like +ilk else_like category else +reserved elsif ilk elsif_like +ilk elsif_like category elsif +if <"\\"-space> expn <"\\"-space> then <force-indent> --> stmt +<force-outdent> else <force-indent> --> stmt +<force-outdent> elsif <"\\"-space> expn <"\\"-space> then <force-indent> --> stmt +# The "end if" rule is in fgm. + +# g. Loop statements: +reserved loop ilk loop_like +ilk loop_like category loop +reserved invariant ilk result_like +loop <force-indent> --> stmt +# The "end loop" rule is in fgm. + +# i. Case statements. "Union" is used. +reserved case ilk case_like +ilk case_like category case +case <"\\"-space> expn <"\\"-space> of <force-indent> --> casebody +casebody <indent> stmt <force-outdent> --> casebody + +# m. For statements: +reserved for ilk for_like +ilk for_like category for +reserved decreasing ilk decreasing_like +ilk decreasing_like category decreasing +for <"\\"-space> decreasing --> for +for <"\\"-space> expn --> for +for colon typespec --> for +for newl <force-indent> --> stmt +# The "end for" rule is in fgm. + +# fgm: the common "end ..." rule: +<outdent-force> end <"\\"-space> (for|if|loop) newl --> stmt + +# o. Put statements: +reserved put ilk put_like +ilk put_like category put +reserved skip ilk skip_like +ilk skip_like category expn +# Context needed for correct parsing of e.g. "put a(i)/b(i)". +[ put <"\\"-space> expn ] !(open|star|unorbinop|binop|comma) --> put !(open|star|unorbinop|binop|comma) +[ put colon expn ] !comma --> put !comma +put <"\\"-space> dotdot --> put +put newl --> stmt + +# p. Get statements: +reserved get ilk get_like +ilk get_like category get +# A getItem. +expn colon star --> expn +[ get <"\\"-space> expn ] !(comma|colon|open) --> get !(comma|colon|open) +[ get colon expn ] !(comma|colon|open) --> get !(comma|colon|open) +get newl --> stmt + +# Formatting rules for statements. +# The first rule is needed for statements separated by blank lines: +stmt newl --> stmt +stmt <force> stmt --> stmt + + +#---------------------------------------------------------------------------- +# Section 4.6: References and Expressions. +#---------------------------------------------------------------------------- + +ilk expn_like category expn + +# 4.6.1. References: +# a. An identifier is already an expression, hence a reference. +# b. +# Note: because of its role in strings, * is "star", and has to be handled explicitly. +[ expn (star|unorbinop|binop|comma) expn ] !open --> expn !open +expn open expn close --> expn +open expn close --> expn + +# 4.6.2. Expressions: +# b. Constants: +reserved false ilk expn_like +reserved true ilk expn_like +# c. Substrings: +open [ star ] close --> open expn close +open [ star unorbinop expn ] close --> open expn close +# d. Set constructors: +expn open close --> expn +reserved all ilk expn_like +# e. Binary operators: +# See 4.6.1b. However, "div" and "mod" are handled specially: +ilk mod_like category mod +reserved div ilk mod_like +reserved mod ilk mod_like +[ expn <"\\"-space> mod <"\\"-space> expn ] !open --> expn !open +# f. Unary operators: +!expn [ unorbinop expn ] --> !expn expn +# g: see 4.6.1b. + +# Special handling of boolean expressions: +reserved and ilk and_like +ilk and_like category binop translation <"\\land"> +reserved or ilk or_like +ilk or_like category binop translation <"\\lor"> +# "not" requires special handling because of "not=" and "not in". +# First, "not" itself: +reserved not ilk not_like +ilk not_like category not translation <"\\"> +not <"neg"> expn --> expn +# Now "not=": +!not [ equal ] --> !not binop +not <"not"> equal --> binop +# Now "in": +reserved in ilk in_like +ilk in_like category in translation <"\\"> +!not [ in <"in"> ] --> !not binop +# Finally, "not in": +not <"not"> in <"in"> --> binop + + + +#---------------------------------------------------------------------------- +# Section 4.6.9: Predefined Functions +#---------------------------------------------------------------------------- + +#reserved eof ilk expn_like +#reserved pred ilk expn_like +#reserved succ ilk expn_like +#reserved length ilk expn_like +#reserved index ilk expn_like +#reserved repeat ilk expn_like +#reserved abs ilk expn_like +#reserved max ilk expn_like +#reserved min ilk expn_like +#reserved sign ilk expn_like +#reserved sqrt ilk expn_like +#reserved sin ilk expn_like +#reserved cos ilk expn_like +#reserved arctan ilk expn_like +#reserved sind ilk expn_like +#reserved sind ilk expn_like +#reserved cosd ilk expn_like +#reserved arctand ilk expn_like +#reserved ln ilk expn_like +#reserved exp ilk expn_like +#reserved floor ilk expn_like +#reserved ceil ilk expn_like +#reserved round ilk expn_like +#reserved intreal ilk expn_like +#reserved chr ilk expn_like +#reserved ord ilk expn_like +#reserved intstr ilk expn_like +#reserved strint ilk expn_like +#reserved erealstr ilk expn_like +#reserved frealstr ilk expn_like +#reserved realstr ilk expn_like +#reserved strreal ilk expn_like + + +#---------------------------------------------------------------------------- +# Section 4.6.10: Attributes +#---------------------------------------------------------------------------- + +#reserved lower ilk expn_like +#reserved upper ilk expn_like +#reserved nil ilk expn_like + + +#---------------------------------------------------------------------------- +# Section 4.6.11: Predefined Procedures +#---------------------------------------------------------------------------- + +#reserved rand ilk expn_like +#reserved randint ilk expn_like +#reserved randomize ilk expn_like +#reserved randnext ilk expn_like +#reserved randseed ilk expn_like +#reserved open ilk expn_like +#reserved close ilk expn_like + +#---------------------------------------------------------------------------- +# Section 4.7: Source Inclusion Facility +#---------------------------------------------------------------------------- + +reserved include ilk result_like + + +#---------------------------------------------------------------------------- +#---------------------------------------------------------------------------- +# Turing Plus Extensions +#---------------------------------------------------------------------------- +#---------------------------------------------------------------------------- + +# Separate Compilation +# -------------------- + +reserved child ilk result_like +reserved parent ilk result_like +reserved grant ilk import_like + +reserved stub ilk stub_like +ilk stub_like category stub +# For subprogram stubs, see 4.4.1. +# Module stubs. This is nice! I am (pleasantly) surprised that it works. +stub <"\\"-space> module <"\\"-space> expn newl <force-indent> --> modulestub +modulestub <force> stmt <force> --> modulestub +modulestub <force> subproghead newl <force> --> modulestub +modulestub <outdent-force> end <"\\"-space> expn newl --> stmt + +# Control of checking +# ------------------- + +reserved checked ilk return_like +reserved unchecked ilk return_like + +? ignore_scrap --> #1 + diff --git a/web/spiderweb/src/turing/make b/web/spiderweb/src/turing/make new file mode 100644 index 0000000000..0d9c844c17 --- /dev/null +++ b/web/spiderweb/src/turing/make @@ -0,0 +1,3 @@ +#!/bin/sh +/bin/make -f ../master/WebMakefile CPUTYPE=`cputype`\ + THETANGLE=turingtangle THEWEAVE=turingweave SPIDER=turing.spider "$@" diff --git a/web/spiderweb/src/turing/turing.spider b/web/spiderweb/src/turing/turing.spider new file mode 100644 index 0000000000..218c7b6ccd --- /dev/null +++ b/web/spiderweb/src/turing/turing.spider @@ -0,0 +1,624 @@ +From ko@surya.ho.att.com Fri Jun 28 12:27:21 1991 +Return-Path: <ko@surya.ho.att.com> +Received: from alpha.xerox.com by palain.PARC (4.1/SMI-4.1) + id AA06309; Fri, 28 Jun 91 12:27:17 PDT +Received: from Revere.Parc.Xerox.xns by alpha.xerox.com via XNS id <11725>; Fri, 28 Jun 1991 12:22:35 PDT +Received: from Princeton.EDU ([128.112.128.1]) by alpha.xerox.com with SMTP id <11654>; Fri, 28 Jun 1991 12:20:30 PDT +Received: from fs.Princeton.EDU by Princeton.EDU (5.65b/2.77/princeton) + id AA27002; Fri, 28 Jun 91 15:20:17 -0400 +Received: from Princeton.EDU (Princeton.EDU.) by fs.Princeton.EDU (4.0/1.105) + id AA25725; Fri, 28 Jun 91 15:20:13 EDT +Received: from att.att.com by Princeton.EDU (5.65b/2.77/princeton) + id AA26997; Fri, 28 Jun 91 15:20:07 -0400 +Received: from spark.ho.att.com by surya.ho.att.com (4.1/SMI-4.1) + id AA19211; Mon, 17 Jun 91 10:42:57 EDT +Original-From: surya.ho.att.com!ko +Received: by spark.ho.att.com (4.1/SMI-4.1) + id AA07125; Mon, 17 Jun 91 10:42:57 EDT +X-Ns-Transport-Id: 08002008D0FD000D0F2A +Date: Mon, 17 Jun 1991 07:42:57 PDT +From: ko@surya.ho.att.com +Subject: Turing Web +To: att.uucp@surya.ho.att.com, nr@princeton.edu +Message-Id: <9106171442.AA19211@surya.ho.att.com> +Status: R + + I have an updated version of Turing Web, which I enclose. + + Kostas + + +# Version of June 1991. + +# ******** +# Named types seem to be O.K. +# Unions have to be tested with named types. +# ******** + + +# Kostas N. Oikonomou, April 1990 and on ... +# Thanks to Norman Ramsey for helpful suggestions. + +# NOTE: newlines are important in the WeB file. They designate the end of statements. + +language Turing extension t + +at_sign @ + +# This says how to treat "@<...@> =" and "@<...@>". See "Specifying the +# treatment of modules" in the Spider User's Guide. +module definition stmt use stmt + +comment begin <"%"> end newline +macros begin +\def \commentbegin {\%} +macros end + +# Line numbers are not necessary. The compiler handles the tangled output +# with no problem. However, there is no way to turn line numbers off! +line begin <"%"-"line"> end <""> + +default translation <*> mathness yes +default mathness yes translation <*> + +#---------------------------------------------------------------------------- +# Tokens +#---------------------------------------------------------------------------- + +token identifier category expn mathness yes +token number category expn mathness yes +# Note: newline's have to be treated carefully; for example, if they are +# found in math mode, webmac.tex ignores them. +token newline category newl translation <> mathness maybe +token pseudo_semi translation <> category semi mathness maybe + +token ( category open +token ) category close +token * category star +token + category binop +token . category binop +token , category comma translation <",\\,"-opt-3> +token - category unorbinop +token / category binop +# This definition seems to be needed for good formatting of labels of case statements. +token : category colon translation <"\\mathbin{:}"> mathness yes +token < category binop +token = category equal +token > category binop +token # category expn translation <"\\#"> +token -> category binop translation <"\\rightarrow"> +token .. category dotdot translation <"\\mathbin{..}"> +# We want the exponentiation operator "**" to be formatted as "^". However, +# "^" is defined in webmac.tex, so we need the following definition: +token ** category binop translation <"\\char`^"> +token := category assign translation <"\\mathbin{:=}"> mathness yes +token >= category binop translation <"\\ge"> +token <= category binop translation <"\\le"> +token @ category atsign + +# In the following, section references are to the Turing Report, in +# "The Turing Programming Language: Design and Definition", 1988. + +#---------------------------------------------------------------------------- +# Section 4.2: Programs and Declarations +#---------------------------------------------------------------------------- + +# 4.2.3, 4.2.4. Constant and variable declarations. See pp. 12-13 of the +# Spider User's Guide for the "*" s. +reserved var ilk varconst_like +reserved const ilk varconst_like +ilk varconst_like category varconst +reserved pervasive ilk pervasive_like +ilk pervasive_like category pervasive +varconst <"\\"-space> pervasive --> varconst +# For "var r := 3.141": +varconst <"\\"-space> expn* assign expn newl --> stmt +# NOTES for the following production: +# 1. "idtypespec" is an auxiliary category which we will also use later. +# 2. "typespec" is defined in sec. 4.3 on types. +# 3. See 4.6.1b for the "id, id" case. +# 4. For the "|dotdot", see the Turing+ extensions, section 6.10. +[ expn colon (typespec|expn) ] !dotdot --> idtypespec !dotdot +# "vcidtypespec" is another auxiliary category, which is also used later. +varconst <"\\"-space> idtypespec* --> vcidtypespec +# For "var r : real", or "var x : named_type": +vcidtypespec newl --> stmt +# For "var r : real := 3.141": +vcidtypespec assign expn newl --> stmt +# Initializing value: +reserved init ilk init_like +ilk init_like category init +# The context is so that the "init" rule in 4.4.6 can work. +[ init <"\\,"> expn ] !assign --> expn !assign + +# 4.2.4. Collections: +reserved collection ilk collection_like +ilk collection_like category collection +reserved forward ilk forward_like +ilk forward_like category forward +reserved of ilk of_like +ilk of_like category of +forward <"\\"-space> expn --> typespec +collection <"\\"-space> of <"\\"-space> (typespec|expn) --> typespec + +# 4.2.5. Bindings: +reserved bind ilk bind_like +ilk bind_like category bind +# We introduce the auxiliary category "binding". To correctly parse +# "bind a to A.a", etc, we need a context: +[ expn <"\\"-space> to <"\\"-space> expn ] !(binop|open) --> binding !(binop|open) +varconst <"\\"-space> binding --> binding +binding comma binding --> binding +bind <"\\"-space> binding newl --> stmt + + +#---------------------------------------------------------------------------- +# Section 4.3: Types +#---------------------------------------------------------------------------- + +# Type declaration: +reserved type ilk type_like +ilk type_like category type +type <"\\"-space> pervasive --> type +type <"\\"-space> idtypespec* newl --> stmt + +# Typespec: +# a. Standard type: +reserved boolean ilk typespec_like +reserved char ilk typespec_like +reserved int ilk typespec_like +reserved int1 ilk typespec_like +reserved int2 ilk typespec_like +reserved int4 ilk typespec_like +reserved nat ilk typespec_like +reserved real ilk typespec_like +reserved real4 ilk typespec_like +reserved real8 ilk typespec_like +ilk typespec_like category typespec +# Strings are tricky (see 4.4.4), so define a new category: +reserved string ilk strng_like +ilk strng_like category strng +[ strng ] !open --> typespec !open +strng <"\\,"> open (expn|star) close --> typespec +# To allow the typespec to be on a line by itself (e.g. ... newl record ... end record): +newl typespec --> typespec + +# b. Subrange type. This is tricky! If the context were not there, +# then, for example, "1..a+b" would be parsed as "typespec + b". +# Also, note that if spaces are not left around the "..", parsing will be +# confused because, e.g., "1..expn" is indistinguishable from "1.expn". +# Finally, see sec. 4.6.1 for "star". +[ expn dotdot (expn|star) ] !(binop|star|unorbinop|open) --> typespec !(binop|star|unorbinop|open) + +# c. Enumerated type: +reserved enum ilk enum_like +ilk enum_like category enum +enum <"\\,"> expn --> typespec + +# d. Array type: +reserved array ilk array_like +ilk array_like category array +typespec comma typespec --> typespec +array <"\\"-space> typespec <"\\"-space> of <"\\"-space> (typespec|expn) --> typespec + +# e. Set type: +reserved set ilk set_like +ilk set_like category set +set <"\\"-space> of <"\\"-space> typespec --> typespec + +# f. Record type. We use the auxiliary category "recordbody". +# Some of the productions are also used by "union" and "case". +reserved record ilk record_like +ilk record_like category record +<force-indent-indent> record <force-indent> --> recordbody +# Eat up a newline, if present (this is to allow free formatting of the record). +(recordbody|unionbody|casebody) newl --> #1 +recordbody idtypespec <force> --> recordbody +# End rule for record and union: +(recordbody|unionbody) <outdent-force> end <"\\"-space> (record|union) <outdent-outdent-force> --> typespec + +# g. Union type. Based on "record". +reserved union ilk union_like +ilk union_like category union +reserved label ilk label_like +ilk label_like category label +label <"\\"-space> expn colon <"\\"-space> --> labelexpn +label colon <"\\"-space> --> labelexpn +<force-indent-indent> union <"\\"-space> idtypespec <"\\"-space> of <force-indent> --> unionbody +<force-indent-indent> union colon typespec <"\\"-space> of <force-indent> --> unionbody +(unionbody|casebody) labelexpn <force> --> #1 +unionbody <indent> idtypespec <force-outdent> --> unionbody + +# h. Pointer type: +reserved pointer ilk pointer_like +ilk pointer_like category pointer +reserved to ilk to_like +ilk to_like category to +pointer <"\\"-space> to <"\\"-space> expn --> typespec + +# i. Named type: +# Named typed are taken care of by productions in 4.2.3, 4.2.4, and 4.3d. + + + +#---------------------------------------------------------------------------- +# Section 4.4: Subprograms and Modules. +#---------------------------------------------------------------------------- + +# 4.4.1. Subprogram declarations. + +reserved body ilk body_like +ilk body_like category body +reserved procedure ilk subprog_like +reserved function ilk subprog_like +ilk subprog_like category subprog +# 4.4.1 b, c. +# NOTES on the next production: +# 1. It is extended to Turing Plus ("stub"). +# 2. It's too hard to handle the fact that a subprogram stub may be followed +# by an import list, which must be indented, but then we must outdent, with no +# matching "end"! So, for +# external, forward, and stub +# subprograms, do the outdenting MANUALLY by @+@t\2@>. +# Module stubs, however, are handled nicely. See the Turing+ extensions section. +(external|forward|stub) <"\\"-space> subprog --> subprog + +# 4.4.1 d. +body <"\\"-space> (subprog|module) <"\\"-space> expn* newl <force-indent> --> stmt + +# 2. Subprogram headers. We use the auxiliary categories "subproghead" and +# "parlist". ("parlist" is defined in no. 3 below.) +(subprog|module) <"\\"-space> expn* --> subproghead +# The following also handles functions that return named types. +subproghead colon (typespec|expn) --> subproghead +subproghead <"\\,"> open parlist close --> subproghead +subproghead <"\\"-space> idtypespec --> subproghead +subproghead newl <force-indent> --> stmt + +# 3. Parameter declarations: +open [ (idtypespec|vcidtypespec) ] --> open parlist +parlist comma (idtypespec|vcidtypespec) --> parlist +# To ensure that the "subproghead" productions above have priority: +open [ subproghead ] !(open|colon) --> open parlist !(open|colon) +[ parlist comma subproghead ] !(open|colon) --> parlist !(open|colon) + +# 4. Parameter types: +# Array parameters: see 4.3b and 4.3d. + +# 5. Import. This should not be so complicated! +reserved import ilk import_like +ilk import_like category import +import <"\\"-space> open --> importlist +importlist (expn|comma) --> importlist +importlist (varconst|forward) <"\\"-space> expn --> importlist +importlist close newl --> stmt + +# 6. Subprogram body: +reserved pre ilk result_like +reserved post ilk result_like +# We use the auxiliary category "initstmt". +init <"\\"-space> expn assign --> initstmt +initstmt (expn|comma|assign) --> initstmt +initstmt newl --> stmt +<outdent-force> end <"\\"-space> expn newl --> stmt + +# 4.4.2. Module declarations: +reserved module ilk module_like +ilk module_like category module +reserved export ilk import_like +reserved opaque ilk forward_like + + + +#---------------------------------------------------------------------------- +# Section 4.5: Statements and I/O. +#---------------------------------------------------------------------------- + +# Statements: +# a. Assignments. +expn assign expn newl --> stmt +# b. Procedure call on a line by itself. +expn newl --> stmt + +# c, e, h, k, l, n: +reserved assert ilk result_like +reserved result ilk result_like +reserved when ilk result_like +reserved new ilk result_like +reserved free ilk result_like +reserved tag ilk result_like +ilk result_like category result +# Note: if the "newl" were not there, the "assert i" part of "assert i > 0" +# would fire the production! +result <"\\"-space> expn newl --> stmt + +# d, h. Return and exit: +reserved exit ilk return_like +reserved return ilk return_like +ilk return_like category return +return newl --> stmt +# This is for "exit when ...". +return <"\\"-space> result <"\\"-space> expn newl --> stmt + +# j. Begin, end: +reserved begin ilk begin_like +ilk begin_like category begin +<force> begin <force-indent> --> stmt +reserved end ilk end_like +ilk end_like category end +<outdent-force> end newl --> stmt + +# f. If statements: +reserved if ilk if_like +ilk if_like category if +reserved then ilk then_like +ilk then_like category then +reserved else ilk else_like +ilk else_like category else +reserved elsif ilk elsif_like +ilk elsif_like category elsif +if <"\\"-space> expn <"\\"-space> then <force-indent> --> stmt +<force-outdent> else <force-indent> --> stmt +<force-outdent> elsif <"\\"-space> expn <"\\"-space> then <force-indent> --> stmt +# The "end if" rule is in fgm. + +# g. Loop statements: +reserved loop ilk loop_like +ilk loop_like category loop +reserved invariant ilk result_like +loop <force-indent> --> stmt +# The "end loop" rule is in fgm. + +# i. Case statements. Also see "Union". +reserved case ilk case_like +ilk case_like category case +case <"\\"-space> expn <"\\"-space> of <force-indent> --> casebody +casebody <indent> stmt <force-outdent> --> casebody +casebody <outdent-force> end <"\\"-space> case newl --> stmt + +# m. For statements: +reserved for ilk for_like +ilk for_like category for +reserved decreasing ilk decreasing_like +ilk decreasing_like category decreasing +for <"\\"-space> decreasing --> for +for <"\\"-space> expn --> for +for colon typespec --> for +for newl <force-indent> --> stmt +# The "end for" rule is in fgm. + +# fgm: the common "end ..." rule: +<outdent-force> end <"\\"-space> (for|if|loop) newl --> stmt + +# o. Put statements: +reserved put ilk put_like +ilk put_like category put +reserved skip ilk skip_like +ilk skip_like category expn +# Context needed for correct parsing of e.g. "put a(i)/b(i)". +[ put <"\\"-space> expn ] !(open|star|unorbinop|binop|comma) --> put !(open|star|unorbinop|binop|comma) +[ put colon expn ] !comma --> put !comma +put <"\\"-space> dotdot --> put +put newl --> stmt + +# p. Get statements: +reserved get ilk get_like +ilk get_like category get +# A getItem. +expn colon star --> expn +[ get <"\\"-space> expn ] !(comma|colon|open) --> get !(comma|colon|open) +[ get colon expn ] !(comma|colon|open) --> get !(comma|colon|open) +get newl --> stmt + +# Formatting rules for statements. +# The first rule is needed for statements separated by blank lines: +stmt newl --> stmt +stmt <force> stmt --> stmt + + +#---------------------------------------------------------------------------- +# Section 4.6: References and Expressions. +#---------------------------------------------------------------------------- + +ilk expn_like category expn + +# 4.6.1. References: +# a. An identifier is already an expression, hence a reference. +# b. +# Note: because of its role in strings, * is "star", and has to be handled explicitly. +[ expn (star|unorbinop|binop|comma) expn ] !open --> expn !open +expn open expn close --> expn +open expn close --> expn + +# 4.6.2. Expressions: +# b. Constants: +reserved false ilk expn_like +reserved true ilk expn_like +# c. Substrings: +open [ star ] close --> open expn close +open [ star unorbinop expn ] close --> open expn close +# d. Set constructors: +expn open close --> expn +reserved all ilk expn_like +# e. Binary operators: +# See 4.6.1b. However, "div" and "mod" are handled specially: +ilk mod_like category mod +reserved div ilk mod_like +reserved mod ilk mod_like +[ expn <"\\"-space> mod <"\\"-space> expn ] !open --> expn !open +# f. Unary operators: +!expn [ unorbinop expn ] --> !expn expn +# g: see 4.6.1b. + +# Special handling of boolean expressions: +reserved and ilk and_like +ilk and_like category binop translation <"\\land"> +reserved or ilk or_like +ilk or_like category binop translation <"\\lor"> +# "not" requires special handling because of "not=" and "not in". +# First, "not" itself: +reserved not ilk not_like +ilk not_like category not translation <"\\"> +not <"neg"> expn --> expn +# Now "not=": +!not [ equal ] --> !not binop +not <"not"> equal --> binop +# Now "in": +reserved in ilk in_like +ilk in_like category in translation <"\\"> +!not [ in <"in"> ] --> !not binop +# Finally, "not in": +not <"not"> in <"in"> --> binop + + + +#---------------------------------------------------------------------------- +# Section 4.6.9: Predefined Functions +#---------------------------------------------------------------------------- + +#reserved eof ilk expn_like +#reserved pred ilk expn_like +#reserved succ ilk expn_like +#reserved length ilk expn_like +#reserved index ilk expn_like +#reserved repeat ilk expn_like +#reserved abs ilk expn_like +#reserved max ilk expn_like +#reserved min ilk expn_like +#reserved sign ilk expn_like +#reserved sqrt ilk expn_like +#reserved sin ilk expn_like +#reserved cos ilk expn_like +#reserved arctan ilk expn_like +#reserved sind ilk expn_like +#reserved sind ilk expn_like +#reserved cosd ilk expn_like +#reserved arctand ilk expn_like +#reserved ln ilk expn_like +#reserved exp ilk expn_like +#reserved floor ilk expn_like +#reserved ceil ilk expn_like +#reserved round ilk expn_like +#reserved intreal ilk expn_like +#reserved chr ilk expn_like +#reserved ord ilk expn_like +#reserved intstr ilk expn_like +#reserved strint ilk expn_like +#reserved erealstr ilk expn_like +#reserved frealstr ilk expn_like +#reserved realstr ilk expn_like +#reserved strreal ilk expn_like + + +#---------------------------------------------------------------------------- +# Section 4.6.10: Attributes +#---------------------------------------------------------------------------- + +#reserved lower ilk expn_like +#reserved upper ilk expn_like +#reserved nil ilk expn_like + + +#---------------------------------------------------------------------------- +# Section 4.6.11: Predefined Procedures +#---------------------------------------------------------------------------- + +#reserved rand ilk expn_like +#reserved randint ilk expn_like +#reserved randomize ilk expn_like +#reserved randnext ilk expn_like +#reserved randseed ilk expn_like +#reserved open ilk expn_like +#reserved close ilk expn_like + +#---------------------------------------------------------------------------- +# Section 4.7: Source Inclusion Facility +#---------------------------------------------------------------------------- + +reserved include ilk result_like + +#---------------------------------------------------------------------------- +# Section 4.13: External Subprograms +#---------------------------------------------------------------------------- + +reserved external ilk ext_like +ilk ext_like category external +external <"\\"-space> expn --> external +# Now see 4.4.1. + + + +#---------------------------------------------------------------------------- +#---------------------------------------------------------------------------- +# Turing Plus Extensions: from the Turing Plus Report, August 1988. +#---------------------------------------------------------------------------- +#---------------------------------------------------------------------------- + +# ------------------------------- +# Section 5: Separate Compilation +# ------------------------------- + +reserved child ilk result_like +reserved parent ilk result_like +reserved grant ilk import_like + +reserved stub ilk stub_like +ilk stub_like category stub +# For subprogram stubs, see 4.4.1. +# Module stubs. This is nice! I am (pleasantly) surprised that it works. +stub <"\\"-space> module <"\\"-space> expn newl <force-indent> --> modulestub +modulestub <force> stmt <force> --> modulestub +modulestub <force> subproghead newl <force> --> modulestub +modulestub <outdent-force> end <"\\"-space> expn newl --> stmt + + + +# -------------------------------------------------------- +# Section 6.6: Type Cheats +# -------------------------------------------------------- + +type <"\\,"> open (typespec|strng) comma expn close --> expn + + +# -------------------------------------------------------- +# Section 6.9: External Variables and External Subprograms +# -------------------------------------------------------- + +# For the external subprograms, see the Turing section 4.13. +external <"\\"-space> varconst --> varconst + + +# ------------------------------------------- +# Section 6.10: Variable Number of Parameters +# ------------------------------------------- + +expn colon dotdot --> idtypespec + +# --------------------------------------- +# Section 6.11: The Indirection Operation +# --------------------------------------- + +(typespec|strng) <"\\,"> atsign <"\\,"> open expn close --> expn + + +# ----------------------------------- +# Section 6.12: Addresses as Integers +# ----------------------------------- + +reserved addressint ilk typespec_like + + +# --------------------------------- +# Section 6.17: Control of checking +# --------------------------------- + +reserved checked ilk return_like +reserved unchecked ilk uncheck_like +ilk uncheck_like category unchecked +unchecked newl --> stmt +unchecked <"\\"-space> collection --> collection + + + +? ignore_scrap --> #1 + diff --git a/web/spiderweb/src/webkernel.tex b/web/spiderweb/src/webkernel.tex new file mode 100644 index 0000000000..1e88863fea --- /dev/null +++ b/web/spiderweb/src/webkernel.tex @@ -0,0 +1,383 @@ +% Copyright 1989-92 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT + +%\let\plainmark=\mark +%\def\mark#1{\message{(Marking ``#1'')}\plainmark{#1}} + +% standard macros for WEB listings (in addition to PLAIN.TEX) +% rename some old favorites +\let\amp=\& +\let\SS=\S +\let\PP=\P +\let\em=\it % compatibility with latex + +\newif\iftwoside\twosidefalse +\parskip 0pt % .1pt plus 0.1pt mins 0.1pt % no stretch between paragraphs +\parindent 1em % for paragraphs and for the first line of Pascal text + +\font\eightrm=cmr8 +\font\sc=cmcsc10 +\let\mainfont=\tenrm +\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) +\let\idfont\it +\let\reservedfont\bf + +\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} + +\def\\#1{\leavevmode\hbox{\idfont#1\/\kern.05em}} % italic type for identifiers +\def\|#1{\leavevmode\hbox{$#1$}} % one-letter identifiers look better this way +\def\{\leavevmode\hbox{\reservedfont#1\/}} % boldface type for reserved words +\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings + \let\\=\BS % backslash in a string + \let\'=\RQ % right quote in a string + \let\`=\LQ % left quote 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 + #1}} +\def\#{\hbox{\tt\char`\#}} % parameter sign +\def\${\hbox{\tt\char`\$}} % dollar sign +\def\%{\hbox{\tt\char`\%}} % percent sign +\def\^{\ifmmode\mathchar"222 \else\char`^ \fi} % pointer or hat +% circumflex accents can be obtained from \^^D instead of \^ +\def\AT!{@} % at sign for control text +\def\@{@} % at sign in strings +% EVERY WEAVE MUST DEFINE \? WHERE ? IS THE AT SIGN!!!! + +% Macros to surround text in |...| +\def\CD{\relax\ifmmode\let\DC\egroup\hbox\bgroup\else\let\DC\relax\fi} +\let\DC=\relax + +\chardef\AM=`\& % ampersand character in a string +\chardef\BS=`\\ % backslash in a string +\chardef\LB=`\{ % left brace in a string +\def\LQ{{\tt\char'22}} % left quote in a string +\chardef\RB=`\} % right brace in a string +\def\RQ{{\tt\char'23}} % right quote 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 + +\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\0{\ifmmode\ifinner$\par % forced break + \hangindent\ind em\noindent\kern\ind em\ignorespaces$\fi + \else\par % forced break + \hangindent\ind em\noindent\kern\ind em\ignorespaces\fi} +\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 with no indentation +% \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi} +\def\6{\ifmmode\else\par % forced break with no indentation + \hangindent\ind em\startline\ignorespaces\fi} +\def\7{\Y\6} % forced break and a little extra space +\def\8{\unskip} % no indentation--works only in code, not in |...| +\def\startline{\noindent + \count255=\ind\advance\count255by-2 + \hskip\count255 em} + +\let\yskip=\smallskip +\def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1 #2.\par}} +\def\lapstar{\rlap{*}} +\def\startsection{\Q\noindent{\let\*=\lapstar\bf\modstar.\quad}} +\def\defin#1{\global\advance\ind by 2 \1\&{#1 }} % begin `define' or `format' +\def\A{\note{See also}} % cross-reference for multiply defined section names +\def\B{\mathopen{\.{@\commentbegin}}} % begin controlled comment +\def\C#1{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % C comments + \XX\hfil\penalty-1\hfilneg\quad + $\commentbegin\,${#1}$\,\commentend$\XX} +\def\D{\defin{define}} % macro definition +\def\F{\defin{format}} % format definition +\def\J{\.{@\&}} % TANGLE's join operation +\outer\def\M#1.{\MN#1.\ifon\vfil\penalty-100\vfilneg % beginning of section + \vskip12ptminus3pt\startsection\ignorespaces} +\outer\def\N#1.#2.{\MN#1.\headcheck#2\headcheck + \edef\rhead{\uppercase{\ignorespaces\themodtitle}} % define running headline + \message{*\modno} % progress report + \edef\next{\write\cont{\thetocskip + \Z{\theopen\relax + \themodtitle}{\modno}{\noexpand\the\pageno}}}\next % to contents file + \ifon\startsection{\bf\ignorespaces\themodtitle.\quad}\ignorespaces} +\def\MN#1.{\par % common code for \M, \N + {\xdef\modstar{#1}\let\*=\empty\xdef\modno{#1}} + \ifx\modno\modstar \onmaybe \else\ontrue \fi \mark{\modno}} +\def\O#1{% octal, hex or decimal constant + {\def\?{\kern.2em}% + \def\${\ell}% long constant + \def\_{\cdot 10^{\aftergroup}}% power of ten + \def\~{\hbox{\rm\char'23\kern-.2em\it\aftergroup\?\aftergroup}}% octal + \def\^{\hbox{\rm\char"7D\tt\aftergroup}}% double quotes for hex constant + #1}} +\def\P{\rightskip=0pt plus 100pt minus 10pt % go into Pascal mode + \sfcode`;=3000 + \pretolerance 10000 + \hyphenpenalty 10000 \exhyphenpenalty 10000 + \global\ind=2 \1\startline}%\ \unskip} +\def\Q{\rightskip=0pt % get out of Pascal mode + \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 } +\def\T{\mathclose{\.{@\commentend}}} % terminate controlled comment +\def\U{\note{This code is used in}} % cross-reference for uses of sections +\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name + \XX$\langle\,$#2{\eightrm\kern.5em#1}$\,\rangle$\XX} +\def\XF#1:#2\XF{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name + \XX{\tt(#2{\eightrm\kern.5em#1})}\XX} +\def\Y{\par\yskip} +\def\){\hbox{\.{@\$}}} % sign for string pool check sum +\def\]{\hbox{\.{@\\}}} % sign for forced line break +\def\=#1{\kern2pt\hbox{\vrule\vtop{\vbox{\hrule + \hbox{\strut\kern2pt\.{#1}\kern2pt}} + \hrule}\vrule}\kern2pt} % verbatim string +\let\~=\ignorespaces +\let\*=* + + +\def\DO{\hbox{\sl\char'044}} % slant dollar sign +\let\G=\ge % greater than or equal sign +\def\H{{\rm\char'136}} % hat +\let\I=\ne % unequal sign +\let\K=\gets % left arrow +\let\L=\le % less than or equal sign +\let\R=\lnot % logical not +\let\S=\equiv % equivalence sign +\let\TI\sim % tilde +\let\V=\lor % logical or +\let\W=\land % logical and +\let\Z=\let % now you can \send the control sequence \Z + + +\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue +\newif\ifon \newif\iftitle \newif\ifpagesaved +\def\lheader{\mainfont\the\pageno\eightrm\qquad\rhead\hfill\title\qquad + \tensy x\mainfont\topmark} % top line on left-hand pages +\def\rheader{\tensy x\mainfont\topmark\eightrm\qquad\title\hfill\rhead + \qquad\mainfont\the\pageno} % top line on right-hand pages +\def\lfooter{\hfil} % bottom line on left-hand-pages +\def\rfooter{\hfil} % bottom line on left-hand-pages +\def\page{\box255 } +\def\normaloutput#1#2#3#4#5{% +%\message{(At start top, first, and bottom marks: \topmark, \firstmark, \botmark)}% +\shipout\vbox{ + \iftwoside\else\ifodd\pageno\hoffset=\pageshift\fi\fi + \vbox to\fullpageheight{ + \iftitle + \else\hbox to\pagewidth{\vbox to10pt{}% + \ifodd\pageno#3\else + \iftwoside#2\else#3\fi + \fi}% + \fi + \vfill#1% parameter #1 is the page itself + \iftitle\global\titlefalse + \else\baselineskip=24pt\hbox to\pagewidth{\strut % see TeXbook p256 + \ifodd\pageno#5\else + \iftwoside#4\else#5\fi + \fi}% + \fi + }% +}% +\global\advance\pageno by1 +%\message{(At end top, first, and bottom marks: \topmark, \firstmark, \botmark)}% +} + + +\def\rhead{\.{WEB} OUTPUT} % this running head is reset by starred sections +\def\title{} % an optional title can be set by the user +\def\topofcontents{\centerline{\titlefont\title} + \vfill} % this material will start the table of contents page +\def\botofcontents{\vfill} % this material will end the table of contents page +\def\contentspagenumber{0} % default page number for table of contents +\newdimen\pagewidth \pagewidth=6.5in % the width of each page +\newdimen\pageheight \pageheight=8.4in % the height of each page +\newdimen\fullpageheight \fullpageheight=9in % page height including + % headlines and footlines +\newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones +\catcode`\@=11 % make at letter +\def\m@g{\mag=\count@\pagewidth=6.5truein\pageheight=8.4truein + \fullpageheight=9truein\setpage} +\catcode`\@=12 % make at other +\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size + +\edef\contentsfile{\jobname.toc } % file that gets table of contents info +\def\readcontents{\expandafter\input \contentsfile} + +\newwrite\cont +\output{\setbox0=\page % the first page is garbage + \openout\cont=\contentsfile + \write\cont{\string\catcode`\string\@=11}% a hack to make contents + % take stuff in \.{---} + \global\output{\normaloutput\page\lheader\rheader\lfooter\rfooter}} +\setpage +\vbox to \vsize{} % the first \topmark won't be null +% Delete as per bug report from kademan@stat.wisc.edu +% Causes headings on first page to be missing +% \eject + +\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 + \write\cont{} % ensure that the contents file isn't empty + \closeout\cont % the contents information has been fully gathered + \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader + \lfooter\rfooter\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 + \lfooter\rfooter + \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi} + \message{Index:} + \parskip 0pt plus .5pt + \outer\def\:##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry + \def\[##1]{$\underline{##1}$} % underlined index item + \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar + \hyphenpenalty 10000 \parindent0pt} +\def\fin{\par\vfill\eject % this is done when we are ending the index + \ifpagesaved\null\vfill\eject\fi % output a null index column + \if L\lr\else\null\vfill\eject\fi % finish the current page + \parfillskip 0pt plus 1fil + \def\rhead{NAMES OF THE SECTIONS} + \message{Section names:} + \output{\normaloutput\page\lheader\rheader\lfooter\rfooter} + \setpage + \def\note##1##2.{\quad{\eightrm##1 ##2.}} + \def\U{\note{Used in}} % cross-reference for uses of sections + \def\:{\par\hangindent 2em}\let\*=*} +\def\con{\par\vfill\eject % finish the section names + \rightskip 0pt \hyphenpenalty 50 \tolerance 200 + \setpage + \output{\normaloutput\page\lheader\rheader\lfooter\rfooter} + \titletrue % prepare to output the table of contents + \pageno=\contentspagenumber \def\rhead{TABLE OF CONTENTS} + \message{Table of contents:} + \topofcontents + \line{\hfil Section\hbox to3em{\hss Page}} + \def\Z##1##2##3{\line{{\ignorespaces##1} + \leaders\hbox to .5em{.\hfil}\hfil\ ##2\hbox to3em{\hss##3}}} + \readcontents\relax % read the contents info + \botofcontents \end} % print the contents page(s) and terminate +%\tracingstats1 % temporary (during development) + + +\def\vert{|} + +%%% this stuff is to allow inital =,1,2,3,4 in starred modules +%%% = means ``part'', don't skip page +%%% normal starred module is 0 +%%% 1,2,3,4 are submodules, and are indented +%%% +%%% @*= bold name in table of contents +%%% causes page eject +%%% suppresses page eject following +%%% +%%% @*1,2 first level of indentation +%%% @*3,4 second level of indentation +%%% +%%% @*1,3 cause page eject +%%% @*2,4 don't cause page eject +%%% + + +\newif\ifcancel\cancelfalse +\catcode`\@=11 +\def\ifnextchar#1#2#3{\let\@tempe=#1\def\@tempa{#2}\def\@tempb{#3}\@ifnch} +\def\@ifnch{\ifx \@tempc \@tempe\let\@tempd\@tempa\else\let\@tempd\@tempb\fi + \@tempd} +\def\makethechar#1{\let\@tempc=#1} +\catcode`\@=12 + +\def\headcheck#1#2\headcheck{% + \makethechar{#1}% + \def\theskipper{\vfil\penalty-100\vfilneg\vskip12ptminus3pt}% + % skip before new module + \def\theopen{}% opening skip in toc entry + \def\thetocskip{}% vertical skip before toc entry + \def\themodtitle{{#2}} + \ifnextchar={% + \def\theskipper{\vfil\eject}% + \canceltrue + \def\theopen{\bf}% + \def\thetocskip{\vskip3ptplus1in\penalty-100 + \vskip0ptplus-1in}% + }{\ifnextchar1{% + \cancelfalse + \def\theskipper{\vfil\eject}% + \def\theopen{\hskip2em}% + }{\ifnextchar2{% + \cancelfalse + \def\theopen{\hskip2em}% + }{\ifnextchar3{% + \cancelfalse + \def\theskipper{\vfil\eject}% + \def\theopen{\hskip4em}% + }{\ifnextchar4{% + \cancelfalse + \def\theopen{\hskip4em}% + }{% else + \ifcancel\else + \def\theskipper{\vfil\eject}% + \fi + \cancelfalse + \def\themodtitle{#1{#2}}% + }}}}}% + \theskipper +} + + +%%%%%%%% for verbatim quoting of code +% The following are copied from manmanc.tex and are taken from p421 of +% the TeXbook ... modified to \verbatim...\endverbatim +% macros for verbatim scanning +\chardef\other=12 +\def\ttverbatim{\begingroup + \catcode`\|=\other + \catcode`\\=\other + \catcode`\{=\other + \catcode`\}=\other + \catcode`\$=\other + \catcode`\&=\other + \catcode`\#=\other + \catcode`\%=\other + \catcode`\~=\other + \catcode`\_=\other + \catcode`\^=\other + \obeyspaces \obeylines \tt} +{\obeyspaces\global\let =\ } % from texbook, p 381 + + +%\outer\def\verbatim{$$\let\par=\endgraf \ttverbatim \parskip=0pt +% \catcode`\|=0 \rightskip-5pc \ttfinish} +%{\catcode`\|=0 |catcode`|\=\other % | is temporary escape character +% |obeylines % end of line is active +% |gdef|ttfinish#1^^M#2\endverbatim{#1|vbox{#2}|endgroup$$}} + +\outer\def\verbatimcode{\par\ttverbatim\leftskip=2em\parskip=0pt + \ttfinishcode} +{\catcode`\|=0 |catcode`|\=\other % | is temporary escape character + |obeylines % end of line is active + |gdef|ttfinishcode#1^^M#2\endverbatimcode{#1|vbox{#2}|endgroup}} + + +% end of manmac stuff + diff --git a/web/spiderweb/todo b/web/spiderweb/todo new file mode 100644 index 0000000000..d7f43e7734 --- /dev/null +++ b/web/spiderweb/todo @@ -0,0 +1,16 @@ +WEB CHANGES THAT WILL NEVER HAPPEN +*) Make it possible to introduce a limited set of new @ codes. +5) Add other web tools to the distribution +6) give depend a -F option to list the full pathname??? +Look over tangle and add variable controlling when line numbers are + inserted into |tok_mem|. +put `balance' into spider and document +Write line number inversion tool +Make WEAVE back-end retargetable +Modularize WEB source in two steps: first language split, then + sensible code. +To parameterize the translation of identifiers. +To parameterize case-sensitivity of language. +Correct TANGLE to include the proper language-dependent meta-comment support. +Restore @\ ?? +Implement @? diff --git a/web/spiderweb/tools/Makefile b/web/spiderweb/tools/Makefile new file mode 100644 index 0000000000..eb2e676894 --- /dev/null +++ b/web/spiderweb/tools/Makefile @@ -0,0 +1,42 @@ +# +DVI=dvi +CFLAGS=-DDEBUG -g -DSTAT + +# Change the following three directories to match your installation + +WEBSOURCE=$(HOME)/src/web# # root of the WEB source distribution +DEST=/usr/charybdis/ada/bin# # place where the executables go +MACROS=$(HOME)/tex/macros# # place where the macros go + +MASTER=$(WEBSOURCE)/master# # master source directory + +CTANGLE=ceetangle -I$(MASTER) +CWEAVE=ceeweave -I$(MASTER) +AWKTANGLE=ktangle -I$(MASTER) + +depend: depend.o $(MASTER)/pathopen.o + cc $(CFLAGS) -o $(DEST)/depend depend.o $(MASTER)/pathopen.o + +depend.c: depend.web + $(CTANGLE) depend + +$(MASTER)/pathopen.c: $(MASTER)/pathopen.web # no change file + $(CTANGLE) $(MASTER)/pathopen + mv pathopen.h $(MASTER) + +$(MASTER)/pathopen.o: $(MASTER)/pathopen.c + cc $(CFLAGS) -c $(MASTER)/pathopen.c + mv pathopen.o $(MASTER) + + + +# This cleanup applies to every language + +clean: + if [ -f WebMakefile ]; then exit 1; fi # don't clean the master! + if [ -f spiderman.tex ]; then exit 1; fi # don't clean the manual! +# -rm -f tangle.* weave.* common.* # remove links that may be obsolete +# -rm -f *.unsorted *.list grammar.web outtoks.web scraps.web +# -rm -f cycle.test spider.slog + -rm -f *.c *.o *.tex *.toc *.dvi *.log *.makelog *~ *.wlog *.printlog + diff --git a/web/spiderweb/tools/depend.web b/web/spiderweb/tools/depend.web new file mode 100644 index 0000000000..42049d4947 --- /dev/null +++ b/web/spiderweb/tools/depend.web @@ -0,0 +1,128 @@ +\def\title{Finding dependencies in a {\tt WEB} file} +@*Introduction. +Often we want to know what files another {\tt WEB} file depends on, for +use in ``{\tt make depend}.'' +This program reads a {\tt WEB} file, looking for |"@i"| at the +beginning of a line, and writes +the names of all of the include files on standard output. +It searches the paths set by the |WEBPATH| environment variable. + +Usage is: +$${\tt depend [-a<at-sign>] [-I<directory>] [files...]}$$ +If no at sign is specified, we use |'@@'|. +If no files are specified, we read from standard input. +In no case do we write the name of the file given on the command line. + +@ The main program just processes the arguments. +|switchar(c)| tells whether |c| introduces an option. +@d switchar(c) = ((c)=='-') +@u +#include <stdio.h> +#include <ctype.h> +@i pathopen.h +static char at_sign = '@@'; + +main(argc,argv) + int argc; char **argv; +{ + FILE *fp; + + @<Read options and set |argc|, |argv| to remaining args@>@; + + pathaddpath(getenv("WEBPATH"),':'); + + if (argc==0) + depend(stdin); + else while (argc-->0) + if ((fp=pathopen(*argv++))!=NULL) + depend(fp); + else { + fprintf(stderr,"Can't find %s on search path\n",*--argv); + exit(1); + } +} + +@ @<Read options...@>= +while (--argc>0) + if (switchar(**++argv)) + switch(*++(*argv)) { + case 'a': + ++*argv; + @<Set |at_sign| according to |**argv|@>@; + break; + case 'I': + pathaddname(++(*argv)); + break; + default: + fprintf(stderr,"Unknown option -%c\n", **argv); + break; + } + else break; + +@ Since {\tt \#} is hard to write in {\tt Makefile}, we +let {\tt s} stand for {\tt \#}. +@<Set |at_sign| according to |**argv|@>= +at_sign = **argv; +if (at_sign=='s') at_sign='#'; + +@ All the real work is done by the recursive function |depend|, which +searches for {\tt @@i} and prints its findings on |stdout|. +@u +depend (fp) + FILE *fp; +{ + int c; + char filename[128], *fn; + FILE *fp2; + + c='\n'; /* begin like at the end of a line */ + do { + if (c=='\n') { + end_line: + if ((c=getc(fp))==EOF) break; + if (c==at_sign) { + if ((c=getc(fp))==EOF) break; + if (c=='i' || c=='I') { /* live one */ + @<Get name, print, and call |depend|@>@; + } else if (c=='\n') goto end_line; + } else if (c=='\n') goto end_line; + } + } while ((c=getc(fp))!=EOF); + fclose(fp); +} + +@ @<Get name, print, and call |depend|@>= +while ((c=getc(fp))!=EOF) + if (!isspace(c)) break; +if (c==EOF) break; +fn=filename; +do { + if (isspace(c)) break; + else { + *fn++=c; + putchar(c); + } +} while ((c=getc(fp))!=EOF); +*fn='\0'; +putchar('\n'); +if ((fp2=pathopen(filename))!=NULL) + depend(fp2); +else { + fprintf(stderr,"Can't find %s on search path\n",filename); + exit(1); +} +if (c==EOF) break; +if (c=='\n') goto end_line; +/* N.B. to reiterate |isspace(c)|, so |c!=at_sign| */ + +@ Here's what |pathopen| and friends call in case of overflow. +@u +overflow(s) + char *s; +{ + fprintf(stderr,"Sorry, capacity exceeded: %s\n",s); + exit(1); +} + +@*Index. + diff --git a/web/spiderweb/tools/excerpt/excerpt b/web/spiderweb/tools/excerpt/excerpt new file mode 100644 index 0000000000..8a956d80c4 --- /dev/null +++ b/web/spiderweb/tools/excerpt/excerpt @@ -0,0 +1,54 @@ +#!/bin/sh +# Take excerpts from a TeX file generated by Weave + +LIB=$HOME/lib/`cputype` + +if [ $# -ne 1 ]; then + echo "Usage: excerpt name" 1>&2 + exit 1 +fi + +if [ -r $1.tex ]; then + lines=`sed '/^ *\([0-9]*\).*\\N[0-9]*[.] *\([^ ]\)\([^.]*\)[.].*$/!d +/^ *\([0-9]*\).*\\N[0-9]*[.] *\([^ ]\)\([^.]*\)[.].*$/= +s/^.*\\N[0-9]*[.] *\([^ ]\)\([^.]*\)[.].*$/\1 \2/ +' $1.tex | awk 'BEGIN { FS=" " # tab + OFS=" " # tab + level["="]=-1 + level["1"]=1 + level["2"]=2 + level["3"]=3 + level["4"]=4 + } +NF==1 {line=$1} +NF==2 { +# print "\"" $1 "\"", level[$1] + if (level[$1]==0) { + name = $1 $2 + } else { + name = $2 + } + + print line + print level[$1]+1 + print name + }' | $LIB/section` + while true; do + echo -n "Did you include the index in the excerpts [ny]? " 1>&2 + read reply + if [ "$reply" = "" ]; then reply="n" ; fi + case $reply in + [ny]) break ;; + *) echo "respond with y or n" 1>&2 ;; + esac + done + echo Splitting $1.tex... 1>&2 + $LIB/filesplit - $lines < $1.tex > $1-excerpts.tex + if [ "$reply" = "n" ]; then + echo \\inx\\fin\\con >> $1-excerpts.tex + fi +else + echo "I can't find the file $1.tex" 1>&2 + exit 1 +fi + diff --git a/web/spiderweb/tools/excerpt/excerpt.doc b/web/spiderweb/tools/excerpt/excerpt.doc new file mode 100644 index 0000000000..1a0839cbb5 --- /dev/null +++ b/web/spiderweb/tools/excerpt/excerpt.doc @@ -0,0 +1,31 @@ +excerpt allows you to extract pieces of a tex file generated by weave. +Like the TeX macros, excerpt recognizes the following hierarchy of +section names: + In Text In Contents + #*= major division new page Bold title + #* ordinary section new page standard title + #*1 subsection new page indented + #*2 subsection same page indented + #*3 subsection new page double-indented + #*4 subsection same page double-indented + +Each kind of section is said to ``contain'' all sections below it in +the table. Thus if you have a WEB file with a section called +``#*=Abstract Syntax.'', that section will contain all of the sections +up to (and not including) the next #*=. excerpt makes heavy use of +containment. + +If you type `excerpt vcgen', the program will go through a list of all +of the sections in vcgen.tex, asking you whether you want to include +each one. You may reply `y' (yes), `n' (no), or `a' (all). Or you +may hit the carriage return and get the default (all). The replies +have the following meanings: + + y include the section, and ask about contained subsections + n omit this section, along with all the sections it contains + a include this section and all the sections it contains + +The output is written to `vcgen-excerpts.tex', and must be run through +TeX and dvi in the usual way. Of course you can use any name, not +just vcgen. + diff --git a/web/spiderweb/tools/excerpt/filesplit.web b/web/spiderweb/tools/excerpt/filesplit.web new file mode 100644 index 0000000000..23e37eaac9 --- /dev/null +++ b/web/spiderweb/tools/excerpt/filesplit.web @@ -0,0 +1,163 @@ +@*Splitting mailing lists. +The object of the game is to split mailing lists into multiple files. +Usage is +$$\hbox{\tt filesplit prefix numbers}$$ +where {\tt prefix} is the prefix of all the output file names, and +{\tt numbers} is a list of line numbers on which pieces of the file begin. +The first line of the file is considered line~1 +(for compatibility with {\tt awk(1)}). +The numbers must be sorted in increasing order. +A section consists of material from one number to the next. +The material is printed in a file whose name begins with the {\tt prefix}, +and which ends with a unique suffix (e.g. {\tt 00001, 00002, ...}). + +If a section number is preceded by a minus sign, +the section beginning with that line number gets thrown on the floor +instead of printed. + +If the prefix is |"-"|, we write all the writable sections to standard +output. +This makes it posssible to extract just pieces of a file. +@<Print usage message and exit@>= +fprintf(stderr,"Usage:\n"); +fprintf(stderr,"\tfilesplit prefix numbers...\n"); +exit(1); + + +@ @c +#include <stdio.h> +main (argc, argv) + int argc; + char ** argv; +{ + char *prefix; + @<Variable declarations@>; + + + if (argc--<3) { + @<Print usage message and exit@>; + } + + prefix = *++argv; + argc--, argv++; + @<With |argc=number count| and |argv| pointing to list, process + standard input into files@>; + exit(0); +} + +@ With only one number left in the list, our job is to print from that +line to end of file. +Otherwise, we have two numbers, which we'll call |from_line| and |to_line|. +We'll track the current line with |this_line|, which will be the number of +next line schedule to be written to the output (or thrown on the floor). +We have an implicit initial {\tt -1}, i.e. we don't print the initial +segment of the file. +@<Variable dec...@>= + int from_line, to_line; + int this_line; /* the number of the next line scheduled to be + printed */ + +@ +@<With |argc=number count| and |argv| pointing to list, process + standard input into files@>= +multi_output=1; +@<If |prefix=="-"|, make |stdout| the output file and set |multi_output=0|@>; +printing=0; +from_line=0; +this_line=1; +while (argc!=0) { + @<Read an argument into |to_line|, set |next_printing|, + check for order, + and advance |argv|@>; + @<If |printing && multi_output|, + choose a name for the output file and open it@>; + while (this_line != to_line) { + @<Copy current line to output file + (or throw out if not |printing|) + and advance |this_line|, + jumping to |finish| on end of file@>; + } + @<If |printing && multi_output|, close the output file@>; + from_line = to_line; + printing = next_printing; + } +@<If |printing && multi_output|, + choose a name for the output file and open it@>; +while (1) { + @<Copy current line to output file...@>; + } +finish: + @<Yelp if we ended prematurely@>; + + +@ We ended prematurely if |from_line!=to_line|. +@<Yelp...@>= +if (from_line != to_line) + fprintf(stderr,"filesplit: premature end of file\n"); + + + + +@ We might as well get the details of the output files done with now. +@<Variable dec...@>= + FILE *output; + char filename[255]; + int sequence_number=0; + int multi_output; +@ @<If |prefix=="-"|, make |stdout| the output file and set |multi_output=0|@>= +if (!strcmp(prefix,"-")) { + output=stdout; + multi_output=0; + } + +@ @<If |printing && multi_output|, choose a name...@>= +if (printing && multi_output) { + sprintf(filename,"%s%05d", prefix, sequence_number++); + if ((output=fopen(filename,"w"))==NULL) { + @<Print an error message and exit@>; + } + } + +@ @<If |printing && multi_output|, close the output file@>= +if (printing && multi_output) fclose(output); + +@ Here's how the copying works +@<Copy current line to output file...@>= +while ((c=getchar())!=EOF) { + if (printing) putc(c,output); + if (c=='\n') { + this_line++; + break; + } + } +if (c==EOF) goto finish; +@ @<Variable dec...@>=char c; + +@ Since we determine sign when we read the target, we save the sign to set +|printing| the next time around. +@<Variable dec...@>=int printing, next_printing; + + + +@ Here's our argument processing: +@ @<Read an argument into |to_line|...@>= +sscanf(*argv++,"%d",&to_line); argc--; +if (to_line<0) { + to_line = - to_line; + next_printing = 0; + } +else { + next_printing=1; + } + +if (to_line <= from_line) { + fprintf(stderr,"filesplit: numbers out of order\n"); + exit(-1); + } + + +@ @<Print an error message and exit@>= +fprintf(stderr,"filesplit: I couldn't open a file or something\n"); +exit(-1); + +@*Index. diff --git a/web/spiderweb/tools/excerpt/section.c b/web/spiderweb/tools/excerpt/section.c new file mode 100644 index 0000000000..355cf9a2a9 --- /dev/null +++ b/web/spiderweb/tools/excerpt/section.c @@ -0,0 +1,70 @@ +#include <stdio.h> +main() { + FILE * ttyin, *ttyout; + char buffer[800]; + char ttybuffer[80]; + int line; + int level,skiplevel; + int skipping=0; + int all=0; + char *name = buffer; + +#define barf fprintf(stderr,"section: file error\n"); exit(1); + if (NULL==(ttyin=fopen("/dev/tty","r"))) { + barf; + } + if (NULL==(ttyout=fopen("/dev/tty","w"))) { + barf; + } + printf("1 "); + level=skiplevel=99; + while (gets(buffer)!=NULL) { + sscanf(buffer,"%d", &line); + if (gets(buffer)==NULL) {barf;} + sscanf(buffer,"%d", &level); + if (gets(buffer)==NULL) {barf;} +/* fprintf(ttyout,"Checking level %d section on line %4d \"%s\"\n", +/* level, line, name); +/* fprintf(ttyout,"skipping=%d and skiplevel=%d\n", skipping,skiplevel); + */ + if ((!skipping) || level <= skiplevel) { + if (all && level>skiplevel) { + fprintf(ttyout," includes \"%s\"...\n", name); + } else { + int querycount=0; + skiplevel=level; + *ttybuffer='X'; + while (*ttybuffer !='y' && *ttybuffer != 'n' && *ttybuffer != 'a' + && *ttybuffer != '\0') { + fprintf(ttyout,"Print level %d section \"%s\" [ayn]? ", + level, name); + fflush(ttyout); + fgets(ttybuffer,80,ttyin); + if (++querycount>10) { + fprintf(ttyout, + "If you won't type 'y', 'n', 'a', or <CR>, I'll just quit\n"); + exit(8); + } + + } + if (*ttybuffer=='n') { + if (!skipping) printf ("%d ", -line); + skipping = 1; + all = 0; + } else if (*ttybuffer=='a' || *ttybuffer=='\0') { + if (skipping) printf ("%d ", line); + skipping = 0; + all=1; + } else { + if (skipping) printf ("%d ", line); + skipping = 0; + all=0; + } + } + } + } +} + + + + diff --git a/web/spiderweb/tools/shortindex b/web/spiderweb/tools/shortindex new file mode 100644 index 0000000000..5fe0918471 --- /dev/null +++ b/web/spiderweb/tools/shortindex @@ -0,0 +1,3 @@ +#!/bin/csh -f +# Make a ``short index'' for file $1 +grep "^\\:\{" $1.tex | cat ~ada/tex/indexhead.tex - ~ada/tex/indextail.tex > short$1.tex diff --git a/web/spiderweb/tools/tie/@read@.me b/web/spiderweb/tools/tie/@read@.me new file mode 100644 index 0000000000..9fbc4d20f5 --- /dev/null +++ b/web/spiderweb/tools/tie/@read@.me @@ -0,0 +1,29 @@ +This file contains a description of the files contained on the +TIE distribution tape/diskettes and some hints for installation. + +If TIE is distributed together with CWEB in tape format this file is +file number 8 on a tape. + + +File Description + @read@.me This file + tie.web WEB source of the TIE processor + tie.chf A sample change file for TIE + tiedoc.tex The LaTeX source file of the TIE documentation + + +Hints for installation + +We assume that you have a working WEB system. +Use the sample change file to create a change file for your compiler +and operating system. + +Run TANGLE to create TIE.PAS from TIE.WEB and your new change file, +then compile TIE.PAS to obtain a working TIE processor. + +Run LaTeX and a driver program for your printer to create copies of the +TIE documentation. + +Now the TIE processor is ready for use. + + diff --git a/web/spiderweb/tools/tie/Makefile b/web/spiderweb/tools/tie/Makefile new file mode 100644 index 0000000000..b6bf452145 --- /dev/null +++ b/web/spiderweb/tools/tie/Makefile @@ -0,0 +1,13 @@ +CC=lcc +CFLAGS=-g -DDEBUG +WEBS=character.web datadecl.web error.web history.web io.web tie.web +DEST=. + +tie: tie.o + $(CC) $(CFLAGS) -o $(DEST)/tie tie.o + +tie.c: $(WEBS) + ceetangle tie + +clean: + -rm -f *.o *.log *.dvi *.toc *.aux tie.c tie.tex *~ diff --git a/web/spiderweb/tools/tie/cf1 b/web/spiderweb/tools/tie/cf1 new file mode 100644 index 0000000000..5b1165435c --- /dev/null +++ b/web/spiderweb/tools/tie/cf1 @@ -0,0 +1,14 @@ +@x +line 2 +line 3 +@y +changed line 2 +changed line 3 +inserted line +@z + +@x +line 7 +@y +changed line 7 +@z diff --git a/web/spiderweb/tools/tie/cf2 b/web/spiderweb/tools/tie/cf2 new file mode 100644 index 0000000000..386bc37587 --- /dev/null +++ b/web/spiderweb/tools/tie/cf2 @@ -0,0 +1,19 @@ +@x +line 1 +changed line 2 +changed line 3 +inserted line +line 4 +@y +final line 2 +final line 3 +changed line 4 +@z + +@x +changed line 7 +line 8 +@y +final line 7 +final line 8 +@z diff --git a/web/spiderweb/tools/tie/cf3 b/web/spiderweb/tools/tie/cf3 new file mode 100644 index 0000000000..6c0e2458da --- /dev/null +++ b/web/spiderweb/tools/tie/cf3 @@ -0,0 +1,5 @@ +@x +changed line 4 +@y +final line 4 +@z diff --git a/web/spiderweb/tools/tie/character.web b/web/spiderweb/tools/tie/character.web new file mode 100644 index 0000000000..8d354334e7 --- /dev/null +++ b/web/spiderweb/tools/tie/character.web @@ -0,0 +1,148 @@ +@* The character set. +One of the main goals in the design of \.{WEB} has been to make it readily +portable between a wide variety of computers. Yet \.{WEB} by its very +nature must use a greater variety of characters than most computer +programs deal with, and character encoding is one of the areas in which +existing machines differ most widely from each other. + +To resolve this problem, all input to \.{WEAVE} and \.{TANGLE} is converted +to an internal seven-bit code that is essentially standard ASCII, the +``American Standard Code for Information Interchange.'' The conversion +is done immediately when each character is read in. Conversely, +characters are converted from ASCII to the user's external +representation just before they are output. + +Such an internal code can be accessed by users of \.{WEB} by means of +constructions like \.{@@'A'}, which should be distinguished from +\.{'A'}. The former is transformed by +\.{TANGLE} into an integer that is the internal code of \.A, but +the latter, a |char| constant, is not touched by +\.{WEB}, and will be interpreted by the \cee\ complier according to +the machine's character set. (Actually, of course, it gets translated +into \.{WEB}'s internal code just like any other character in the +input file, but then it gets translated back at output time.) +@^ASCII code@> + +Here is a table of the standard visible ASCII codes (\.{ } stands for +a blank space): +$$\def\:{\char\count255\global\advance\count255 by 1} +\count255='40 +\vbox{ +\hbox{\hbox to 40pt{\it\hfill0\/\hfill}% +\hbox to 40pt{\it\hfill1\/\hfill}% +\hbox to 40pt{\it\hfill2\/\hfill}% +\hbox to 40pt{\it\hfill3\/\hfill}% +\hbox to 40pt{\it\hfill4\/\hfill}% +\hbox to 40pt{\it\hfill5\/\hfill}% +\hbox to 40pt{\it\hfill6\/\hfill}% +\hbox to 40pt{\it\hfill7\/\hfill}} +\vskip 4pt +\hrule +\def\^{\vrule height 10.5pt depth 4.5pt} +\halign{\hbox to 0pt{\hskip -24pt\O{#0}\hfill}&\^ +\hbox to 40pt{\tt\hfill#\hfill\^}& +&\hbox to 40pt{\tt\hfill#\hfill\^}\cr +04&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +05&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +06&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +07&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +10&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +11&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +12&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +13&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +14&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +15&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +16&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +17&\:&\:&\:&\:&\:&\:&\:\cr} +\hrule width 280pt}$$ + +We introduce new types to distinguish between the transliterated characters +and the characters in the outside world. Let all +``interesting'' values that a |char| variable may take lie between +|first_text_char| and |last_text_char|; for the ASCII code we can +take |first_text_char=0| and |last_text_char=0177|. We will tell \.{WEB} +to convert all input characters in this range to its own code, and balk at +characters outside the range. We make two assumptions: +|first_text_char>=0| and |char| has room for at least eight bits. +@^system dependencies@> + +@d first_text_char = 0 /* lowest interesting value of a |char| */ +@d last_text_char = 0177 /* highest interesting value of a |char| */ + +@<Input and output types@>= +typedef char ASCII; /* type of characters inside \.{WEB} */ +typedef char outer_char; /* type of characters outside \.{WEB} */ + +@ The \.{WEAVE} and \.{TANGLE} processors convert between ASCII code and +the user's external character set by means of arrays |xord| and |xchr| +that are analogous to PASCAL's |ord| and |chr| functions. + +@<Globals...@>= +ASCII xord[last_text_char]; /* specifies conversion of input characters */ +outer_char xchr[0200]; /* specifies conversion of output characters */ + +@ Every system supporting \cee\ must be able to read and write the 95 +visible characters of standard ASCII above (although not necessarily using the +ASCII codes to represent them). Conversely, these characters, plus +the newline, are sufficient to write any \cee\ program. Other +characters are desirable mainly in strings, and they can be referred +to by means of escape sequences like \.{'\t'}. + +The basic implementation of \.{WEB}, then, only has to assign an +|xord| to these 95 characters (newlines are swallowed by the reading +routines). The easiest way to do this is to assign the characters to +their positions in |xchr| and then invert the correspondence: + +@c +common_init() +{ + strcpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "); + @<System-dependent parts of character set@>; + @<Invert |xchr| to get |xord|@>; +} + +@ The following system-independent code makes the |xord| array contain +a suitable inverse to the information in |xchr|. + +@<Invert |xchr|...@>= { + int i; /* to invert the correspondence */ + for (i=first_text_char; i<=last_text_char; i++) xord[i]='\040'; + for (i=1; i<0177; i++) xord[xchr[i]]=i; +} + +@ Some \cee\ compilers accept an extended character +set, so that one can type things like \.^^Z\ instead of \.{!=}. +If that's the case in your system, you should change this module, +assigning positions |01| to |037| in the most convenient way; +for example, at MIT you can just say +$$\hbox{|for (i=1; i<=037; i++) xchr[i]=i;|}$$ +since \.{WEB}'s character set is essentially identical to MIT's, +even with respect to characters less than |040| (see the definitions +below). If, however, the changes do not conform with these +definitions you should change the definitions as well. +@^system dependencies@> +@^notes to myself@> + +@<System-dependent parts of character set@>= /* nothing needs to be done */ + +@ +@d text_char = char /* the data type of characters in text files */ + + +@<Input and output types@>= +typedef char ascii_code; /* ascii codes from 0 to 127 */ +typedef FILE *text_file; + + +@ One of the \ASCII{} codes below 040 has been given a +symbolic name in \.{TIE} because it is used with a special +meaning. + +@d tab_mark = '\t' /* \ASCII{} code used as tab-skip */ + + +@ When we initialize the |xord| array and the remaining +parts of |xchr|, it will be convenient to make use of an +index variable, |i|. + diff --git a/web/spiderweb/tools/tie/datadecl.web b/web/spiderweb/tools/tie/datadecl.web new file mode 100644 index 0000000000..08b2ed2119 --- /dev/null +++ b/web/spiderweb/tools/tie/datadecl.web @@ -0,0 +1,74 @@ +@* Data structures. + +\noindent The multiple input files (master file and change +files) are treated the same way. To organize the +simultaneous usage of several input files, we introduce the +data types |in_file_modes|. + +The mode |search| indicates that \.{TIE} searches for a +match of the input line with any line of an input file in +|reading| mode. |test| is used whenever a match is found +and it has to be tested if the next input lines do match +also. |reading| describes that the lines can be read without +any check for equality to other lines. |ignore| denotes +that the file cannot be used. This may happen because an +error has been detected or because the end of the file has +been found. + +\leavevmode |file_types| is used to describe whether a file +is a master file or a change file. +@d search = 1 +@d test = 2 +@d reading = 3 +@d ignore = 4 + +@d master = 1 +@d chf = 2 + +@<Types...@>= +typedef char in_file_modes; +typedef char file_types; + +@ We have to add a boolean type since none is present in C. +@d true = 1 +@d false = 0 +@<Types...@>= +typedef char boolean; + +@ The following data structures join all informations needed to use +these input files. + +@d normal = 1 +@d pre = 2 +@d post = 3 + +@<Types...@>= +typedef char out_md_type;@/ +typedef char *name_type;@/ +typedef int buffer_index; +typedef int file_index; +typedef struct { + name_type name_of_file; + ascii_code buffer[buf_size+1]; + in_file_modes mode; + int lineno; + file_types type_of_file; + int limit; +} input_description; + + + +@ These data types are used in the global variable section. + +@<Globals...@>= +int actual_input, test_input; +boolean input_has_ended; + input_description input_organization[max_file_index+1]; + text_file input_files[max_file_index+1]; +int no_ch; +boolean prod_chf; +out_md_type out_mode; +int verbose = 0; /* noisy if nonzero */ + + + diff --git a/web/spiderweb/tools/tie/error.web b/web/spiderweb/tools/tie/error.web new file mode 100644 index 0000000000..6e9cb913ca --- /dev/null +++ b/web/spiderweb/tools/tie/error.web @@ -0,0 +1,56 @@ +@* Reporting errors to the user. + +\noindent There may be errors if a line in a given change +file does not match a line in the master file or a +replacement in a previous change file. Such errors are +reported to the user by saying +$$ + \hbox{|err_print('! Error message')|.} +$$ +Please note that no trailing point is supplied by the error +message because it is appended by |err_print|. Non +recoverable errors are handled by calling |fatal_error| that +outputs a message and then calls `|jump_out()|'. + +\leavevmode |err_print| will print the error message +followed by an indication of where the error was spotted in +the source files. |fatal_error| cannot state any files +because the problem is usually to access these. + +For |err_print| messages the following procedure is used to +write the proper name of an input file. + +@d fatal_error(X) = {print_nl(X); print_ln("."); history=fatal; jump_out();} + +@<Error handling...@>= + print_name_of_file(cur_index) + file_index cur_index; +{ + fprintf(stderr,"%s",input_organization[cur_index].name_of_file); +} + + +@ The actual error indications are provided by a procedure +called |err_loc|. + +@<Error handling...@>= + err_loc(i) /* prints location of error */ +int i; +{ + fprintf(stderr, + " (file %s, l.%d).\n",input_organization[i].name_of_file, + input_organization[i].lineno); +@^system dependencies@> +} + +@ If it is necessary to abort the job because of a fatal +error, the program calls the `|jump_out()|' procedure, which +does something system-dependent. +@^system dependencies@> +@ The |jump_out()| procedure just cuts across all active +procedure levels and jumps out of the program. +It is implemented by a call to |exit()|. +@^system dependencies@> + +@<Error handling...@>= + jump_out() { exit(history==spotless ? 0 : 1);} diff --git a/web/spiderweb/tools/tie/history.web b/web/spiderweb/tools/tie/history.web new file mode 100644 index 0000000000..a6a9a7ef4d --- /dev/null +++ b/web/spiderweb/tools/tie/history.web @@ -0,0 +1,25 @@ +@*Job history. + We introduce a history variable that allows us to set a +return code if the operating system and the local \PASCAL\ +compiler allow it. First we introduce the coded values for +the history. + +@d spotless = 0 +@d troublesome = 1 +@d fatal = 2 + +@<Globals in ...@>= +@!int history; + + +@ We must initialize this variable at the very beginning. + +@<Set initial values@>= +history=spotless; +@ At the end of the job we may want to print out the history. +@<Print the job |history|...@>= +switch ( history) { +case spotless: if (verbose) print_ln("(No errors were found.)"); break; +case troublesome: print_ln("(Pardon me, but I think I spotted something wrong.)"); break; +case fatal: print_ln("(That was a fatal error, my friend.)"); break; +} diff --git a/web/spiderweb/tools/tie/io.web b/web/spiderweb/tools/tie/io.web new file mode 100644 index 0000000000..e3dc7e894b --- /dev/null +++ b/web/spiderweb/tools/tie/io.web @@ -0,0 +1,108 @@ +@* Input and output. + +\noindent Terminal output is done by writing on file +|term_out|, which is assumed to consist of characters of +type |text_char|. Terminal input is read from |term_in|. +@^system dependencies@> + +@d print(X) = fprintf(stderr,X) /* `|print|' means write on the terminal */ +@d new_line = putc('\n',stderr) /* start new line */ +@d print_ln(X) = {print(X); new_line;} +@d print_nl(X) = { new_line; print(X);} + +@d term_in = stdin +@d term_out = stderr + +@ 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(term_out) {empty the terminal output buffer} + + +@ If an error occurs we indicate this calling a procedure +named |err_print|. This procedure is implemented as a +macro. It gives a message and an indication of the +offending file. The actions to determine the error location +will be explained later. + +@d err_print(MSG,LOC) = {print_nl(MSG); err_loc(LOC); history=troublesome;} + + +@ The basic procedure |get_ln_from_file| can be used to get +a line from an input file. The line is stored in +|input_files[i].buffer|. The components |limit| and |lineno| +are updated. If the end of the file is reached +|input_files[i].mode| is set to |ignore|. On some systems +it might be useful to replace tab characters by a proper +number of spaces since several editors used to create change +files insert tab characters into a source file not under +control of the user. So it might be a problem to create a +matching change file. +@^tab character expansion@> + +We define |get_line| to read a line from a file specified by +number. To ease an inplementation without arrays of files +we introduce one more parameter. In such cases |get_line| +is best replaced by a procedure containing a |case| +statement to select the file needed. + +@d get_line(X) = get_ln_from_file(X,input_files[X]); + +@c + get_ln_from_file(i,cur_file) + int i; + text_file cur_file; +{ +int final_limit; +int c; + if (input_organization[i].mode==ignore) return; + if (feof(cur_file)) @<Handle end of file and return@>; + @<Get line into buffer@>; +} + +@ End of file is special if this file is the master file. +@<Handle end of file ...@>= +{ + input_organization[i].mode=ignore; + if (input_organization[i].type_of_file==master) input_has_ended=true; + return; +} + + +@ Lines must fit into the buffer completely. +Tab character expansion might be done here. +@^tab character expansion@> + +@<Get line into buffer@>= +(input_organization[i].lineno)++; +input_organization[i].limit=0; final_limit = 0; +while ((input_organization[i].limit<=buf_size) && (c=getc(cur_file)) != EOF + && c!='\n') +{ + input_organization[i].buffer[input_organization[i].limit]=xord[c]; + (input_organization[i].limit)++; + if ((input_organization[i].buffer[input_organization[i].limit-1]!=' ') + && (input_organization[i].buffer[input_organization[i].limit-1] + != tab_mark)) + final_limit=input_organization[i].limit; +} + if (input_organization[i].limit>buf_size) + if ((c=getc(cur_file))!=EOF && c!='\n') { + ungetc(c,cur_file); err_print("! Input line too long",i); +@.Input line too long@> + } +@<Check for end of file@>@; +input_organization[i].limit=final_limit; + +@ We have to check for end of file in the middle of reading +@<Check for end of file@>= +if (input_organization[i].limit==0 && c==EOF) + @<Handle end of file...@>@; + + + + + diff --git a/web/spiderweb/tools/tie/master b/web/spiderweb/tools/tie/master new file mode 100644 index 0000000000..fa2da6e55c --- /dev/null +++ b/web/spiderweb/tools/tie/master @@ -0,0 +1,10 @@ +line 1 +line 2 +line 3 +line 4 +line 5 +line 6 +line 7 +line 8 +line 9 +line 10 diff --git a/web/spiderweb/tools/tie/newmaster b/web/spiderweb/tools/tie/newmaster new file mode 100644 index 0000000000..930094b813 --- /dev/null +++ b/web/spiderweb/tools/tie/newmaster @@ -0,0 +1,9 @@ +final line 2 +final line 3 +final line 4 +line 5 +line 6 +final line 7 +final line 8 +line 9 +line 10 diff --git a/web/spiderweb/tools/tie/tie.c b/web/spiderweb/tools/tie/tie.c new file mode 100644 index 0000000000..679787ad26 --- /dev/null +++ b/web/spiderweb/tools/tie/tie.c @@ -0,0 +1,696 @@ +/*2:*/ +#line 66 "tie.web" + +#include<stdio.h> +/*56:*/ +#line 72 "character.web" + +typedef char ASCII; +typedef char outer_char; + +/*:56*//*61:*/ +#line 133 "character.web" + +typedef char ascii_code; +typedef FILE *text_file; + + +/*:61*/ +#line 68 "tie.web" + +/*9:*/ +#line 28 "datadecl.web" + +typedef char in_file_modes; +typedef char file_types; + +/*:9*//*10:*/ +#line 35 "datadecl.web" + +typedef char boolean; + +/*:10*//*11:*/ +#line 45 "datadecl.web" + +typedef char out_md_type; +typedef char *name_type; +typedef int buffer_index; +typedef int file_index; +typedef struct{ +name_type name_of_file; +ascii_code buffer[100+1]; +in_file_modes mode; +int lineno; +file_types type_of_file; +int limit; +}input_description; + + + +/*:11*/ +#line 69 "tie.web" + +/*8:*/ +#line 165 "tie.web" + +int next_available_file= 0; +#line 1 "datadecl.web" +/*:8*//*12:*/ +#line 63 "datadecl.web" + +int actual_input,test_input; +boolean input_has_ended; +input_description input_organization[9+1]; +text_file input_files[9+1]; +int no_ch; +boolean prod_chf; +out_md_type out_mode; +int verbose= 0; + + + +#line 168 "tie.web" + + + + +/*:12*//*14:*/ +#line 190 "tie.web" +boolean lines_dont_match(); +/*:14*//*16:*/ +#line 204 "tie.web" +boolean e_of_ch_module(); + +/*:16*//*18:*/ +#line 219 "tie.web" +boolean e_of_ch_module(); + +/*:18*//*21:*/ +#line 236 "tie.web" +boolean file_open(); + +/*:21*//*40:*/ +#line 529 "tie.web" +long int lines_processed= 0; +/*:40*//*49:*/ +#line 11 "history.web" + +int history; + + +/*:49*//*57:*/ +#line 80 "character.web" + +ASCII xord[0177]; +outer_char xchr[0200]; + +/*:57*/ +#line 70 "tie.web" + +/*52:*/ +#line 25 "error.web" + +print_name_of_file(cur_index) +file_index cur_index; +{ +fprintf(stderr,"%s",input_organization[cur_index].name_of_file); +} + + +/*:52*//*53:*/ +#line 36 "error.web" + +err_loc(i) +int i; +{ +fprintf(stderr, +" (file %s, l.%d).\n",input_organization[i].name_of_file, +input_organization[i].lineno); + +} + +/*:53*//*55:*/ +#line 55 "error.web" + +jump_out(){exit(history==0?0:1);} +#line 1 "character.web" +/*:55*/ +#line 71 "tie.web" + + +main(argc,argv) +int argc; +char * *argv; +{ +int i,j; + +/*50:*/ +#line 17 "history.web" + +history= 0; +/*:50*/ +#line 79 "tie.web" + +if(verbose) +{fprintf(stderr,"This is TIE, C Version 0.1 (ported to C)");putc('\n',stderr);}; +/*7:*/ +#line 137 "tie.web" + +while(--argc>0){ +if( * *++argv=='-') +switch( *++ *argv){ +case'm': +prod_chf= 0; +break; +case'c': +prod_chf= 1; +break; +case'v': +verbose++; +break; +default: +fprintf(stderr,"Bad option -%c ignored\n", + * *argv); +break; +} +else{ +if(next_available_file>9) +{{putc('\n',stderr);fprintf(stderr,"too many files");};{fprintf(stderr,".");putc('\n',stderr);};history= 2;jump_out();}; +input_organization[next_available_file++].name_of_file= *argv; +} +} + + +/*:7*/ +#line 83 "tie.web" +; +/*30:*/ +#line 374 "tie.web" + +common_init(); +for(i= 0;i<next_available_file;i++){ +input_organization[i].mode= 1; +input_organization[i].lineno= 0; +input_organization[i].type_of_file= 2; +input_organization[i].limit= 0; +for(j= 0;j<=100;j++)input_organization[i].buffer[j]= 0; +} +actual_input= 0; +out_mode= 1; +open_input(); + + +/*:30*/ +#line 84 "tie.web" +; +/*3:*/ +#line 93 "tie.web" + +input_has_ended= 0; +while(!input_has_ended||(actual_input!=0))process_line(); +if(out_mode==3) +write_string(stdout,"@z\n"); +/*41:*/ +#line 530 "tie.web" +if(verbose)fprintf(stderr,"\n"); + + +#line 1 "io.web" +/*:41*/ +#line 98 "tie.web" +; + + +/*:3*/ +#line 85 "tie.web" +; +/*4:*/ +#line 105 "tie.web" + +for(i= 1;i<next_available_file;i++) +if(input_organization[i].mode!=4) +{{putc('\n',stderr);fprintf(stderr,"! Change file entry did not match");};err_loc(i);history= 1;}; + + +/*:4*/ +#line 86 "tie.web" +; + +/*51:*/ +#line 20 "history.web" + +switch(history){ +case 0:if(verbose){fprintf(stderr,"(No errors were found.)");putc('\n',stderr);};break; +case 1:{fprintf(stderr,"(Pardon me, but I think I spotted something wrong.)");putc('\n',stderr);};break; +case 2:{fprintf(stderr,"(That was a fatal error, my friend.)");putc('\n',stderr);};break; +} +#line 1 "error.web" +/*:51*/ +#line 88 "tie.web" + +jump_out(); +} + +/*:2*//*13:*/ +#line 177 "tie.web" + +boolean lines_dont_match(i,j) +int i,j; +{ +buffer_index k,lmt; +if(input_organization[i].limit!=input_organization[j].limit) +return 1; +lmt= input_organization[i].limit; +for(k= 0;k<lmt;k++) +if(input_organization[i].buffer[k]!=input_organization[j].buffer[k]) +return 1; +return 0; +} +/*:13*//*15:*/ +#line 194 "tie.web" + +boolean e_of_ch_module(i) +int i; +{ +return((input_organization[i].limit>=2)&& +(input_organization[i].buffer[0]=='@')&& +((input_organization[i].buffer[1]=='Z')|| +(input_organization[i].buffer[1]=='z'))); +} + +/*:15*//*17:*/ +#line 209 "tie.web" + +boolean e_of_ch_preamble(i) +int i; +{ +return((input_organization[i].limit>=2)&& +(input_organization[i].buffer[0]=='@')&& +((input_organization[i].buffer[1]=='Y')|| +(input_organization[i].buffer[1]=='y'))); +} + +/*:17*//*20:*/ +#line 228 "tie.web" + +boolean file_open(f,name) +text_file *f; +name_type name; +{ +return(( *f= fopen(name,"r"))!=NULL); +} + +/*:20*//*22:*/ +#line 240 "tie.web" + +/*25:*/ +#line 297 "tie.web" + +init_change_file(i,b) +int i; +boolean b; +{ +/*26:*/ +#line 312 "tie.web" + +while(1){ +get_ln_from_file(i,input_files[i]);; +if(input_organization[i].mode==4)return; +if(input_organization[i].limit<2)continue; +if(input_organization[i].buffer[0]!='@')continue; +if((input_organization[i].buffer[1]>='X') +&&(input_organization[i].buffer[1]<='Z')) +input_organization[i].buffer[1]+= 'z'-'Z'; +if(input_organization[i].buffer[1]=='x')break; +if((input_organization[i].buffer[1]=='y')|| +(input_organization[i].buffer[1]=='z')) +if(b) +{{putc('\n',stderr);fprintf(stderr,"! Where is the matching @x?");};err_loc(i);history= 1;}; + +} + + + +/*:26*/ +#line 302 "tie.web" +; +/*27:*/ +#line 333 "tie.web" + +do{ +get_ln_from_file(i,input_files[i]);; +if(input_organization[i].mode==4){ +{{putc('\n',stderr);fprintf(stderr,"! Change file ended after @x");};err_loc(i);history= 1;}; + +return; +} +}while(input_organization[i].limit<=0); + + +/*:27*/ +#line 303 "tie.web" +; +} + + +/*:25*/ +#line 241 "tie.web" + +open_input() +{ +int i; +/*23:*/ +#line 271 "tie.web" + +if(!file_open(&(input_files[0]),input_organization[0].name_of_file)){ +{{putc('\n',stderr);fprintf(stderr,"! Master file can\'t be opened");};{fprintf(stderr,".");putc('\n',stderr);};history= 2;jump_out();}; +} + +else{ +if(verbose){ +fprintf(stderr,"("); +print_name_of_file(0); +{fprintf(stderr,")");putc('\n',stderr);}; +} +input_organization[0].type_of_file= 1; +get_ln_from_file(0,input_files[0]);; +} + + +/*:23*/ +#line 245 "tie.web" +; +actual_input= 0; +no_ch= 0; +while(++no_ch<next_available_file){ +if(!file_open(&(input_files[no_ch]),input_organization[no_ch].name_of_file)){ +{{putc('\n',stderr);fprintf(stderr,"! Change file can\'t be opened");};{fprintf(stderr,".");putc('\n',stderr);};history= 2;jump_out();}; +} + +else{ +if(verbose){ +fprintf(stderr,"("); +print_name_of_file(no_ch); +{fprintf(stderr,")");putc('\n',stderr);}; +} +init_change_file(no_ch,1); +} +} + +if(--no_ch==0) +{{putc('\n',stderr);fprintf(stderr,"! No change file found");};{fprintf(stderr,".");putc('\n',stderr);};history= 2;jump_out();}; + +for(i= next_available_file;i<=9;i++) +input_organization[i].mode= 4; +} + +/*:22*//*28:*/ +#line 347 "tie.web" + +put_line(j) +int j; +{ +int i; +for(i= 0;i<input_organization[j].limit;i++) +fputc(xchr[input_organization[j].buffer[i]],stdout); +fputc('\n',stdout); +} + +/*:28*//*29:*/ +#line 358 "tie.web" + +write_string(fp,s) +text_file fp; +char *s; +{ +while( *s!='\0'){ +putc( *s,fp);s++;} +} + + + + +/*:29*//*32:*/ +#line 394 "tie.web" + +process_line() +{ +int i; +/*39:*/ +#line 521 "tie.web" + +if(++lines_processed%100==0&&verbose){ +if(lines_processed%500==0) +fprintf(stderr,"%d",lines_processed); +else +fprintf(stderr,"."); +} + +/*:39*/ +#line 398 "tie.web" +; +/*33:*/ +#line 410 "tie.web" + +while(e_of_ch_module(actual_input)){ +if(input_organization[actual_input].type_of_file==1) + +{{putc('\n',stderr);fprintf(stderr,"! This can\'t happen");};{fprintf(stderr,".");putc('\n',stderr);};history= 2;jump_out();}; +input_organization[actual_input].mode= 1; +init_change_file(actual_input,1); +while((input_organization[actual_input].mode!=3) +&&(actual_input>0))actual_input--; +} +if(input_has_ended&&(actual_input==0))return; +test_input= (next_available_file); +i= actual_input; +while((test_input==(next_available_file))&&(i<no_ch)){ +i++; +switch(input_organization[i].mode){ +case 1:if(!lines_dont_match(actual_input,i)){ +input_organization[i].mode= 2; +test_input= i; +} +break; +case 2: +if(lines_dont_match(actual_input,i)) +{ + +input_organization[i].mode= 1; +{{putc('\n',stderr);fprintf(stderr,"! Sections do not match");};err_loc(actual_input);history= 1;}; + +err_loc(i); +init_change_file(i,0); +} +else test_input= i; +break; +case 3:; +break; +case 4:; +break; +} +} + + +/*:33*/ +#line 399 "tie.web" +; +/*34:*/ +#line 451 "tie.web" + +if(prod_chf){ +while(1){ +/*35:*/ +#line 464 "tie.web" + +{ +if(out_mode==1) +if(test_input!=(next_available_file)){ +write_string(stdout,"@x\n"); +out_mode= 2; +} +else break; +} + + +/*:35*/ +#line 454 "tie.web" +; +/*36:*/ +#line 477 "tie.web" + +{ +if(out_mode==2){ +if(test_input==(next_available_file)){ +write_string(stdout,"@y\n"); +out_mode= 3; +}else{ +if(input_organization[actual_input].type_of_file==1) +put_line(actual_input); +break; +} +} +} + + +/*:36*/ +#line 455 "tie.web" +; +/*37:*/ +#line 494 "tie.web" + +{ +if(out_mode==3){ +if(input_organization[actual_input].type_of_file==2){ +if(test_input==(next_available_file))put_line(actual_input); +break; +}else{ +write_string(stdout,"@z\n"); +out_mode= 1; +} +} +} + + +/*:37*/ +#line 456 "tie.web" +; +} +}else +if(test_input==(next_available_file))put_line(actual_input); + + +/*:34*/ +#line 400 "tie.web" +; +/*38:*/ +#line 508 "tie.web" + +get_ln_from_file(actual_input,input_files[actual_input]);; +if(test_input!=(next_available_file)){ +get_ln_from_file(test_input,input_files[test_input]);; +if(e_of_ch_preamble(test_input)){ +get_ln_from_file(test_input,input_files[test_input]);; +input_organization[test_input].mode= 3; +actual_input= test_input; +test_input= (next_available_file); +} +} + +/*:38*/ +#line 402 "tie.web" +; +} + + +/*:32*//*45:*/ +#line 54 "io.web" + +get_ln_from_file(i,cur_file) +int i; +text_file cur_file; +{ +int final_limit; +int c; +if(input_organization[i].mode==4)return; +if(feof(cur_file))/*46:*/ +#line 67 "io.web" + +{ +input_organization[i].mode= 4; +if(input_organization[i].type_of_file==1)input_has_ended= 1; +return; +} + + +/*:46*/ +#line 62 "io.web" +; +/*47:*/ +#line 79 "io.web" + +(input_organization[i].lineno)++; +input_organization[i].limit= 0;final_limit= 0; +while((input_organization[i].limit<=100)&&(c= getc(cur_file))!=EOF +&&c!='\n') +{ +input_organization[i].buffer[input_organization[i].limit]= xord[c]; +(input_organization[i].limit)++; +if((input_organization[i].buffer[input_organization[i].limit-1]!=' ') +&&(input_organization[i].buffer[input_organization[i].limit-1] +!='\t')) +final_limit= input_organization[i].limit; +} +if(input_organization[i].limit>100) +if((c= getc(cur_file))!=EOF&&c!='\n'){ +ungetc(c,cur_file);{{putc('\n',stderr);fprintf(stderr,"! Input line too long");};err_loc(i);history= 1;}; + +} +/*48:*/ +#line 101 "io.web" + +if(input_organization[i].limit==0&&c==EOF) +/*46:*/ +#line 67 "io.web" + +{ +input_organization[i].mode= 4; +if(input_organization[i].type_of_file==1)input_has_ended= 1; +return; +} + + +/*:46*/ +#line 103 "io.web" + + + + + + +#line 1 "history.web" +/*:48*/ +#line 97 "io.web" + +input_organization[i].limit= final_limit; + +/*:47*/ +#line 63 "io.web" +; +} + +/*:45*//*58:*/ +#line 96 "character.web" + +common_init() +{ +strcpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "); +/*60:*/ +#line 127 "character.web" + + +/*:60*//*64:*/ +#line 551 "tie.web" + +#line 552 "tie.web" +xchr['\t']= '\t'; + + +/*:64*/ +#line 101 "character.web" +; +/*59:*/ +#line 108 "character.web" +{ +int i; +for(i= 0;i<=0177;i++)xord[i]= '\040'; +for(i= 1;i<0177;i++)xord[xchr[i]]= i; +} + +/*:59*/ +#line 102 "character.web" +; +} + +/*:58*/ diff --git a/web/spiderweb/tools/tie/tie.chf b/web/spiderweb/tools/tie/tie.chf new file mode 100644 index 0000000000..c7c75980c0 --- /dev/null +++ b/web/spiderweb/tools/tie/tie.chf @@ -0,0 +1,191 @@ +@x +@d banner=='This is TIE, Version 1.3' +@y +@d banner=='This is TIE, Version 1.3 (MUNIX changes by THD/ITI)' +@z + +@x +@!max_name_length=54; {adapt this to your local name space} +@y +@!max_name_length=120; {adapt this to your local name space} +@z + +@x +@!ascii_code=0..127; {seven-bit numbers, a subrange of the integers} +@y +@!ascii_code=packed 0..127; +@z + +@x +@!text_file=packed file of text_char; +@y +@!text_file=text; +@z + +@x +xchr["\"]:='\'; +@y +xchr["\"]:='\\'; +@z + +@x +for i:=1 to @'37 do xchr[i]:=' '; +@y +for i:=1 to @'37 do xchr[i]:=' '; +xchr[tab_mark]:=chr(tab_mark); +@z + +@x +reset(term_in,'TTY:','/I') +@y +reset(term_in,'/dev/tty') +@z + +@x +rewrite(term_out,'TTY:'); +@y +rewrite(term_out,'/dev/tty'); +@z + +@x +@d update_terminal == break(term_out) {empty the terminal output buffer} +@y +@d update_terminal == write_ln(term_out) {empty the terminal output buffer} +@z + +Delete definition of |get_line|. Replace by procedure. +@x +@d get_line(#)==get_ln_from_file(#,input_files[#]); +@y +@z + +Add the definition now +@x +exit: end; +@y +exit: end; + +procedure get_line(i:file_index);@/ +begin + case i of + 0 : get_ln_from_file(0,infile0); + 1 : get_ln_from_file(1,infile1); + 2 : get_ln_from_file(2,infile2); + 3 : get_ln_from_file(3,infile3); + 4 : get_ln_from_file(4,infile4); + 5 : get_ln_from_file(5,infile5); + 6 : get_ln_from_file(6,infile6); + 7 : get_ln_from_file(7,infile7); + 8 : get_ln_from_file(8,infile8); + 9 : get_ln_from_file(9,infile9); + end; +end; +@z + +@x +@!input_files: array[0..max_file_index] of text_file; +@y +@!infile0,@!infile1,@!infile2,@!infile3,@!infile4,@!infile5:text_file; +@!infile6,@!infile7,@!infile8,@!infile9:text_file; +@z + +@x +@ We continue with a function to open a text file. Success +is indicated by a boolean result. We assume that empty +files can be handled like non existent ones. +@^system dependencies@> + +@p function file_open(var f:text_file;name:name_type):boolean; +begin + reset(f,name.name); + file_open:=not eof(f); +end; +@y +@ We continue with a function to open a text file. Success +is indicated by a boolean result. We assume that empty +files can be handled like non existent ones. +@^system dependencies@> +We use a special function to determine missing files. +@p function lookop(var n:string):integer; externc; +function file_open(var f:text_file;name:name_type):boolean;@/ +var curname:string; +begin + curname:=con@&vert(name.name,string); + if lookop(curname)=1 then + begin + reset(f,curname); + file_open:=not eof(f); + end else file_open:=false; +end; +@z + +@x + for i:=1 to max_name_length do name_of_file.name[i]:=' '; + for i:=1 to prefix.nam_len do name_of_file.name[i]:=prefix.name[i]; + for i:=1 to extension.nam_len do + name_of_file.name[prefix.nam_len+i]:=extension.name[i]; +@y + for i:=1 to prefix.nam_len do name_of_file.name[i]:=prefix.name[i]; + for i:=1 to extension.nam_len do + name_of_file.name[prefix.nam_len+i]:=extension.name[i]; + name_of_file.name[prefix.nam_len+extension.nam_len+1]:=chr(0); +@z + +@x + if not file_open(input_files[0],input_organization[0].name_of_file) then +@y + if not file_open(infile0,input_organization[0].name_of_file) then +@z + +@x +procedure open_input; {prepare to read |input_files|} +label done; +var i:integer; +@y +procedure open_input; {prepare to read |input_files|} +label done; +var i:integer; + b:boolean; +@z + +@x + if not file_open(input_files[no_ch], + input_organization[no_ch].name_of_file) +@y + case no_ch of + 1: b:=file_open(infile1,input_organization[1].name_of_file); + 2: b:=file_open(infile2,input_organization[2].name_of_file); + 3: b:=file_open(infile3,input_organization[3].name_of_file); + 4: b:=file_open(infile4,input_organization[4].name_of_file); + 5: b:=file_open(infile5,input_organization[5].name_of_file); + 6: b:=file_open(infile6,input_organization[6].name_of_file); + 7: b:=file_open(infile7,input_organization[7].name_of_file); + 8: b:=file_open(infile8,input_organization[8].name_of_file); + 9: b:=file_open(infile9,input_organization[9].name_of_file); + end; + if not b +@z + +@x +cf_ext.name[1]:='.'; +cf_ext.name[2]:='C'; +cf_ext.name[3]:='F'; +cf_ext.name[4]:=' '; +cf_ext.nam_len:=4; +for i:=cf_ext.nam_len+1 to max_name_length do cf_ext.name[i]:=' '; +@y +cf_ext.name[1]:='.'; +cf_ext.name[2]:='c'; +cf_ext.name[3]:='f'; +cf_ext.name[4]:=' '; +cf_ext.name[5]:=chr(0); +cf_ext.nam_len:=4; +@z + +@x + {here files should be closed if the operating system requires it} +@y + {here files should be closed if the operating system requires it} + {terminate with return code} + halt(history); +@z diff --git a/web/spiderweb/tools/tie/tie.preamble b/web/spiderweb/tools/tie/tie.preamble new file mode 100644 index 0000000000..d559d506d6 --- /dev/null +++ b/web/spiderweb/tools/tie/tie.preamble @@ -0,0 +1,31 @@ + +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\mc=cmcsc10 +\def\PASCAL{{\mc Pascal}} +\def\cee{{\mc C}} +\def\ASCII{{\mc ascii}} +\def\pb{$\.|\ldots\.|$} % pascal brackets (|...|) +\def\v{\.{\char'174}} % vertical (|) in typewriter font +\mathchardef\BA="3224 % double arrow +\def\({} % kludge for alphabetizing certain module names + +\def\title{TIE} +\def\topofcontents{\null\vfill + \centerline{\titlefont The {\ttitlefont TIE} processor} + \vskip 15pt + \centerline{(Version 1.3)} + \vfill} +\def\botofcontents{ +\null\vfill +\item{$\copyright$}1983, 1984, 1986 + by Technische Hochschule Darmstadt,\hfill\break +Fachbereich Informatik, Institut f\"ur Theoretische Informatik\hfill\break +All rights reserved.\hfill\break +This program is put into the public domain and may be used freely +for any non commercial purposes. +} + + + + + diff --git a/web/spiderweb/tools/tie/tie.web b/web/spiderweb/tools/tie/tie.web new file mode 100644 index 0000000000..24594a4f3e --- /dev/null +++ b/web/spiderweb/tools/tie/tie.web @@ -0,0 +1,558 @@ +% This is TIE.WEB +%------------------------------------------------------------ + +% Version 0.1 ported from PASCAL (NR) 24 August 87 + +% Here is TeX material that gets inserted after \input webmac +@i tie.preamble + +@* Introduction. + +\noindent Whenever a programmer wants to change a given +\.{WEB} program because of system dependencies, he will +create a new change file. In addition there may be a second +change file to modify system independent modules of the +program. But the \.{WEB} file cannot be tangled and weaved +with more than one change file simultaneously. Therefore, +we introduce the present program to merge a \.{WEB} file and +several change files producing a new \.{WEB} file. Since +the input files are tied together, the program is called +\.{TIE}. Furthermore, the program can be used to merge +several change files giving a new single change file. This +method seems to be more important because it doesn't modify +the original source file. The use of \.{TIE} can be +expanded to other programming languages since this processor +only knows about the structure of change files and does not +interpret the master file at all. + +The program \.{TIE} has to read lines from several input +files to bring them in some special ordering. For this +purpose an algorithm is used which looks a little bit +complicated. But the method used only needs one buffer line +for each input file. Thus the storage requirement of +\.{TIE} does not depend on the input data. + +The program uses only few features of the local \PASCAL\ +compiler that may need to be changed in other installations. +The changes needed may be similar to those used to change +the \.{WEB} processors \.{TANGLE} and \.{WEAVE}. All places +where changes may be needed are listed in the index under +the entry ``system dependencies''. +@!@^system dependencies@> + +This version of \.{TIE} has been ported from a \PASCAL version +{$\copyright$}1983, 1984, 1986 by Technische Hochschule Darmstadt, +Fachbereich Informatik, Institut f\"ur Theoretische Informatik. +No attempt has been made to take advantage of the many nice features +of C (for example to remove the restriction on the number of change +files). +There is no warranty, express or implied. + +The ``banner line'' defined here should be changed whenever +\.{TIE} is modified. This program is put into the public +domain. Nevertheless the copyright notice must not be +replaced or modified. + + + +@d banner = "This is TIE, C Version 0.1 (ported to C)" + +@ Here is where \.{TIE} starts, and where it ends. +If a command line interface is present, changes to +initialize the access might be needed here. +@^system dependencies@> +@^command line processing@> + +@c +#include <stdio.h> +@<Input and output types@>@; +@<Types in the outer block@>@; +@<Globals in the outer block@>@; +@<Error handling procedures@>@; +@# +main (argc, argv) + int argc; + char **argv; +{ + int i,j; + + @<Set initial values@>@; + if (verbose) + print_ln(banner); /* print a ``banner line'' */ + @<Read the arguments, setting the master file, the change files, + and any options@>; + @<Initialize the input system@>; + @<Process the input@>; + @<Check that all changes have been read@>; + /* here files should be closed if the operating system requires it */ + @<Print the job |history| if |verbose| is appropriate@> + jump_out(); +} + +@ The guts of the program are simple: we drag each line through the mud: +@<Process the input@>= +input_has_ended=false; +while (!input_has_ended || (actual_input!=0)) process_line(); +if (out_mode == post) /* last line has been changed */ + write_string(out_file,"@@z\n"); +@<Write carriage return for end of counts@>; + + +@ At the end of the program, we will tell the user if a +change file had a line that didn't match any relevant line +in the master file. + +@<Check that all changes have been read@>= +for (i=1; i<next_available_file; i++) /* all change files */ + if (input_organization[i].mode != ignore) + err_print("! Change file entry did not match",i); +@.Change file entry ...@> + +@ Here are some macros for common programming idioms. + +@d loop = while (true) +@d do_nothing = /* empty statement */ +@f loop while + + +@ The following parameters should be sufficient for most +applications of \.{TIE}. Note that |max_file_index| should +not be enlarged without changing the processing of change +file names. +@^system dependencies@> + +@d buf_size = 100 /* maximum length of one input line*/ +@d max_file_index = 9/* we dont think that anyone needs more than 9 change files*/ +@d max_name_length = 54 /* adapt this to your local name space*/ + + +@* Handling multiple change files. +We read the master and change files from the argument vector. +The master file is first, followed by (eventually any number) up to 9 +change files. +The only options are |"-m"| to produce a master file, and |"-c"| to +produce a change file. +The last one wins. + +@<Read the arguments...@>= +while (--argc>0) { + if (**++argv=='-') + switch (*++*argv) { + case 'm': + prod_chf=false; + break; + case 'c': + prod_chf=true; + break; + case 'v': + verbose++; + break; + default: + fprintf(stderr, "Bad option -%c ignored\n", + **argv); + break; + } + else { + if (next_available_file > max_file_index) + fatal_error("too many files"); + input_organization[next_available_file++].name_of_file=*argv; + } +} + + +@ |next_available_file| tells us what file numebr is available as +a change file. +@<Globals...@>= +int next_available_file=0; +@i datadecl.web + + + + +@*Routines that test input/output conditions. + +\noindent Here's a simple function that checks if two lines +are different. + +@c +boolean lines_dont_match(i,j) + int i,j; +{ + buffer_index k, lmt; + if (input_organization[i].limit != input_organization[j].limit) + return true; + lmt=input_organization[i].limit; + for (k=0; k<lmt; k++) + if (input_organization[i].buffer[k] != input_organization[j].buffer[k]) + return true; + return false; +} +@ @<Globals...@>=boolean lines_dont_match(); +@ The function |e_of_ch_module| returns true if the input +line from file |i| is equal to \.{@@z}. + +@c +boolean e_of_ch_module(i) + int i; +{ + return ((input_organization[i].limit>=2) && + (input_organization[i].buffer[0]=='@@') && + ((input_organization[i].buffer[1]=='Z') || + (input_organization[i].buffer[1]=='z'))); +} + +@ @<Globals...@>=boolean e_of_ch_module(); + +@ The function |e_of_ch_preamble| returns true if the input +line from file |i| is equal to \.{@@y}. + +@c +boolean e_of_ch_preamble(i) + int i; +{ + return ((input_organization[i].limit>=2) && + (input_organization[i].buffer[0]=='@@') && + ((input_organization[i].buffer[1]=='Y') || + (input_organization[i].buffer[1]=='y'))); +} + +@ @<Globals...@>=boolean e_of_ch_module(); + +@*Routines that manipulate input and output. + +@ We continue with a function to open a text file. Success +is indicated by a boolean result. We assume that empty +files can be handled like non existent ones. +@^system dependencies@> + +@c +boolean file_open(f,name) + text_file *f; + name_type name; +{ + return ((*f=fopen(name,"r"))!=NULL); +} + +@ @<Globals...@>=boolean file_open(); + +@ This procedure opens all the input files. + +@c +@<Procedures for |open_input|@>@;@% + open_input() /* prepare to read |input_files| */ +{ +int i; + @<Get the master file started@>; + actual_input=0; +no_ch=0; +while (++no_ch<next_available_file) { + if (!file_open(&(input_files[no_ch]),input_organization[no_ch].name_of_file)) { + fatal_error("! Change file can\'t be opened"); + } +@.Change file can't be opened@> + else { + if (verbose) { + print("("); + print_name_of_file(no_ch); + print_ln(")"); + } + init_change_file(no_ch,true); + } +} + + if (--no_ch==0) + fatal_error("! No change file found"); +@.No change file found@> + for (i=next_available_file; i<=max_file_index; i++) + input_organization[i].mode=ignore; +} + +@ The master file is actually started just like the change files. +@<Get the master file started@>= + if (!file_open(&(input_files[0]),input_organization[0].name_of_file)) { + fatal_error("! Master file can\'t be opened"); + } +@.Master file can't be opened@> + else { + if (verbose) { + print("("); + print_name_of_file(0); + print_ln(")"); + } + input_organization[0].type_of_file = master; + get_line(0); +} + + +@ The main output goes to |out_file|. +@d out_file = stdout + + +@ Procedure |init_change_file(i,b)| is used to ignore all +lines of the input file with index |i| until the next change +module is found. The boolean parameter |b| indicates +whether we do not want to see "@@x" or "@@y" entries during +our skip. + +@<Procedures for |open_input|@>= + init_change_file(i,b) + int i; + boolean b; +{ + @<Skip over comment lines; |return| if end of file@>; + @<Skip to the next nonblank line; |return| if end of file@>; +} + + +@ 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} or \.{@@z} (which would +probably indicate that the change file is fouled up). + +@<Skip over comment lines...@>= +loop { + get_line(i); + if (input_organization[i].mode==ignore) return; + if (input_organization[i].limit<2) continue; + if (input_organization[i].buffer[0] != '@@') continue; + if ((input_organization[i].buffer[1]>='X') + && (input_organization[i].buffer[1]<='Z')) + input_organization[i].buffer[1] += 'z'-'Z'; /* lowercasify */ + if (input_organization[i].buffer[1]=='x') break; + if ((input_organization[i].buffer[1]=='y') || + (input_organization[i].buffer[1]=='z')) + if (b) /* waiting for start of change */ + err_print("! Where is the matching @@x?",i); +@.Where is the match...@> +} + + + +@ Here we are looking at lines following the \.{@@x}. + +@<Skip to the next nonblank line...@>= +do { + get_line(i); + if (input_organization[i].mode==ignore) { + err_print("! Change file ended after @@x",i); +@.Change file ended...@> + return; + } +} while (input_organization[i].limit<=0); + + +@ The |put_line| procedure is used to write a line from +input buffer |j| to the output file. + +@c + put_line(j) + int j; +{ + int i; /* index into the buffer */ + for (i=0; i<input_organization[j].limit; i++) + fputc(xchr[input_organization[j].buffer[i]],out_file); + fputc('\n',out_file); +} + +@ Writing strings to the output +@c +write_string(fp, s) + text_file fp; + char *s; +{ + while (*s != '\0') { + putc(*s,fp);s++;} +} + + + + +@ To start with our inputs we set the indication that all +change files are in state |search|. That means that we must +skip to the next (in this case the first) change entry. + +@<Initialize the input system@>= +common_init(); +for (i=0; i<next_available_file; i++) { + input_organization[i].mode=search; + input_organization[i].lineno=0; + input_organization[i].type_of_file=chf; + input_organization[i].limit=0; + for (j=0 ; j<= buf_size; j++) input_organization[i].buffer[j]=0; + } +actual_input=0; +out_mode=normal; + open_input(); + + +@*The major line-eating routines. +@ To process the input file the procedure |process_line| +reads a line of the actual input file and updates the +|input_organization| for all files with index |i| greater +|actual_input|. + +@c +process_line() +{ + int i; + @<Count lines processed, and shout at each hundred@>; + @<Set |actual_input| and |test_input|, and set their modes@>; + @<Write one (decorated) line of output, and set output mode@>; + @<Read lines from |actual_input| + (and |test_input| if necessary, checking for preamble end)@>; +} + + +@ If |test_input| is |none|, no change file is tested. + +@d none = (next_available_file) + +@<Set |actual_input| and |test_input|, and set their modes@>= +while (e_of_ch_module(actual_input)) { + if (input_organization[actual_input].type_of_file==master) + /* emergency exit, everything mixed up! */ + fatal_error("! This can\'t happen"); + input_organization[actual_input].mode=search; + init_change_file(actual_input,true); + while ((input_organization[actual_input].mode!=reading) + && (actual_input>0)) actual_input--; +} +if (input_has_ended && (actual_input==0)) return; +test_input=none; +i=actual_input; +while ((test_input==none) && (i<no_ch)) { + i++; + switch (input_organization[i].mode) { +case search: if (!lines_dont_match(actual_input,i)) { + input_organization[i].mode=test; + test_input=i; + } + break; +case test: + if (lines_dont_match(actual_input, i)) + { + /* error, modules do not match */ + input_organization[i].mode=search; + err_print("! Sections do not match",actual_input); +@.Sections do not match@> + err_loc(i); + init_change_file(i,false); + } + else test_input=i; + break; +case reading:do_nothing; /* this can't happen */ + break; +case ignore: do_nothing; /* nothing to do */ + break; +} +} + + +@ @<Write one (decorated) line of output, and set output mode@>= +if (prod_chf) { + loop { + @<Test for normal@>; + @<Test for pre@>; + @<Test for post@>; +} +} else +if (test_input==none) put_line(actual_input); + + +@ Check whether we have to start a change file entry. + +@<Test for normal@>= +{ + if (out_mode==normal) + if (test_input!=none) { + write_string(out_file,"@@x\n"); + out_mode=pre; + } + else break; +} + + +@ Check whether we have to start the replacement text. + +@<Test for pre@>= +{ + if (out_mode==pre) { + if (test_input==none) { + write_string(out_file,"@@y\n"); + out_mode=post; + } else { + if (input_organization[actual_input].type_of_file==master) + put_line(actual_input); + break; + } + } +} + + +@ Check whether a change file entry is complete. + +@<Test for post@>= +{ + if (out_mode==post) { + if (input_organization[actual_input].type_of_file==chf) { + if (test_input==none) put_line(actual_input); + break; + } else { + write_string(out_file,"@@z\n"); + out_mode=normal; + } + } +} + + +@ @<Read lines from |actual_input| (and |test_input| if necessary, checking for preamble end)@>= +get_line(actual_input); +if (test_input!=none) { + get_line(test_input); + if (e_of_ch_preamble(test_input)) { + get_line(test_input); /* update input file */ + input_organization[test_input].mode=reading; + actual_input=test_input; + test_input=none; + } +} + +@ We shout at the user about lines processed... +@<Count lines proc...@>= +if (++lines_processed % 100 == 0 && verbose) { + if (lines_processed % 500 == 0) + fprintf(stderr,"%d",lines_processed); + else + fprintf(stderr,"."); + } + +@ @<Globals in...@>=long int lines_processed=0; +@ @<Write carriage return...@>=if (verbose) fprintf(stderr,"\n"); + + +@i io.web +@i history.web +@i error.web +@i character.web + +@* System-dependent changes. + +\noindent This section should be replaced, if necessary, by +changes to the program that are necessary to make \.{TIE} +work at a particular installation. It is usually best to +design your change file so that all changes to previous +modules preserve the module numbering; then everybody's +version will be consistent with the printed program. More +extensive changes, which introduce new modules, can be +inserted here; then only the index itself will get a new +module number. +@^system dependencies@> + +@<System-dependent parts of char...@>= +xchr['\t']='\t'; + + +@* Index. + +\noindent Here is the cross-reference table for the \.{TIE} +processor. diff --git a/web/spiderweb/tools/tie/tie.web,v b/web/spiderweb/tools/tie/tie.web,v new file mode 100644 index 0000000000..8794b356a1 --- /dev/null +++ b/web/spiderweb/tools/tie/tie.web,v @@ -0,0 +1,576 @@ +head 1.1; +branch ; +access ; +symbols ; +locks nr:1.1; strict; +comment @@; + + +1.1 +date 92.07.06.18.51.25; author nr; state Exp; +branches ; +next ; + + +desc +@tie program +@ + + + +1.1 +log +@Initial revision +@ +text +@% This is TIE.WEB +%------------------------------------------------------------ + +% Version 0.1 ported from PASCAL (NR) 24 August 87 + +% Here is TeX material that gets inserted after \input webmac +@@i tie.preamble + +@@* Introduction. + +\noindent Whenever a programmer wants to change a given +\.{WEB} program because of system dependencies, he will +create a new change file. In addition there may be a second +change file to modify system independent modules of the +program. But the \.{WEB} file cannot be tangled and weaved +with more than one change file simultaneously. Therefore, +we introduce the present program to merge a \.{WEB} file and +several change files producing a new \.{WEB} file. Since +the input files are tied together, the program is called +\.{TIE}. Furthermore, the program can be used to merge +several change files giving a new single change file. This +method seems to be more important because it doesn't modify +the original source file. The use of \.{TIE} can be +expanded to other programming languages since this processor +only knows about the structure of change files and does not +interpret the master file at all. + +The program \.{TIE} has to read lines from several input +files to bring them in some special ordering. For this +purpose an algorithm is used which looks a little bit +complicated. But the method used only needs one buffer line +for each input file. Thus the storage requirement of +\.{TIE} does not depend on the input data. + +The program uses only few features of the local \PASCAL\ +compiler that may need to be changed in other installations. +The changes needed may be similar to those used to change +the \.{WEB} processors \.{TANGLE} and \.{WEAVE}. All places +where changes may be needed are listed in the index under +the entry ``system dependencies''. +@@!@@^system dependencies@@> + +This version of \.{TIE} has been ported from a \PASCAL version +{$\copyright$}1983, 1984, 1986 by Technische Hochschule Darmstadt, +Fachbereich Informatik, Institut f\"ur Theoretische Informatik. +No attempt has been made to take advantage of the many nice features +of C (for example to remove the restriction on the number of change +files). +There is no warranty, express or implied. + +The ``banner line'' defined here should be changed whenever +\.{TIE} is modified. This program is put into the public +domain. Nevertheless the copyright notice must not be +replaced or modified. + + + +@@d banner = "This is TIE, C Version 0.1 (ported to C)" + +@@ Here is where \.{TIE} starts, and where it ends. +If a command line interface is present, changes to +initialize the access might be needed here. +@@^system dependencies@@> +@@^command line processing@@> + +@@c +#include <stdio.h> +@@<Input and output types@@>@@; +@@<Types in the outer block@@>@@; +@@<Globals in the outer block@@>@@; +@@<Error handling procedures@@>@@; +@@# +main (argc, argv) + int argc; + char **argv; +{ + int i,j; + + @@<Set initial values@@>@@; + print_ln(banner); /* print a ``banner line'' */ + @@<Read the arguments, setting the master file, the change files, + and any options@@>; + @@<Initialize the input system@@>; + @@<Process the input@@>; + @@<Check that all changes have been read@@>; + /* here files should be closed if the operating system requires it */ + @@<Print the job |history|@@>; + jump_out(); +} + +@@ The guts of the program are simple: we drag each line through the mud: +@@<Process the input@@>= +input_has_ended=false; +while (!input_has_ended || (actual_input!=0)) process_line(); +if (out_mode == post) /* last line has been changed */ + write_string(out_file,"@@@@z\n"); +@@<Write carriage return for end of counts@@>; + + +@@ At the end of the program, we will tell the user if a +change file had a line that didn't match any relevant line +in the master file. + +@@<Check that all changes have been read@@>= +for (i=1; i<next_available_file; i++) /* all change files */ + if (input_organization[i].mode != ignore) + err_print("! Change file entry did not match",i); +@@.Change file entry ...@@> + +@@ Here are some macros for common programming idioms. + +@@d loop = while (true) +@@d do_nothing = /* empty statement */ +@@f loop while + + +@@ The following parameters should be sufficient for most +applications of \.{TIE}. Note that |max_file_index| should +not be enlarged without changing the processing of change +file names. +@@^system dependencies@@> + +@@d buf_size = 100 /* maximum length of one input line*/ +@@d max_file_index = 9/* we dont think that anyone needs more than 9 change files*/ +@@d max_name_length = 54 /* adapt this to your local name space*/ + + +@@* Handling multiple change files. +We read the master and change files from the argument vector. +The master file is first, followed by (eventually any number) up to 9 +change files. +The only options are |"-m"| to produce a master file, and |"-c"| to +produce a change file. +The last one wins. + +@@<Read the arguments...@@>= +while (--argc>0) { + if (**++argv=='-') + switch (*++*argv) { + case 'm': + prod_chf=false; + break; + case 'c': + prod_chf=true; + break; + default: + fprintf(stderr, "Bad option -%c ignored\n", + **argv); + break; + } + else { + if (next_available_file > max_file_index) + fatal_error("too many files"); + input_organization[next_available_file++].name_of_file=*argv; + } + } + + +@@ |next_available_file| tells us what file numebr is available as +a change file. +@@<Globals...@@>= +int next_available_file=0; +@@i datadecl.web + + + + +@@*Routines that test input/output conditions. + +\noindent Here's a simple function that checks if two lines +are different. + +@@c +boolean lines_dont_match(i,j) + int i,j; +{ + buffer_index k, lmt; + if (input_organization[i].limit != input_organization[j].limit) + return true; + lmt=input_organization[i].limit; + for (k=0; k<lmt; k++) + if (input_organization[i].buffer[k] != input_organization[j].buffer[k]) + return true; + return false; +} +@@ @@<Globals...@@>=boolean lines_dont_match(); +@@ The function |e_of_ch_module| returns true if the input +line from file |i| is equal to \.{@@@@z}. + +@@c +boolean e_of_ch_module(i) + int i; +{ + return ((input_organization[i].limit>=2) && + (input_organization[i].buffer[0]=='@@@@') && + ((input_organization[i].buffer[1]=='Z') || + (input_organization[i].buffer[1]=='z'))); +} + +@@ @@<Globals...@@>=boolean e_of_ch_module(); + +@@ The function |e_of_ch_preamble| returns true if the input +line from file |i| is equal to \.{@@@@y}. + +@@c +boolean e_of_ch_preamble(i) + int i; +{ + return ((input_organization[i].limit>=2) && + (input_organization[i].buffer[0]=='@@@@') && + ((input_organization[i].buffer[1]=='Y') || + (input_organization[i].buffer[1]=='y'))); +} + +@@ @@<Globals...@@>=boolean e_of_ch_module(); + +@@*Routines that manipulate input and output. + +@@ We continue with a function to open a text file. Success +is indicated by a boolean result. We assume that empty +files can be handled like non existent ones. +@@^system dependencies@@> + +@@c +boolean file_open(f,name) + text_file *f; + name_type name; +{ + return ((*f=fopen(name,"r"))!=NULL); +} + +@@ @@<Globals...@@>=boolean file_open(); + +@@ This procedure opens all the input files. + +@@c +@@<Procedures for |open_input|@@>@@;@@% + open_input() /* prepare to read |input_files| */ +{ +int i; + @@<Get the master file started@@>; + actual_input=0; +no_ch=0; +while (++no_ch<next_available_file) { + if (!file_open(&(input_files[no_ch]),input_organization[no_ch].name_of_file)) { + fatal_error("! Change file can\'t be opened"); + } +@@.Change file can't be opened@@> + else { + print("("); + print_name_of_file(no_ch); + print_ln(")"); + init_change_file(no_ch,true); + } +} + + if (--no_ch==0) + fatal_error("! No change file found"); +@@.No change file found@@> + for (i=next_available_file; i<=max_file_index; i++) + input_organization[i].mode=ignore; +} + +@@ The master file is actually started just like the change files. +@@<Get the master file started@@>= + if (!file_open(&(input_files[0]),input_organization[0].name_of_file)) { + fatal_error("! Master file can\'t be opened"); + } +@@.Master file can't be opened@@> + else { + print("("); + print_name_of_file(0); + print_ln(")"); + input_organization[0].type_of_file = master; + get_line(0); +} + + +@@ The main output goes to |out_file|. +@@d out_file = stdout + + +@@ Procedure |init_change_file(i,b)| is used to ignore all +lines of the input file with index |i| until the next change +module is found. The boolean parameter |b| indicates +whether we do not want to see "@@@@x" or "@@@@y" entries during +our skip. + +@@<Procedures for |open_input|@@>= + init_change_file(i,b) + int i; + boolean b; +{ + @@<Skip over comment lines; |return| if end of file@@>; + @@<Skip to the next nonblank line; |return| if end of file@@>; +} + + +@@ 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} or \.{@@@@z} (which would +probably indicate that the change file is fouled up). + +@@<Skip over comment lines...@@>= +loop { + get_line(i); + if (input_organization[i].mode==ignore) return; + if (input_organization[i].limit<2) continue; + if (input_organization[i].buffer[0] != '@@@@') continue; + if ((input_organization[i].buffer[1]>='X') + && (input_organization[i].buffer[1]<='Z')) + input_organization[i].buffer[1] += 'z'-'Z'; /* lowercasify */ + if (input_organization[i].buffer[1]=='x') break; + if ((input_organization[i].buffer[1]=='y') || + (input_organization[i].buffer[1]=='z')) + if (b) /* waiting for start of change */ + err_print("! Where is the matching @@@@x?",i); +@@.Where is the match...@@> +} + + + +@@ Here we are looking at lines following the \.{@@@@x}. + +@@<Skip to the next nonblank line...@@>= +do { + get_line(i); + if (input_organization[i].mode==ignore) { + err_print("! Change file ended after @@@@x",i); +@@.Change file ended...@@> + return; + } +} while (input_organization[i].limit<=0); + + +@@ The |put_line| procedure is used to write a line from +input buffer |j| to the output file. + +@@c + put_line(j) + int j; +{ + int i; /* index into the buffer */ + for (i=0; i<input_organization[j].limit; i++) + fputc(xchr[input_organization[j].buffer[i]],out_file); + fputc('\n',out_file); +} + +@@ Writing strings to the output +@@c +write_string(fp, s) + text_file fp; + char *s; +{ + while (*s != '\0') { + putc(*s,fp);s++;} +} + + + + +@@ To start with our inputs we set the indication that all +change files are in state |search|. That means that we must +skip to the next (in this case the first) change entry. + +@@<Initialize the input system@@>= +common_init(); +for (i=0; i<next_available_file; i++) { + input_organization[i].mode=search; + input_organization[i].lineno=0; + input_organization[i].type_of_file=chf; + input_organization[i].limit=0; + for (j=0 ; j<= buf_size; j++) input_organization[i].buffer[j]=0; + } +actual_input=0; +out_mode=normal; + open_input(); + + +@@*The major line-eating routines. +@@ To process the input file the procedure |process_line| +reads a line of the actual input file and updates the +|input_organization| for all files with index |i| greater +|actual_input|. + +@@c +process_line() +{ + int i; + @@<Count lines processed, and shout at each hundred@@>; + @@<Set |actual_input| and |test_input|, and set their modes@@>; + @@<Write one (decorated) line of output, and set output mode@@>; + @@<Read lines from |actual_input| + (and |test_input| if necessary, checking for preamble end)@@>; +} + + +@@ If |test_input| is |none|, no change file is tested. + +@@d none = (next_available_file) + +@@<Set |actual_input| and |test_input|, and set their modes@@>= +while (e_of_ch_module(actual_input)) { + if (input_organization[actual_input].type_of_file==master) + /* emergency exit, everything mixed up! */ + fatal_error("! This can\'t happen"); + input_organization[actual_input].mode=search; + init_change_file(actual_input,true); + while ((input_organization[actual_input].mode!=reading) + && (actual_input>0)) actual_input--; +} +if (input_has_ended && (actual_input==0)) return; +test_input=none; +i=actual_input; +while ((test_input==none) && (i<no_ch)) { + i++; + switch (input_organization[i].mode) { +case search: if (!lines_dont_match(actual_input,i)) { + input_organization[i].mode=test; + test_input=i; + } + break; +case test: + if (lines_dont_match(actual_input, i)) + { + /* error, modules do not match */ + input_organization[i].mode=search; + err_print("! Sections do not match",actual_input); +@@.Sections do not match@@> + err_loc(i); + init_change_file(i,false); + } + else test_input=i; + break; +case reading:do_nothing; /* this can't happen */ + break; +case ignore: do_nothing; /* nothing to do */ + break; +} +} + + +@@ @@<Write one (decorated) line of output, and set output mode@@>= +if (prod_chf) { + loop { + @@<Test for normal@@>; + @@<Test for pre@@>; + @@<Test for post@@>; +} +} else +if (test_input==none) put_line(actual_input); + + +@@ Check whether we have to start a change file entry. + +@@<Test for normal@@>= +{ + if (out_mode==normal) + if (test_input!=none) { + write_string(out_file,"@@@@x\n"); + out_mode=pre; + } + else break; +} + + +@@ Check whether we have to start the replacement text. + +@@<Test for pre@@>= +{ + if (out_mode==pre) { + if (test_input==none) { + write_string(out_file,"@@@@y\n"); + out_mode=post; + } else { + if (input_organization[actual_input].type_of_file==master) + put_line(actual_input); + break; + } + } +} + + +@@ Check whether a change file entry is complete. + +@@<Test for post@@>= +{ + if (out_mode==post) { + if (input_organization[actual_input].type_of_file==chf) { + if (test_input==none) put_line(actual_input); + break; + } else { + write_string(out_file,"@@@@z\n"); + out_mode=normal; + } + } +} + + +@@ @@<Read lines from |actual_input| (and |test_input| if necessary, checking for preamble end)@@>= +get_line(actual_input); +if (test_input!=none) { + get_line(test_input); + if (e_of_ch_preamble(test_input)) { + get_line(test_input); /* update input file */ + input_organization[test_input].mode=reading; + actual_input=test_input; + test_input=none; + } +} + +@@ We shout at the user about lines processed... +@@<Count lines proc...@@>= +if (++lines_processed % 100 == 0) { + if (lines_processed % 500 == 0) + fprintf(stderr,"%d",lines_processed); + else + fprintf(stderr,"."); + } + +@@ @@<Globals in...@@>=long int lines_processed=0; +@@ @@<Write carriage return...@@>=fprintf(stderr,"\n"); + + +@@i io.web +@@i history.web +@@i error.web +@@i character.web + +@@* System-dependent changes. + +\noindent This section should be replaced, if necessary, by +changes to the program that are necessary to make \.{TIE} +work at a particular installation. It is usually best to +design your change file so that all changes to previous +modules preserve the module numbering; then everybody's +version will be consistent with the printed program. More +extensive changes, which introduce new modules, can be +inserted here; then only the index itself will get a new +module number. +@@^system dependencies@@> + +@@<System-dependent parts of char...@@>= +xchr['\t']='\t'; + + +@@* Index. + +\noindent Here is the cross-reference table for the \.{TIE} +processor. +@ diff --git a/web/spiderweb/tools/tie/tie.web.dist b/web/spiderweb/tools/tie/tie.web.dist new file mode 100644 index 0000000000..07cc03db1d --- /dev/null +++ b/web/spiderweb/tools/tie/tie.web.dist @@ -0,0 +1,1336 @@ +% This is TIE.WEB in text format, as of December 30, 1986. +%------------------------------------------------------------ + +% +% Version 1.0 was completed Nov 30, 1983. +% Version 1.1 was released Mar 19, 1984. +% Version 1.2 was restructured for release. (kg) (86-12-22) +% Version 1.3 allowed to change the last line, +% made none a constant, +% read empty lines correct, +% edited system dependent parts. (js) (86-12-30) +% + +% Here is TeX material that gets inserted after \input webmac + +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\mc=cmcsc10 +\def\PASCAL{{\mc Pascal}} +\def\ASCII{{\mc ascii}} +\def\pb{$\.|\ldots\.|$} % pascal brackets (|...|) +\def\v{\.{\char'174}} % vertical (|) in typewriter font +\mathchardef\BA="3224 % double arrow +\def\({} % kludge for alphabetizing certain module names + +\def\title{TIE} +\def\topofcontents{\null\vfill + \centerline{\titlefont The {\ttitlefont TIE} processor} + \vskip 15pt + \centerline{(Version 1.3)} + \vfill} +\def\botofcontents{ +\null\vfill +\item{$\copyright$}1983, 1984, 1986 + by Technische Hochschule Darmstadt,\hfill\break +Fachbereich Informatik, Institut f\"ur Theoretische Informatik\hfill\break +All rights reserved.\hfill\break +This program is put into the public domain and may be used freely +for any non commercial purposes. +} + + + + + +@* Introduction. + +\noindent Whenever a programmer wants to change a given +\.{WEB} program because of system dependencies, he will +create a new change file. In addition there may be a second +change file to modify system independent modules of the +program. But the \.{WEB} file cannot be tangled and weaved +with more than one change file simultaneously. Therefore, +we introduce the present program to merge a \.{WEB} file and +several change files producing a new \.{WEB} file. Since +the input files are tied together, the program is called +\.{TIE}. Furthermore, the program can be used to merge +several change files giving a new single change file. This +method seems to be more important because it doesn't modify +the original source file. The use of \.{TIE} can be +expanded to other programming languages since this processor +only knows about the structure of change files and does not +interpret the master file at all. + +The program \.{TIE} has to read lines from several input +files to bring them in some special ordering. For this +purpose an algorithm is used which looks a little bit +complicated. But the method used only needs one buffer line +for each input file. Thus the storage requirement of +\.{TIE} does not depend on the input data. + +The program uses only few features of the local \PASCAL\ +compiler that may need to be changed in other installations. +The changes needed may be similar to those used to change +the \.{WEB} processors \.{TANGLE} and \.{WEAVE}. All places +where changes may be needed are listed in the index under +the entry ``system dependencies''. +@!@^system dependencies@> + +The ``banner line'' defined here should be changed whenever +\.{TIE} is modified. This program is put into the public +domain. Nevertheless the copyright notice must not be +replaced or modified. + +@d banner=='This is TIE, Version 1.3' +@d copyright== + 'Copyright (c) 1983, 1984, 1986 by THD/ITI. All rights reserved.' + + +@ If it is necessary to abort the job because of a fatal +error, the program calls the `|jump_out|' procedure, which +goes to the label |end_of_TIE|. + +@d end_of_TIE = 9999 {go here to wrap it up} + +@p @t\4@>@<Compiler directives@> +program TIE(out_file); + label end_of_TIE; {go here to finish} + const @<Constants in the outer block@>@; + type @<Types in the outer block@>@; + var @<Globals in the outer block@>@; + @t\4@>@<Error handling procedures@>@; + procedure initialize; + var @<Local variables for initialization@>@; + begin @<Set initial values@> + end; + +@ Some of this code ist optional for use when debugging +only; such material is enclosed between the delimiters +|debug| and |gubed|. + +@d debug==@t@>@{ {change this to `|debug==@t@>|' when debugging} +@d gubed==@t@>@} {change this to `|gubed==@t@>|' when debugging} +@f debug==repeat +@f gubed==until + + +@ The \PASCAL\ compiler used to develop this system has +``compiler directives'' that can appear in comments whose +first character is a dollar sign. In production versions of +\.{TIE} these directives tell the compiler that it is safe +to avoid range checks and to leave out the extra code it +inserts for the \PASCAL\ debugger's benefit, although +interrupts will occur if there is arithmetic overflow. +@^system dependencies@> + +@<Compiler directives@>= +@{@&@=$D-@> @} {no range check, catch arithmetic overflow, no debug overhead} +@!debug @{@&@=$D+@> @}@+ gubed @; {but turn everything on when debugging} + + +@ Labels are given symbolic names by the following +definitions. We insert the label `|exit|:' just before the +`\ignorespaces|end|\unskip' of a procedure in which we have +used the `|return|' statement defined below. Loops that are +set up with the \&{loop} construction defined below are +commonly exited by going to `|done|' or to `|found|' or to +`|not_found|', and they are sometimes repeated by going to +`|continue|'. + +@d exit=10 {go here to leave a procedure} +@d continue=20 {go here to resume a loop} +@d done=30 {go here to exit a loop} +@d found=31 {go here when you've found it} +@d not_found=32 {go here when you've found something else} + + +@ Here are some macros for common programming idioms. + +@d incr(#) == #:=#+1 {increase a variable by unity} +@d decr(#) == #:=#-1 {decrease a variable by unity} +@d loop == @+ while true do@+ {repeat over and over until a |goto| happens} +@d do_nothing == {empty statement} +@d return == goto exit {terminate a procedure call} +@f return == nil +@f loop == xclause + + +@ We assume that |case| statements may include a default +case that applies if no matching label is found. Thus, we +shall use constructions like +$$ +\vbox{ + \halign{#\hfil\cr + |case x of|\cr + \qquad 1: $\langle\,$code for $x=1\,\rangle$;\cr + \qquad 3: $\langle\,$code for $x=3\,\rangle$;\cr + \qquad |othercases| $\langle\,$code for |x<>1| and |x<>3|$\,\rangle$\cr + |endcases|\cr + }} +$$ +since most \PASCAL\ compilers have plugged this hole in the +language by incorporating some sort of default mechanism. +For example, the compiler used to develop \.{WEB} and \TeX\ +allows `|others|:' as a default label, and other \PASCAL s +allow syntaxes like `\ignorespaces|else|\unskip' or +`\&{otherwise}' or `\\{otherwise}:', etc. The definitions +of |othercases| and |endcases| should be changed to agree +with local conventions. (Of course, if no default mechanism +is available, the |case| statements of this program must be +extended by listing all remaining cases.) +@^system dependencies@> + +@d othercases == others: {default for cases not listed explicitly} +@d endcases == @+end {follows the default case in an extended |case| statement} +@f othercases == else +@f endcases == end + + +@ The following parameters should be sufficient for most +applications of \.{TIE}. Note that |max_file_index| should +not be enlarged without changing the processing of change +file names. +@^system dependencies@> + +@<Constants...@>= +@!buf_size=100; {maximum length of one input line} +@!max_file_index=9;{we dont think that anyone needs more than 9 change files} +@!max_name_length=54; {adapt this to your local name space} + + +@ We introduce a history variable that allows us to set a +return code if the operating system and the local \PASCAL\ +compiler allow it. First we introduce the coded values for +the history. + +@d spotless=0 +@d troublesome=1 +@d fatal=2 + +@<Globals in ...@>= +@!history:integer; + + +@ We must initialize this variable at the very beginning. + +@<Set initial values@>= +history:=spotless; + + + + + +@* The character set. + +\noindent One of the main goals in the design of \.{TIE} has +been to make it readily portable between a wide variety of +computers. Yet \.{TIE} by its very nature must use a +greater variety of characters than most computer programs +deal with, and character encoding is one of the areas in +which existing machines differ most widely from each other. + +To resolve this problem, all input to \.{TIE} is converted +to an internal seven-bit code that is essentially standard +\ASCII{}, the ``American Standard Code for Information +Interchange.'' The conversion is done immediately when each +character is read in. Conversely, characters are converted +from \ASCII{} to the user's external representation just +before they are output. + +\noindent Here is a table of the standard visible \ASCII{} codes: +$$\def\:{\char\count255\global\advance\count255 by 1} +\count255='40 +\vbox{ +\hbox{\hbox to 40pt{\it\hfill0\/\hfill}% +\hbox to 40pt{\it\hfill1\/\hfill}% +\hbox to 40pt{\it\hfill2\/\hfill}% +\hbox to 40pt{\it\hfill3\/\hfill}% +\hbox to 40pt{\it\hfill4\/\hfill}% +\hbox to 40pt{\it\hfill5\/\hfill}% +\hbox to 40pt{\it\hfill6\/\hfill}% +\hbox to 40pt{\it\hfill7\/\hfill}} +\vskip 4pt +\hrule +\def\^{\vrule height 10.5pt depth 4.5pt} +\halign{\hbox to 0pt{\hskip -24pt\O{#0}\hfill}&\^ +\hbox to 40pt{\tt\hfill#\hfill\^}& +&\hbox to 40pt{\tt\hfill#\hfill\^}\cr +04&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +05&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +06&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +07&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +10&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +11&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +12&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +13&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +14&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +15&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +16&\:&\:&\:&\:&\:&\:&\:&\:\cr\noalign{\hrule} +17&\:&\:&\:&\:&\:&\:&\:\cr} +\hrule width 280pt}$$ +(Actually, of course, code @'040 is an invisible blank +space.) Code @'136 was once an upward arrow (\.{\char'13}), +and code @'137 was once a left arrow (\.^^X), in olden times +when the first draft of \ASCII{} code was prepared; but +\.{TIE} works with today's standard \ASCII{} in which those +codes represent circumflex and underline as shown. + +@<Types...@>= +@!ascii_code=0..127; {seven-bit numbers, a subrange of the integers} + + +@ The original \PASCAL\ compiler was designed in the late +60s, when six-bit character sets were common, so it did not +make provision for lowercase letters. Nowadays, of course, +we need to deal with both capital and small letters in a +convenient way, so \.{TIE} assumes that it is being used +with a \PASCAL\ whose character set contains at least the +characters of standard \ASCII{} as listed above. Some +\PASCAL\ compilers use the original name |char| for the data +type associated with the characters in text files, while +other \PASCAL s consider |char| to be a 64-element subrange +of a larger data type that has some other name. + +In order to accommodate this difference, we shall use the +name |text_char| to stand for the data type of the +characters in the input and output files. We shall also +assume that |text_char| consists of the elements +|chr(first_text_char)| through |chr(last_text_char)|, +inclusive. The following definitions should be adjusted if +necessary. +@^system dependencies@> + +@d text_char == char {the data type of characters in text files} +@d first_text_char=0 {ordinal number of the smallest element of |text_char|} +@d last_text_char=127 {ordinal number of the largest element of |text_char|} + +@<Types...@>= +@!text_file=packed file of text_char; + + +@ The \.{TIE} processor convert between \ASCII{} code and +the user's external character set by means of arrays |xord| +and |xchr| that are analogous to \PASCAL's |ord| and |chr| +functions. + +@<Globals...@>= +@!xord: array [text_char] of ascii_code; + {specifies conversion of input characters} +@!xchr: array [ascii_code] of text_char; + {specifies conversion of output characters} + + +@ If we assume that every system using \.{WEB} is able to +read and write the visible characters of standard \ASCII{} +(although not necessarily using the \ASCII{} codes to +represent them), the following assignment statements +initialize most of the |xchr| array properly, without +needing any system-dependent changes. For example, the +statement \.{xchr["A"]:=\'A\'} that appears in the present +\.{WEB} file might be encoded in, say, {\mc EBCDIC} code on +the external medium on which it resides, but \.{TANGLE} will +convert from this external code to \ASCII{} and back again. +Therefore the assignment statement \.{XCHR[65]:=\'A\'} will +appear in the corresponding \PASCAL\ file, and \PASCAL\ will +compile this statement so that |xchr[65]| receives the +character \.A in the external (|char|) code. Note that it +would be quite incorrect to say \.{xchr["A"]:="A"}, because +|"A"| is a constant of type |integer|, not |char|, and +because we have $|"A"|=65$ regardless of the external +character set. + +@<Set init...@>= +xchr[" "]:=' '; +xchr["!"]:='!'; +xchr[""""]:='"'; +xchr["#"]:='#'; +xchr["$"]:='$'; +xchr["%"]:='%'; +xchr["&"]:='&'; +xchr["'"]:='''';@/ +xchr["("]:='('; +xchr[")"]:=')'; +xchr["*"]:='*'; +xchr["+"]:='+'; +xchr[","]:=','; +xchr["-"]:='-'; +xchr["."]:='.'; +xchr["/"]:='/';@/ +xchr["0"]:='0'; +xchr["1"]:='1'; +xchr["2"]:='2'; +xchr["3"]:='3'; +xchr["4"]:='4'; +xchr["5"]:='5'; +xchr["6"]:='6'; +xchr["7"]:='7';@/ +xchr["8"]:='8'; +xchr["9"]:='9'; +xchr[":"]:=':'; +xchr[";"]:=';'; +xchr["<"]:='<'; +xchr["="]:='='; +xchr[">"]:='>'; +xchr["?"]:='?';@/ +xchr["@@"]:='@@'; +xchr["A"]:='A'; +xchr["B"]:='B'; +xchr["C"]:='C'; +xchr["D"]:='D'; +xchr["E"]:='E'; +xchr["F"]:='F'; +xchr["G"]:='G';@/ +xchr["H"]:='H'; +xchr["I"]:='I'; +xchr["J"]:='J'; +xchr["K"]:='K'; +xchr["L"]:='L'; +xchr["M"]:='M'; +xchr["N"]:='N'; +xchr["O"]:='O';@/ +xchr["P"]:='P'; +xchr["Q"]:='Q'; +xchr["R"]:='R'; +xchr["S"]:='S'; +xchr["T"]:='T'; +xchr["U"]:='U'; +xchr["V"]:='V'; +xchr["W"]:='W';@/ +xchr["X"]:='X'; +xchr["Y"]:='Y'; +xchr["Z"]:='Z'; +xchr["["]:='['; +xchr["\"]:='\'; +xchr["]"]:=']'; +xchr["^"]:='^'; +xchr["_"]:='_';@/ +xchr["`"]:='`'; +xchr["a"]:='a'; +xchr["b"]:='b'; +xchr["c"]:='c'; +xchr["d"]:='d'; +xchr["e"]:='e'; +xchr["f"]:='f'; +xchr["g"]:='g';@/ +xchr["h"]:='h'; +xchr["i"]:='i'; +xchr["j"]:='j'; +xchr["k"]:='k'; +xchr["l"]:='l'; +xchr["m"]:='m'; +xchr["n"]:='n'; +xchr["o"]:='o';@/ +xchr["p"]:='p'; +xchr["q"]:='q'; +xchr["r"]:='r'; +xchr["s"]:='s'; +xchr["t"]:='t'; +xchr["u"]:='u'; +xchr["v"]:='v'; +xchr["w"]:='w';@/ +xchr["x"]:='x'; +xchr["y"]:='y'; +xchr["z"]:='z'; +xchr["{"]:='{'; +xchr["|"]:='|'; +xchr["}"]:='}'; +xchr["~"]:='~';@/ +xchr[0]:=' '; xchr[@'177]:=' '; {these \ASCII{} codes are not used} + + +@ One of the \ASCII{} codes below @'40 has been given a +symbolic name in \.{TIE} because it is used with a special +meaning. + +@d tab_mark=@'11 {\ASCII{} code used as tab-skip} + + +@ When we initialize the |xord| array and the remaining +parts of |xchr|, it will be convenient to make use of an +index variable, |i|. + +@<Local variables for init...@>= +@!i:0..last_text_char; + + +@ Here now is the system-dependent part of the character +set. If \.{TIE} is being implemented on a garden-variety +\PASCAL\ for which only standard \ASCII{} codes will appear +in the input and output files, you don't need to make any +changes here. +@^system dependencies@> + +Changes to the present module will make \.{TIE} more +friendly on computers that have an extended character set, +so that one can type things like \.^^Z. If you have an +extended set of characters that are easily incorporated into +text files, you can assign codes arbitrarily here, giving an +|xchr| equivalent to whatever characters the users of +\.{TIE} are allowed to have in their input files, provided +that unsuitable characters do not correspond to special +codes like |carriage_return| that are listed above. + +@<Set init...@>= +for i:=1 to @'37 do xchr[i]:=' '; + + +@ The following system-independent code makes the |xord| +array contain a suitable inverse to the information in +|xchr|. + +@<Set init...@>= +for i:=first_text_char to last_text_char do xord[chr(i)]:=@'40; +for i:=1 to @'176 do xord[xchr[i]]:=i; + + + + + +@* Input and output. + +\noindent Terminal output is done by writing on file +|term_out|, which is assumed to consist of characters of +type |text_char|. Terminal input is read from |term_in|. +@^system dependencies@> + +@d print(#)==write(term_out,#) {`|print|' means write on the terminal} +@d print_ln(#)==write_ln(term_out,#) +@d new_line==write_ln(term_out) {start new line} +@d print_nl(#)== @+ begin new_line; print(#) @+ end + +@<Globals...@>= +@!term_in:text_file; +@!term_out:text_file; + + +@ To initialize terminal input we do a reset, just when the +first character is needed. This allows output before the +first input line is read even if ``lazy input'' is not +supported by your \PASCAL\ compiler. +@^system dependencies@> + +@<Reset terminal input@>= +reset(term_in,'TTY:','/I') + + +@ Similarly we initialize terminal output to a file that +should be associated to the user's terminal interactively. +@^system dependencies@> + +@<Set init...@>= +rewrite(term_out,'TTY:'); + + +@ 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 == break(term_out) {empty the terminal output buffer} + + +@ If an error occurs we indicate this calling a procedure +named |err_print|. This procedure is implemented as a +macro. It gives a message and an indication of the +offending file. The actions to determine the error location +will be explained later. + +@d error_loc(#) == err_loc(#); history:=troublesome; @+ end +@d err_print(#) == @+ begin print_nl(#); error_loc + + +@ The basic procedure |get_ln_from_file| can be used to get +a line from an input file. The line is stored in +|input_files[i].buffer|. The components |limit| and |line| +are updated. If the end of the file is reached +|input_files[i].mode| is set to |ignore|. On some systems +it might be useful to replace tab characters by a proper +number of spaces since several editors used to create change +files insert tab characters into a source file not under +control of the user. So it might be a problem to create a +matching change file. +@^tab character expansion@> + +We define |get_line| to read a line from a file specified by +number. To ease an inplementation without arrays of files +we introduce one more parameter. In such cases |get_line| +is best replaced by a procedure containing a |case| +statement to select the file needed. + +@d get_line(#)==get_ln_from_file(#,input_files[#]); + +@p +procedure get_ln_from_file(i:integer;var cur_file:text_file); + label exit; + var final_limit:0..buf_size; + begin + with input_organization[i] do + begin + if mode=ignore then return; + if eof(cur_file) then @<Handle end of file and return@>; + @<Get line into buffer@>; + end; +exit: end; + + +@ End of file is special if this file is the master file. + +@<Handle end of file ...@>= +begin + mode:=ignore; + if type_of_file=master then input_has_ended:=true; + return; +end + + +@ Lines must fit into the buffer completely. +Tab character expansion might be done here. +@^tab character expansion@> + +@<Get line into buffer@>= +incr(line); +limit:=0; final_limit := 0; +while (not eoln(cur_file) and (limit<=buf_size)) do +begin + buffer[limit]:=xord[cur_file^]; get(cur_file); incr(limit); + if (buffer[limit-1]<>" ")and(buffer[limit-1]<>tab_mark) then + final_limit:=limit; +end; +limit:=final_limit; +if not eoln(cur_file) then err_print('! Input line too long')(i); +@.Input line too long@> +read_ln(cur_file) + + + + + +@* Data structures. + +\noindent The multiple input files (master file and change +files) are treated the same way. To organize the +simultaneous usage of several input files, we introduce the +data types |in_file_modes|. + +The mode |search| indicates that \.{TIE} searches for a +match of the input line with any line of an input file in +|reading| mode. |test| is used whenever a match is found +and it has to be tested if the next input lines do match +also. |reading| describes that the lines can be read without +any check for equality to other lines. |ignore| denotes +that the file cannot be used. This may happen because an +error has been detected or because the end of the file has +been found. + +\leavevmode |file_types| is used to describe whether a file +is a master file or a change file. + +@<Types...@>= +@!in_file_modes=(@!search,@!test,@!reading,@!ignore);@/ +@!file_types=(@!master,@!chf); + + +@ The following data structures join all informations needed to use +these input files. + +@<Types...@>= +@!out_md_type=(@!normal,@!pre,@!post);@/ +@!name_type=record @!name:array[1..max_name_length] of char; + @!nam_len:0..max_name_length; + end; +@!buffer_index=0..buf_size;@/ +@!file_index=0..max_file_index;@/ +@!input_description=record + @!name_of_file: name_type; + @!buffer: array[0..buf_size]of ascii_code; + @!mode: in_file_modes; + @!line: integer; + @!type_of_file: file_types; + @!limit: buffer_index; + end; + + +@ These data types are used in the global variable section. + +@<Globals...@>= +@!actual_input,@!test_input:integer; +@!input_has_ended:boolean; +@!input_organization: array[0..max_file_index] of input_description; +@!input_files: array[0..max_file_index] of text_file; +@!no_ch,@!cmd:integer; +@!c:char; +i,j:integer; +@!prod_chf:boolean; +@!name_field:name_type; +@!master_ext:name_type; +@!cf_ext:name_type; +@!no_ext:name_type; +@!out_mode:out_md_type; +@!ext_start:0..max_name_length; + + + + + +@* Reporting errors to the user. + +\noindent There may be errors if a line in a given change +file does not match a line in the master file or a +replacement in a previous change file. Such errors are +reported to the user by saying +$$ + \hbox{|err_print('! Error message')|.} +$$ +Please note that no trailing point is supplied by the error +message because it is appended by |err_print|. Non +recoverable errors are handled by calling |fatal_error| that +outputs a message and then calls `|jump_out|'. + +\leavevmode |err_print| will print the error message +followed by an indication of where the error was spotted in +the source files. |fatal_error| cannot state any files +because the problem is usually to access these. + +For |err_print| messages the following procedure is used to +write the proper name of an input file. + +@d fatal_error(#)==begin print_nl(#); print_ln('.'); history:=fatal; jump_out; + end + +@<Error handling...@>= +procedure print_name_of_file(cur_index:file_index); +var i:integer; +begin + with input_organization[cur_index] do + for i:=1 to name_of_file.nam_len do print(name_of_file.name[i]); +end; + + +@ The actual error indications are provided by a procedure +called |err_loc|. + +@<Error handling...@>= +procedure err_loc(i:integer); {prints location of error} +begin + with input_organization[i] do + begin + print(' (file '); + print_name_of_file(i); + print(', l.',line:1,').'); + new_line; + end; +end; + + +@ The |jump_out| procedure just cuts across all active +procedure levels and jumps out of the program. This is the +only non-local |goto| statement in \.{TIE}. It is used when +no recovery from a particular error has been provided. + +Some \PASCAL\ compilers do not implement non-local |goto| +statements. In such cases the code that appears at label +|end_of_TIE| should be copied into the |jump_out| procedure, +followed by a call to a system procedure that terminates the +program. +@^system dependencies@> + +@<Error handling...@>= +procedure jump_out; +begin goto end_of_TIE; +end; + + + + + +@* Handling multiple change files. + +\noindent In the standard version we read the name of the +files from the console. Handling of the end of line +indicator might need a system dependent update. There might +be system dependent changes to get the names of the files +from the command line. + +If \.{TIE} is used on a system which allows filenames only +in upper or lower case, |read_chr| should be replaced by a +procedure that converts the characters properly. +@^system dependencies@> + +@d read_chr(#)==read(term_in,#) + +@p procedure rd_file; +var c:char; +begin + name_field.nam_len:=0; + while (not eoln(term_in) and (name_field.nam_len<max_name_length)) do + begin + incr(name_field.nam_len); + read_chr(c); + name_field.name[name_field.nam_len]:=c; + end; + if name_field.nam_len>0 then + if not eoln(term_in) then + fatal_error('! File name too long'); +@.File name too long@> +end; + + +@ To do our job we need the master file's name. + +@<Read master file name@>= +begin + print_nl('Please enter the name of the master file: '); +@.Please enter the name ...@> + update_terminal; + @<Reset terminal input@>; + rd_file; + if name_field.nam_len=0 then + fatal_error('! Illegal file name'); +@.Illegal file name@> + @<Ignore master file extension@>; + if name_field.nam_len+4>max_name_length then + fatal_error('! File name too long'); +@.File name too long@> +end + + +@ The extension of the master source file is to be ignored. +We assume that extensions are separated from the base name +by a period. Let us scan from the tail to the last period. +We skip only characters, digits and underscore characters. +Finding any other character stops extension scanning. + +@<Ignore master file extension@>= +begin if name_field.nam_len>3 then with name_field do + begin i:=nam_len; ext_start:=0; {extension not yet found} + while i>0 do + if name[i]='.' then begin ext_start:=i; i:=0 end + else + if (name[i]>='a') and (name[i]<='z') then i:=i-1 else + if (name[i]>='A') and (name[i]<='Z') then i:=i-1 else + if (name[i]>='0') and (name[i]<='9') then i:=i-1 else + if (name[i]='_') then i:=i-1 else i:=0; + if ext_start>0 then + begin {initialize master file extension} + for i:=ext_start to nam_len do + master_ext.name[i-ext_start+1]:=name[i]; + master_ext.nam_len:=nam_len-ext_start+1; + for i:=master_ext.nam_len+1 to max_name_length do + master_ext.name[i]:=' '; + nam_len:=ext_start-1; + end; + end +end + + +@ We must determine the name of a change file, too. +This might be changed to command line parameter processing. +@^command line processing@> + +@<Read change file name@>= +begin + print_ln('Please enter the name of change file ',no_ch:1); + print('or <Return> if there are no more change files: '); + update_terminal; + read_ln(term_in); + rd_file; +end + + +@ The selection whether a new master file or a mixed change +file should be produced might be replaced by a command line +switch, too. +@^command line processing@> + +@<Change or master file producing@>= +repeat + print_nl('Do you want to create a new master or a change file (m/c)? '); +@.Do you want to create ...@> + update_terminal; + read_ln(term_in); read_chr(c); + cmd:=xord[c]; + if (cmd>="a") and (cmd<="z") then cmd:=cmd+"A"-"a"; +until (cmd="C")or(cmd="M"); +prod_chf:=(cmd="C") + + +@ We continue with a function to open a text file. Success +is indicated by a boolean result. We assume that empty +files can be handled like non existent ones. +@^system dependencies@> + +@p function file_open(var f:text_file;name:name_type):boolean; +begin + reset(f,name.name); + file_open:=not eof(f); +end; + + +@ The procedure |insert_name| initializes the name of the +file number |cur_index| to ``prefix'' ``extension''. + +@p procedure insert_name(cur_index:file_index;prefix:name_type; + extension:name_type); +var i:integer; +begin + with input_organization[cur_index] do + begin + for i:=1 to max_name_length do name_of_file.name[i]:=' '; + for i:=1 to prefix.nam_len do name_of_file.name[i]:=prefix.name[i]; + for i:=1 to extension.nam_len do + name_of_file.name[prefix.nam_len+i]:=extension.name[i]; + name_of_file.nam_len:=prefix.nam_len+extension.nam_len; + end; +end; + + +@ +@<Get the master file started@>= + insert_name(0,name_field,master_ext); + if not file_open(input_files[0],input_organization[0].name_of_file) then + fatal_error('! Master file can''t be opened') +@.Master file can't be opened@> + else + begin + print('('); + print_name_of_file(0); + print_ln(')'); + input_organization[0].type_of_file:=master; + get_line(0); + end; + + +@ This is a procedure to open all input files. Changes +might be used to get the names of the files from a command +line. In this interactive version \.{TIE} will try to use +change files with extensions \.{CF1} to \.{CF9} +automatically---and there is no way to inhibit this, if +those files exist. +@^command line processing@> + +@p +@t\4@>@<Procedures for |open_input|@> +procedure open_input; {prepare to read |input_files|} +label done; +var i:integer; +begin + @<Initialize extensions@>; + @<Get the master file started@>; + actual_input:=0; + for i:=1 to max_file_index do + begin + cf_ext.name[cf_ext.nam_len]:=xchr["0"+i]; + insert_name(i,name_field,cf_ext); + end; + no_ch:=0; + while no_ch<9 do + begin + incr(no_ch); + if not file_open(input_files[no_ch], + input_organization[no_ch].name_of_file) + then + begin + @<Read change file name@>; + if name_field.nam_len=0 then begin decr(no_ch); goto done; end; + insert_name(no_ch,name_field,no_ext); + decr(no_ch); + end else + begin + print('('); + print_name_of_file(no_ch); + print_ln(')'); + init_change_file(no_ch,true); + end; + end; +done: + if no_ch=0 then + fatal_error('! No change file found'); +@.No change file found@> + for i:=no_ch+1 to max_file_index do input_organization[i].mode:=ignore; +end; + + +@ According to the names given above, we initialize the +extension names. We need the standard change file +extensions that are \.{CF}$i$ and a ``dummy'' entry for +change files that do not need additional extensions. + +@<Initialize extensions@>= +cf_ext.name[1]:='.'; +cf_ext.name[2]:='C'; +cf_ext.name[3]:='F'; +cf_ext.name[4]:=' '; +cf_ext.nam_len:=4; +for i:=cf_ext.nam_len+1 to max_name_length do cf_ext.name[i]:=' '; +no_ext.nam_len:=0; +for i:=1 to max_name_length do no_ext.name[i]:=' ' + + +@ The main output goes to |out_file|. + +@<Globals...@>= +@!out_file:text_file; + + +@ The following code opens |out_file|. Since this file is +mentioned in the program header we assume that the \PASCAL\ +runtime system has checked the existence of the file. +@^system dependencies@> + +@<Set init...@>= +rewrite(out_file); + + + + + +@*Input/output organization. + +\noindent Here's a simple function that checks if two lines +are different. + +@p function lines_dont_match(i,j:integer):boolean; +label exit; +var k,lmt:buffer_index; +begin + lines_dont_match:=true; + if input_organization[i].limit <> input_organization[j].limit + then return; + lmt:=input_organization[i].limit; + if lmt > 0 then + for k:=0 to lmt-1 do + if input_organization[i].buffer[k] <> + input_organization[j].buffer[k] then return; + lines_dont_match:=false; +exit: end; + + +@ Procedure |init_change_file(i,b)| is used to ignore all +lines of the input file with index |i| until the next change +module is found. The boolean parameter |b| indicates +whether we do not want to see '@@x' or '@@y' entries during +our skip. + +@<Procedures for |open_input|@>= +procedure init_change_file(i:integer;b:boolean); +label continue, done, exit; +begin + with input_organization[i] do + begin + @<Skip over comment lines; |return| if end of file@>; + @<Skip to the next nonblank line; |return| if end of file@>; + end; +exit: end; + + +@ 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} or \.{@@z} (which would +probably indicate that the change file is fouled up). + +@<Skip over comment lines...@>= +loop@+ begin get_line(i); + if mode=ignore then return; + if limit<2 then goto continue; + if buffer[0] <> "@@" then goto continue; + if (buffer[1]>="X") and (buffer[1]<="Z") then + buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify} + if buffer[1]="x" then goto done; + if (buffer[1]="y") or (buffer[1]="z") then + if b then {waiting for start of change} + err_print('! Where is the matching @@x?')(i); +@.Where is the match...@> +continue: end; +done: + + +@ Here we are looking at lines following the \.{@@x}. + +@<Skip to the next nonblank line...@>= +repeat + get_line(i); + if mode=ignore then + begin + err_print('! Change file ended after @@x')(i); +@.Change file ended...@> + return; + end; +until limit>0 + + +@ The |put_line| procedure is used to write a line from +input buffer |j| to the output file. + +@p procedure put_line(j:integer); +var i:integer; {index into the buffer} +begin + with input_organization[j] do + for i:=0 to limit-1 do write(out_file,xchr[buffer[i]]); + write_ln(out_file); +end; + + +@ The function |e_of_ch_module| returns true if the input +line from file |i| is equal to \.{@@z}. + +@p function e_of_ch_module(i:integer):boolean; +begin + e_of_ch_module:=false; + with input_organization[i] do + if limit>=2 then if buffer[0]="@@" then + if (buffer[1]="Z") or (buffer[1]="z") then e_of_ch_module:=true; +end; + + +@ The function |e_of_ch_preamble| returns true if the input +line from file |i| is equal to \.{@@y}. + +@p function e_of_ch_preamble(i:integer):boolean; +begin + e_of_ch_preamble:=false; + with input_organization[i] do + if limit>=2 then if buffer[0]="@@" then + if (buffer[1]="Y") or (buffer[1]="y") then e_of_ch_preamble:=true; +end; + + +@ To start with our inputs we set the indication that all +change files are in state |search|. That means that we must +skip to the next (in this case the first) change entry. + +@<Initialize the input system@>= +for i:=0 to max_file_index do + with input_organization[i] do + begin + mode:=search; line:=0; type_of_file:=chf; limit:=0; + for j:=1 to max_name_length do name_of_file.name[j]:=' '; + for j:=0 to buf_size do buffer[j]:=0; + end; +actual_input:=0; +out_mode:=normal + + +@ To process the input file the procedure |process_line| +reads a line of the actual input file and updates the +|input_organization| for all files with index |i| greater +|actual_input|. + +@p procedure process_line; +label done, exit; +var i:integer; +begin + @<Init process@>; + @<Handle output@>; + @<Step to next line@>; +exit: end; + + +@ If |test_input| is |none|, no change file is tested. + +@d none == (max_file_index+1) + +@<Init process@>= +while e_of_ch_module(actual_input) do + with input_organization[actual_input] do + begin + if type_of_file=master then {emergency exit, everything mixed up!} + fatal_error('! This can''t happen'); + mode:=search; + init_change_file(actual_input,true); + while ((input_organization[actual_input].mode<>reading) + and (actual_input>0)) do decr(actual_input); + end; +if input_has_ended and (actual_input=0) then return; +test_input:=none; +i:=actual_input; +while ((test_input=none) and (i<no_ch)) do +begin + incr(i); + case input_organization[i].mode of + search: if not lines_dont_match(actual_input,i) then + begin + input_organization[i].mode:=test; + test_input:=i; + end; + test: begin + if lines_dont_match(actual_input, i) then + begin + {error, modules do not match} + input_organization[i].mode:=search; + err_print('! Sections do not match')(actual_input); +@.Sections do not match@> + err_loc(i); + init_change_file(i,false); + end else test_input:=i; + end; + reading:do_nothing; {this can't happen} + ignore: do_nothing; {nothing to do} + end; +end + + +@ @<Handle output@>= +if prod_chf then +begin + loop @+ begin + @<Test for normal@>; + @<Test for pre@>; + @<Test for post@>; + end; +done: +end else +if test_input=none then put_line(actual_input) + + +@ Check whether we have to start a change file entry. + +@<Test for normal@>= +begin + if out_mode=normal then + if test_input<>none then + begin + write(out_file,xchr["@@"]); write_ln(out_file,xchr["x"]); + out_mode:=pre; + end else goto done; +end + + +@ Check whether we have to start the replacement text. + +@<Test for pre@>= +begin + if out_mode=pre then + begin + if test_input=none then + begin + write(out_file,xchr["@@"]); write_ln(out_file,xchr["y"]); + out_mode:=post; + end else + begin + if input_organization[actual_input].type_of_file=master then + put_line(actual_input); + goto done; + end; + end; +end + + +@ Check whether a change file entry is complete. + +@<Test for post@>= +begin + if out_mode=post then + begin + if input_organization[actual_input].type_of_file=chf then + begin + if test_input=none then put_line(actual_input); + goto done; + end else + begin + write(out_file,xchr["@@"]); write_ln(out_file,xchr["z"]); + write_ln(out_file); + out_mode:=normal; + end; + end; +end + + +@ @<Step to next line@>= +get_line(actual_input); +if test_input<>none then +begin + get_line(test_input); + if e_of_ch_preamble(test_input) then + begin + get_line(test_input); {update input file} + input_organization[test_input].mode:=reading; + actual_input:=test_input; + test_input:=none; + end; +end + + +@ @<Process the input@>= +input_has_ended:=false; +while not input_has_ended or (actual_input<>0) do process_line; +if out_mode = post then {last line has been changed} + begin write(out_file,xchr["@@"]); write_ln(out_file,xchr["z"]); + end; + + +@ 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 the master file. + +@<Check that all changes have been read@>= +for i:=1 to max_file_index do {all change files} + if input_organization[i].mode <> ignore then + err_print('! Change file entry did not match')(i); +@.Change file entry ...@> + + + + + +@* The main program. + +\noindent Here is where \.{TIE} starts, and where it ends. +If a command line interface is present, changes to +initialize the access might be needed here. +@^system dependencies@> +@^command line processing@> + +@p begin initialize; + print_ln(banner); {print a ``banner line''} + print_ln(copyright); {include the copyright notice} + @<Initialize the input system@>; + @<Read master file name@>; + open_input; + @<Change or master file producing@>; + @<Process the input@>; + @<Check that all changes have been read@>; +end_of_TIE: + {here files should be closed if the operating system requires it} + @<Print the job |history|@>; +end. + + +@ 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 we simply +report the history to the user. +@^system dependencies@> + +@<Print the job |history|@>= +case history of +spotless: print_nl('(No errors were found.)'); +troublesome: print_nl('(Pardon me, but I think I spotted something wrong.)'); +fatal: print_nl('(That was a fatal error, my friend.)'); +end {there are no other cases} + + + + + +@* System-dependent changes. + +\noindent This section should be replaced, if necessary, by +changes to the program that are necessary to make \.{TIE} +work at a particular installation. It is usually best to +design your change file so that all changes to previous +modules preserve the module numbering; then everybody's +version will be consistent with the printed program. More +extensive changes, which introduce new modules, can be +inserted here; then only the index itself will get a new +module number. +@^system dependencies@> + + + + + +@* Index. + +\noindent Here is the cross-reference table for the \.{TIE} +processor. diff --git a/web/spiderweb/tools/tie/tiedoc.tex b/web/spiderweb/tools/tie/tiedoc.tex new file mode 100644 index 0000000000..ba2dd767e5 --- /dev/null +++ b/web/spiderweb/tools/tie/tiedoc.tex @@ -0,0 +1,149 @@ +\documentstyle{article} +\font\mc=cmcsc10 +\def\TANGLE{{\tt TANGLE}} +\def\TIE{{\tt TIE}} +\def\WEAVE{{\tt WEAVE}} +\def\WEB{{\tt WEB}} +\def\CWEB{{\mc cweb}} +\def\PASCAL{{\mc Pascal}} +\title{The TIE Processor} +\author{Klaus Guntermann\\ +TH Darmstadt\\ +Fachbereich Informatik\\ +Institut f\"ur Theoretische Informatik} + +\date{December 1986} +\begin{document} +\maketitle +\section{Introduction} + +To install a program on a computer usually +system dependent changes are needed. +The \WEB\ system allows to describe these changes in a +so called change file. +To incorporate the changes into the program \TANGLE\ processes +the original source file and inserts the changes into the proper places. + +Sometimes it is good practice to develop a set of change files to be able to +distinguish between different changes like +program enhancements, bug fixes, system dependent changes +and output device dependent modifications. +Additionally this allows combinations of changes that can be used with a set of +programs that share some common features. + +The processors \TANGLE\ and \WEAVE\ can handle only one change file. +The combination of change files is done best in another preprocessing step. +\TIE\ is able to create either a new master file or a single change file that +comprises the effect of all change files. + +Since \TIE\ does not know anything about \WEB\ programs but only about the +structure of change files, it is possible to use this program for other +programming languages as well. +You just pretend that you want to create a new master file and \TIE\ will go +and insert all the changes from your change files. + + + +\section{Application} + +The current version of \TIE\ accepts a master file and up to 9 change files. +Because in general it is important to use the changes in their proper sequence +the order of the files must be chosen carefully. + +The standard version of \TIE\ prompts the user for the names of the change +files interactively. +The implementor may choose to replace this by a command line interface if the +operating system and the compiler support such features. +Within this document we will refer to the interactive version of \TIE. + +First the name of the master file must be entered. +The extension of this name (beginning with a period) +is stripped to get the base name of the file. +The base name and the extensions {\tt CF1}, \dots, {\tt CF9} +are checked. +If such files exist they are opened and are allocated as current change files. +As soon as one of these files is not found the user is asked to supply +additional change file names. +Thus change files with other names may be used deliberately. +If there are no more changes the user enters an empty name just hitting +``Return''. +Then the processing mode still must be supplied. +The user may request the creation of a new master file by selection of mode +``m'' or he may want to create a single change file by selection of mode ``c''. + +The name of the output file created is not specified interactively. +It depends on the runtime system of the \PASCAL\ compiler and the +operating system whether it must be given before the program is started +or at some point when the file is to be opened. + +The multiple change files are used as if the single change files were merged +into the master files step by step. +Thus more than 9 change files might be incorporated by repeated application of +\TIE. + +Please note that even when multiple change files are processed each of the +files is read only once. +For each of the change files and for the master file there is only one line in +memory at a time (neglecting operating system buffering). +Thus the storage requirement of \TIE\ does not depend on the size of the change +files or the size of a single changed section. + +\vfill\eject +\def\eof{$\langle$EOF$\rangle$} +\section{Example} + +To illustrate the actions \TIE\ performs you may inspect the following example +that exercises some of the border line cases. + +$$\vbox{ +\halign{#\hfill\qquad\quad&#\hfill\qquad\quad&#\hfill\qquad\quad&#\hfill\cr +``master'' &{\tt CF1} &{\tt CF2} &{\tt CF3}\cr +line 1 &@x &@x &@x\cr +line 2 &line 2 &line 1 &changed line 4\cr +line 3 &line 3 &changed line 2 &@y\cr +line 4 &@y &changed line 3 &final line 4\cr +line 5 &changed line 2 &inserted line &@z\cr +line 6 &changed line 3 &line 4 &\eof\cr +line 7 &inserted line &@y\cr +line 8 &@z &final line 2\cr +line 9 & &final line 3\cr +line 10 &@x &changed line 4\cr +\eof &line 7 &@z\cr + &@y\cr + &changed line 7 &@x\cr + &@z &changed line 7\cr + &\eof &line 8\cr + & &@y\cr + & &final line 7\cr + & &final line 8\cr + & &@z\cr + & &\eof\cr} +}$$ +\vfill\eject +Using these input files and running \TIE\ twice to create a new master file +and a new change file will result in the following output files: + +$$\vbox{ +\halign{#\hfill\qquad\quad&&#\hfill\qquad\quad\cr +``master'' &``change''\cr +final line 2 &@x\cr +final line 3 &line 1\cr +final line 4 &line 2\cr +line 5 &line 3\cr +line 6 &line 4\cr +final line 7 &@y\cr +final line 8 &final line 2\cr +line 9 &final line 3\cr +line 10 &final line 4\cr +\eof &@z\cr + &\cr + &@x\cr + &line 7\cr + &line 8\cr + &@y\cr + &final line 7\cr + &final line 8\cr + &@z\cr + &\eof\cr} +}$$ +\end{document} |