From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- web/spiderweb/COPYRIGHT | 11 + web/spiderweb/README | 102 + web/spiderweb/bug-reports | 1973 ++++++++ web/spiderweb/doc/Makefile | 3 + web/spiderweb/doc/abstracts.tex | 23 + web/spiderweb/doc/cacm.aux | 16 + web/spiderweb/doc/cacm.tex | 602 +++ web/spiderweb/doc/overview.aux | 12 + web/spiderweb/doc/overview.tex | 149 + web/spiderweb/doc/spdjman.tex | 2065 +++++++++ web/spiderweb/doc/spe.aux | 70 + web/spiderweb/doc/spe.bbl | 186 + web/spiderweb/doc/spe.tex | 545 +++ web/spiderweb/doc/spiderman.aux | 56 + web/spiderweb/doc/spiderman.tex | 1693 +++++++ web/spiderweb/doc/spiderwebman.tex | 2268 +++++++++ web/spiderweb/doc/spiderwebman.toc | 1 + web/spiderweb/fixes-to-be-applied/changes | 641 +++ web/spiderweb/fixes-to-be-applied/dnn.web | 125 + web/spiderweb/fixes-to-be-applied/fixes | 139 + web/spiderweb/fixes-to-be-applied/latex/README | 66 + .../fixes-to-be-applied/latex/WebMakefile | 172 + web/spiderweb/fixes-to-be-applied/latex/awkmake | 5 + web/spiderweb/fixes-to-be-applied/latex/cmake | 5 + .../fixes-to-be-applied/latex/cspider.dif | 17 + .../fixes-to-be-applied/latex/latexweb.tex | 81 + web/spiderweb/fixes-to-be-applied/latex/spider.ltx | 107 + web/spiderweb/fixes-to-be-applied/latex/tangle.ltx | 79 + web/spiderweb/fixes-to-be-applied/latex/tie.web | 1276 ++++++ web/spiderweb/fixes-to-be-applied/latex/tiedoc.tex | 138 + web/spiderweb/fixes-to-be-applied/latex/weave.ltx | 700 +++ web/spiderweb/fixes-to-be-applied/latex/web.doc | 945 ++++ web/spiderweb/fixes-to-be-applied/latex/web.sty | 271 ++ web/spiderweb/mac/MPW_SpiderWEB_21Mar93.sit.bin | 1796 ++++++++ web/spiderweb/ms-dos/whereis | 325 ++ web/spiderweb/os2/os2.changes | 688 +++ web/spiderweb/patches/001 | 32 + web/spiderweb/patches/002 | 95 + web/spiderweb/patches/003 | 179 + web/spiderweb/patches/004 | 70 + web/spiderweb/patches/005 | 74 + web/spiderweb/patches/006 | 92 + web/spiderweb/patches/007 | 188 + web/spiderweb/patches/008 | 29 + web/spiderweb/patches/009 | 44 + web/spiderweb/patches/010 | 36 + web/spiderweb/src/68k/68k.spider | 569 +++ web/spiderweb/src/68k/make | 3 + web/spiderweb/src/BUGS | 84 + web/spiderweb/src/COPYRIGHT | 11 + web/spiderweb/src/Makefile | 44 + web/spiderweb/src/README | 104 + web/spiderweb/src/README.DOS | 56 + web/spiderweb/src/ada/ada.spider | 278 ++ web/spiderweb/src/ada/make | 3 + web/spiderweb/src/ada/new.spider | 315 ++ web/spiderweb/src/ada/old.spider | 261 ++ web/spiderweb/src/ada/stacks.web | 443 ++ web/spiderweb/src/awk/awk.spider | 168 + web/spiderweb/src/awk/make | 2 + web/spiderweb/src/awk/tangle.c | 2172 +++++++++ web/spiderweb/src/big-web.ch | 59 + web/spiderweb/src/c++/c++.spider | 368 ++ web/spiderweb/src/c++/make | 3 + web/spiderweb/src/c/c.spider | 350 ++ web/spiderweb/src/c/local.guide | 4 + web/spiderweb/src/c/make | 3 + web/spiderweb/src/c/new.spider | 407 ++ web/spiderweb/src/c/tangle.c | 2214 +++++++++ web/spiderweb/src/concrete-kernel.diff | 200 + web/spiderweb/src/dijkstra/README | 3 + web/spiderweb/src/dijkstra/binary.web | 267 ++ web/spiderweb/src/dijkstra/d.spider | 155 + web/spiderweb/src/dijkstra/make | 2 + web/spiderweb/src/dijkstra/sp.web | 28 + web/spiderweb/src/kelem/ac.spider | 496 ++ web/spiderweb/src/kelem/ac_guide.web | 292 ++ web/spiderweb/src/kelem/indent-troubles | 40 + web/spiderweb/src/kelem/make | 2 + web/spiderweb/src/kelem/test.web | 19 + web/spiderweb/src/larch/l.spider | 245 + web/spiderweb/src/larch/lists.web | 56 + web/spiderweb/src/larch/make | 2 + web/spiderweb/src/master/Make.pretty | 18 + web/spiderweb/src/master/Makefile | 18 + web/spiderweb/src/master/WebMakefile | 146 + web/spiderweb/src/master/common.c | 1001 ++++ web/spiderweb/src/master/common.h | 146 + web/spiderweb/src/master/common.web | 1198 +++++ web/spiderweb/src/master/cycle.awk | 86 + web/spiderweb/src/master/cycle.web | 81 + web/spiderweb/src/master/junk.list | 22 + web/spiderweb/src/master/multitang.ch | 107 + web/spiderweb/src/master/newdefs.awk | 11 + web/spiderweb/src/master/nodups.awk | 13 + web/spiderweb/src/master/pathopen.c | 122 + web/spiderweb/src/master/pathopen.h | 9 + web/spiderweb/src/master/pathopen.web | 192 + web/spiderweb/src/master/pretty.awk | 2 + web/spiderweb/src/master/spider.awk | 4799 ++++++++++++++++++++ web/spiderweb/src/master/spider.web | 2580 +++++++++++ web/spiderweb/src/master/tangle.web | 1800 ++++++++ web/spiderweb/src/master/transcheck.awk | 23 + web/spiderweb/src/master/transcheck.list | 14 + web/spiderweb/src/master/weave.web | 3250 +++++++++++++ web/spiderweb/src/master/webhead | 2 + web/spiderweb/src/master/webtail | 1 + web/spiderweb/src/nawk/make | 2 + web/spiderweb/src/nawk/nawk.spider | 176 + web/spiderweb/src/penelope/SpiderMakefile | 9 + web/spiderweb/src/penelope/a.spider | 375 ++ web/spiderweb/src/penelope/make | 5 + web/spiderweb/src/penelope/nesting.spider | 21 + web/spiderweb/src/penelope/processed-a.spider | 418 ++ web/spiderweb/src/penelope/scan_annotations.awk | 81 + web/spiderweb/src/penelope/stacks.web | 445 ++ web/spiderweb/src/postscript/README | 10 + web/spiderweb/src/postscript/WebMakefile.new | 147 + web/spiderweb/src/postscript/local.guide | 72 + web/spiderweb/src/postscript/make | 5 + web/spiderweb/src/postscript/outline.ps1 | 212 + web/spiderweb/src/postscript/outline.web | 162 + web/spiderweb/src/postscript/ps.spider | 77 + web/spiderweb/src/reduce/INSTALL | 26 + web/spiderweb/src/reduce/Makefile | 152 + web/spiderweb/src/reduce/README | 69 + web/spiderweb/src/reduce/make | 3 + web/spiderweb/src/reduce/reduce.spider | 283 ++ web/spiderweb/src/reduce/rtangle | 10 + web/spiderweb/src/reduce/rtangle.ch | 135 + web/spiderweb/src/reduce/rweave.ch | 149 + web/spiderweb/src/reduce/underscore.web | 32 + web/spiderweb/src/sml/leavens.mail | 548 +++ web/spiderweb/src/sml/make | 3 + web/spiderweb/src/sml/mason.mail | 1031 +++++ web/spiderweb/src/ssl/make | 2 + web/spiderweb/src/ssl/s.spider | 220 + web/spiderweb/src/turing+/example.mail | 195 + web/spiderweb/src/turing+/make | 3 + web/spiderweb/src/turing+/turing+.spider | 527 +++ web/spiderweb/src/turing/make | 3 + web/spiderweb/src/turing/turing.spider | 624 +++ web/spiderweb/src/webkernel.tex | 383 ++ web/spiderweb/todo | 16 + web/spiderweb/tools/Makefile | 42 + web/spiderweb/tools/depend.web | 128 + web/spiderweb/tools/excerpt/excerpt | 54 + web/spiderweb/tools/excerpt/excerpt.doc | 31 + web/spiderweb/tools/excerpt/filesplit.web | 163 + web/spiderweb/tools/excerpt/section.c | 70 + web/spiderweb/tools/shortindex | 3 + web/spiderweb/tools/tie/@read@.me | 29 + web/spiderweb/tools/tie/Makefile | 13 + web/spiderweb/tools/tie/cf1 | 14 + web/spiderweb/tools/tie/cf2 | 19 + web/spiderweb/tools/tie/cf3 | 5 + web/spiderweb/tools/tie/character.web | 148 + web/spiderweb/tools/tie/datadecl.web | 74 + web/spiderweb/tools/tie/error.web | 56 + web/spiderweb/tools/tie/history.web | 25 + web/spiderweb/tools/tie/io.web | 108 + web/spiderweb/tools/tie/master | 10 + web/spiderweb/tools/tie/newmaster | 9 + web/spiderweb/tools/tie/tie.c | 696 +++ web/spiderweb/tools/tie/tie.chf | 191 + web/spiderweb/tools/tie/tie.preamble | 31 + web/spiderweb/tools/tie/tie.web | 558 +++ web/spiderweb/tools/tie/tie.web,v | 576 +++ web/spiderweb/tools/tie/tie.web.dist | 1336 ++++++ web/spiderweb/tools/tie/tiedoc.tex | 149 + 170 files changed, 54728 insertions(+) create mode 100644 web/spiderweb/COPYRIGHT create mode 100644 web/spiderweb/README create mode 100644 web/spiderweb/bug-reports create mode 100644 web/spiderweb/doc/Makefile create mode 100644 web/spiderweb/doc/abstracts.tex create mode 100644 web/spiderweb/doc/cacm.aux create mode 100644 web/spiderweb/doc/cacm.tex create mode 100644 web/spiderweb/doc/overview.aux create mode 100644 web/spiderweb/doc/overview.tex create mode 100644 web/spiderweb/doc/spdjman.tex create mode 100644 web/spiderweb/doc/spe.aux create mode 100644 web/spiderweb/doc/spe.bbl create mode 100644 web/spiderweb/doc/spe.tex create mode 100644 web/spiderweb/doc/spiderman.aux create mode 100644 web/spiderweb/doc/spiderman.tex create mode 100644 web/spiderweb/doc/spiderwebman.tex create mode 100644 web/spiderweb/doc/spiderwebman.toc create mode 100644 web/spiderweb/fixes-to-be-applied/changes create mode 100644 web/spiderweb/fixes-to-be-applied/dnn.web create mode 100644 web/spiderweb/fixes-to-be-applied/fixes create mode 100644 web/spiderweb/fixes-to-be-applied/latex/README create mode 100644 web/spiderweb/fixes-to-be-applied/latex/WebMakefile create mode 100644 web/spiderweb/fixes-to-be-applied/latex/awkmake create mode 100644 web/spiderweb/fixes-to-be-applied/latex/cmake create mode 100644 web/spiderweb/fixes-to-be-applied/latex/cspider.dif create mode 100644 web/spiderweb/fixes-to-be-applied/latex/latexweb.tex create mode 100644 web/spiderweb/fixes-to-be-applied/latex/spider.ltx create mode 100644 web/spiderweb/fixes-to-be-applied/latex/tangle.ltx create mode 100644 web/spiderweb/fixes-to-be-applied/latex/tie.web create mode 100644 web/spiderweb/fixes-to-be-applied/latex/tiedoc.tex create mode 100644 web/spiderweb/fixes-to-be-applied/latex/weave.ltx create mode 100644 web/spiderweb/fixes-to-be-applied/latex/web.doc create mode 100644 web/spiderweb/fixes-to-be-applied/latex/web.sty create mode 100644 web/spiderweb/mac/MPW_SpiderWEB_21Mar93.sit.bin create mode 100644 web/spiderweb/ms-dos/whereis create mode 100644 web/spiderweb/os2/os2.changes create mode 100644 web/spiderweb/patches/001 create mode 100644 web/spiderweb/patches/002 create mode 100644 web/spiderweb/patches/003 create mode 100644 web/spiderweb/patches/004 create mode 100644 web/spiderweb/patches/005 create mode 100644 web/spiderweb/patches/006 create mode 100644 web/spiderweb/patches/007 create mode 100644 web/spiderweb/patches/008 create mode 100644 web/spiderweb/patches/009 create mode 100644 web/spiderweb/patches/010 create mode 100644 web/spiderweb/src/68k/68k.spider create mode 100644 web/spiderweb/src/68k/make create mode 100644 web/spiderweb/src/BUGS create mode 100644 web/spiderweb/src/COPYRIGHT create mode 100644 web/spiderweb/src/Makefile create mode 100644 web/spiderweb/src/README create mode 100644 web/spiderweb/src/README.DOS create mode 100644 web/spiderweb/src/ada/ada.spider create mode 100644 web/spiderweb/src/ada/make create mode 100644 web/spiderweb/src/ada/new.spider create mode 100644 web/spiderweb/src/ada/old.spider create mode 100644 web/spiderweb/src/ada/stacks.web create mode 100644 web/spiderweb/src/awk/awk.spider create mode 100644 web/spiderweb/src/awk/make create mode 100644 web/spiderweb/src/awk/tangle.c create mode 100644 web/spiderweb/src/big-web.ch create mode 100644 web/spiderweb/src/c++/c++.spider create mode 100644 web/spiderweb/src/c++/make create mode 100644 web/spiderweb/src/c/c.spider create mode 100644 web/spiderweb/src/c/local.guide create mode 100644 web/spiderweb/src/c/make create mode 100644 web/spiderweb/src/c/new.spider create mode 100644 web/spiderweb/src/c/tangle.c create mode 100644 web/spiderweb/src/concrete-kernel.diff create mode 100644 web/spiderweb/src/dijkstra/README create mode 100644 web/spiderweb/src/dijkstra/binary.web create mode 100644 web/spiderweb/src/dijkstra/d.spider create mode 100644 web/spiderweb/src/dijkstra/make create mode 100644 web/spiderweb/src/dijkstra/sp.web create mode 100644 web/spiderweb/src/kelem/ac.spider create mode 100644 web/spiderweb/src/kelem/ac_guide.web create mode 100644 web/spiderweb/src/kelem/indent-troubles create mode 100644 web/spiderweb/src/kelem/make create mode 100644 web/spiderweb/src/kelem/test.web create mode 100644 web/spiderweb/src/larch/l.spider create mode 100644 web/spiderweb/src/larch/lists.web create mode 100644 web/spiderweb/src/larch/make create mode 100644 web/spiderweb/src/master/Make.pretty create mode 100644 web/spiderweb/src/master/Makefile create mode 100644 web/spiderweb/src/master/WebMakefile create mode 100644 web/spiderweb/src/master/common.c create mode 100644 web/spiderweb/src/master/common.h create mode 100644 web/spiderweb/src/master/common.web create mode 100644 web/spiderweb/src/master/cycle.awk create mode 100644 web/spiderweb/src/master/cycle.web create mode 100644 web/spiderweb/src/master/junk.list create mode 100644 web/spiderweb/src/master/multitang.ch create mode 100644 web/spiderweb/src/master/newdefs.awk create mode 100644 web/spiderweb/src/master/nodups.awk create mode 100644 web/spiderweb/src/master/pathopen.c create mode 100644 web/spiderweb/src/master/pathopen.h create mode 100644 web/spiderweb/src/master/pathopen.web create mode 100644 web/spiderweb/src/master/pretty.awk create mode 100644 web/spiderweb/src/master/spider.awk create mode 100644 web/spiderweb/src/master/spider.web create mode 100644 web/spiderweb/src/master/tangle.web create mode 100644 web/spiderweb/src/master/transcheck.awk create mode 100644 web/spiderweb/src/master/transcheck.list create mode 100644 web/spiderweb/src/master/weave.web create mode 100644 web/spiderweb/src/master/webhead create mode 100644 web/spiderweb/src/master/webtail create mode 100644 web/spiderweb/src/nawk/make create mode 100644 web/spiderweb/src/nawk/nawk.spider create mode 100644 web/spiderweb/src/penelope/SpiderMakefile create mode 100644 web/spiderweb/src/penelope/a.spider create mode 100644 web/spiderweb/src/penelope/make create mode 100644 web/spiderweb/src/penelope/nesting.spider create mode 100644 web/spiderweb/src/penelope/processed-a.spider create mode 100644 web/spiderweb/src/penelope/scan_annotations.awk create mode 100644 web/spiderweb/src/penelope/stacks.web create mode 100644 web/spiderweb/src/postscript/README create mode 100644 web/spiderweb/src/postscript/WebMakefile.new create mode 100644 web/spiderweb/src/postscript/local.guide create mode 100644 web/spiderweb/src/postscript/make create mode 100644 web/spiderweb/src/postscript/outline.ps1 create mode 100644 web/spiderweb/src/postscript/outline.web create mode 100644 web/spiderweb/src/postscript/ps.spider create mode 100644 web/spiderweb/src/reduce/INSTALL create mode 100644 web/spiderweb/src/reduce/Makefile create mode 100644 web/spiderweb/src/reduce/README create mode 100644 web/spiderweb/src/reduce/make create mode 100644 web/spiderweb/src/reduce/reduce.spider create mode 100644 web/spiderweb/src/reduce/rtangle create mode 100644 web/spiderweb/src/reduce/rtangle.ch create mode 100644 web/spiderweb/src/reduce/rweave.ch create mode 100644 web/spiderweb/src/reduce/underscore.web create mode 100644 web/spiderweb/src/sml/leavens.mail create mode 100644 web/spiderweb/src/sml/make create mode 100644 web/spiderweb/src/sml/mason.mail create mode 100644 web/spiderweb/src/ssl/make create mode 100644 web/spiderweb/src/ssl/s.spider create mode 100644 web/spiderweb/src/turing+/example.mail create mode 100644 web/spiderweb/src/turing+/make create mode 100644 web/spiderweb/src/turing+/turing+.spider create mode 100644 web/spiderweb/src/turing/make create mode 100644 web/spiderweb/src/turing/turing.spider create mode 100644 web/spiderweb/src/webkernel.tex create mode 100644 web/spiderweb/todo create mode 100644 web/spiderweb/tools/Makefile create mode 100644 web/spiderweb/tools/depend.web create mode 100644 web/spiderweb/tools/excerpt/excerpt create mode 100644 web/spiderweb/tools/excerpt/excerpt.doc create mode 100644 web/spiderweb/tools/excerpt/filesplit.web create mode 100644 web/spiderweb/tools/excerpt/section.c create mode 100644 web/spiderweb/tools/shortindex create mode 100644 web/spiderweb/tools/tie/@read@.me create mode 100644 web/spiderweb/tools/tie/Makefile create mode 100644 web/spiderweb/tools/tie/cf1 create mode 100644 web/spiderweb/tools/tie/cf2 create mode 100644 web/spiderweb/tools/tie/cf3 create mode 100644 web/spiderweb/tools/tie/character.web create mode 100644 web/spiderweb/tools/tie/datadecl.web create mode 100644 web/spiderweb/tools/tie/error.web create mode 100644 web/spiderweb/tools/tie/history.web create mode 100644 web/spiderweb/tools/tie/io.web create mode 100644 web/spiderweb/tools/tie/master create mode 100644 web/spiderweb/tools/tie/newmaster create mode 100644 web/spiderweb/tools/tie/tie.c create mode 100644 web/spiderweb/tools/tie/tie.chf create mode 100644 web/spiderweb/tools/tie/tie.preamble create mode 100644 web/spiderweb/tools/tie/tie.web create mode 100644 web/spiderweb/tools/tie/tie.web,v create mode 100644 web/spiderweb/tools/tie/tie.web.dist create mode 100644 web/spiderweb/tools/tie/tiedoc.tex (limited to 'web/spiderweb') 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 +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 +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 +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 +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 + #include + #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 +> #include +> #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 +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 + 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 +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 + 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 +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 +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 +> @= +> 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 ; 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: +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 --> 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 +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. + +@= +#include +---------- + +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 "" +cleverly formated ends up being just "". (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 +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 +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 +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 +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 +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 +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 +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 +@= + @@; + for (i=0; i<256; i++) + if (to_ascii[i] != UNDEFINED_CODE) + to_ebcdic[to_ascii[i]]=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 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> + +<"{\\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 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 stmt --> ifbrace +ifbrace close else <"\\"-space> if --> if +ifbrace close else lbrace --> ifbrace +ifbrace close else newline --> ifline +ifbrace close --> stmt +(ifline|ifmath) stmt --> 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 newline --> preproc + preproc 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 + + question math colon --> condbegin +[ condbegin math ] (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 + +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 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 stmt --> stmt + +(open|lsquare) math close --> math + +math lbrace --> lbrace +lbrace stmt --> lbrace +lbrace close --> stmt + +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace stmt --> ifbrace +ifbrace close else <"\\"-space> if --> if +ifbrace close else lbrace --> ifbrace +ifbrace close else newline --> ifline +ifbrace close --> stmt +(ifline|ifmath) stmt else <"\\"-space> if --> if +(ifline|ifmath) stmt else lbrace --> ifbrace +(ifline|ifmath) stmt else newline --> ifline +(ifline|ifmath) stmt else --> ifmath +(ifline|ifmath) stmt --> stmt + +for <"\\"-space> math --> formath +formath lbrace --> forbrace +formath newline --> forline +forbrace stmt --> forbrace +forbrace close --> stmt +(forline|formath) stmt --> 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> + +<"{\\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 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 stmt --> ifbrace +ifbrace close else <"\\"-space> if --> if +ifbrace close else lbrace --> ifbrace +ifbrace close else newline --> ifline +ifbrace close --> stmt +(ifline|ifmath) stmt --> 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 newline --> preproc + preproc 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 + + question math colon --> condbegin +[ condbegin math ] (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 + +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 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 stmt --> stmt + +(open|lsquare) math close --> math + +math lbrace --> lbrace +lbrace stmt --> lbrace +lbrace close --> stmt + +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace stmt --> ifbrace +ifbrace close else <"\\"-space> if --> if +ifbrace close else lbrace --> ifbrace +ifbrace close else newline --> ifline +ifbrace close --> stmt +(ifline|ifmath) stmt else <"\\"-space> if --> if +(ifline|ifmath) stmt else lbrace --> ifbrace +(ifline|ifmath) stmt else newline --> ifline +(ifline|ifmath) stmt else --> ifmath +(ifline|ifmath) stmt --> stmt + +for <"\\"-space> math --> formath +formath lbrace --> forbrace +formath newline --> forline +forbrace stmt --> forbrace +forbrace close --> stmt +(forline|formath) stmt --> 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, `\.{@}' can be abbreviated to `\.{@}' 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} +\.{@}' 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]|. +% +% @= +% @!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. +% +% @= +% @!h:0..hash_size; {index into hash-head array} +% +% @ @= +% 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} +% @; +% @; +% if p=name_ptr then @; +% 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|.$$ +% +% @= +% h:=buffer[id_first]; i:=id_first+1; +% while i0 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(IMAXBYTES 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}', 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 +@ @= + pathaddname(*argv+2); +@ @= +@y +@ @= + pathaddname(*argv+2); +@ @= +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 + @; +@y +#ifdef STAT + print_stats(); +#endif + @; +@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}. +#= + 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: +#= + grammarfile = "grammar.web" + print "@*Grammar code generated by {\tt SPIDER}." > grammarfile +#y +# We use a special file to write grammar information: +#= + 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. +#= + 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 +#= + 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 + @; +#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; + } + } +} +#endif DEBUG + +@x module 106 +@ @= +#ifdef DEBUG +@y +@ @= +#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 +@ @= +#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 +@ @= +#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; kcat); 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 +@ @= +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 + @; +#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 { +# +# +} +#@ +# +# +#@ +END { +# +} + + +# #= +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!} +#= +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 +#= +#=/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. +#= +#=/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. +#= +#=$0 !~ /app1|reduce/#> {dumparray()} + +# #=print banner + +# #= + +#*=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: +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-- +- # + ## 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-- + # + ## 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. +- #= +- templ=length($2) +- i=1 #/ +- while(i<=length($2)) { #/ +- if(substr($2,i,1)=="\\") { #/ +- if(i= + +--- 799,804 ----- + tokentest[$2]=temp + tokenlength[$2]=length($2) + + + # The setting of attributes is as for all tokens: + #= + 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 +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 +! sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc + preproc backslash newline --> preproc + preproc newline --> ignore_scrap +--- 326,332 ---- + + # control sequence \8 puts things on the left margin +! # sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +! # changed to work with LaTeX as well: +! sharp <"{\\let\\idfont=\\reservedfont"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc + preproc backslash newline --> preproc + preproc 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 +#= + scrapfile = "scraps.web" + print "@*Scrap code generated by {\tt SPIDER}." > scrapfile + ttokfile = "outtoks.web" + print "@*Token code generated by {\tt SPIDER}." > scrapfile +#y +#= + 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 +#= + macrofile = extension "web.tex" + print "\\input webkernel.tex" > macrofile +#y +#= + 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 +@ +@ +@ +@ +@ +@ +@ + +@ 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|. + +@= +#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@> + +@= +#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 + +@= +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@> + +@= +#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 + +@= +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 */ + +@= +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. + +@= +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|. + +@= +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. + +@= +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|. + +@= +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);} + +@= +#include + + +@ And we need dynamic memory allocation. +This should cause no trouble in any \Cl\ program. +@^system dependencies@> + +@= +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.) + +@= +#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. + +@= +#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. + +@= +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. + +@= +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. + +@= +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 + +@= +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. + +@= +@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)) + @; + @; +} + + +@ End of file is special if this file is the master file. +Then we set the global flag variable |input_has_ended|. + +@= +{ + 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. + +@= +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@> + +@= +{int final_limit; /* used to delete trailing spaces */ + int c; /* the actual character read */ + @ + inp_desc->limit=final_limit=0; + while (inp_desc->limitthe_file); + @ + 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; + } + @ + 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. + +@= +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@> + +@= + 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|!). +@= +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 + +@= +@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. + +@= +{ + 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. + +@= +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. + +@= +{ 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|. + +@= +{file_index i; + i=1; + while (ithe_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. + +@= +@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 ; kbuffer[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. + +@= +@h void init_change_file(i,b) + file_index i; boolean b; +{register input_description *inp_desc=input_organization[i]; + @; + @; +} + + +@ 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). + +@= +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}. + +@= +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. + +@= +@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= +@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}. + +@= +@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|. + +@= +{file_index test_file; + @ + if (input_has_ended && actual_input==0) break; /* all done */ + @ + @ + @ +} + + +@ 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. + +@= +{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) + +@= +test_input=none; +test_file=actual_input; +while (test_input==none && test_filemode) { + 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. + +@= +if (prod_chf==chf) { + loop @+ { + @ + @ + @ + } +} 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. + +@= +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. +@= + + 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. + +@= + 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. + +@= +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. + +@= +actual_input=0; +input_has_ended=false; +while (input_has_ended==false||actual_input!=0) + @ +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. + +@= +{file_index i; +for (i=1;imode!=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. + +@= +@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. + +@= +{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 + else @ + } + 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. + +@= +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. + +@= +{ 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. + +@= +@h main(argc,argv) + int argc; string *argv; +{{@ + @ + } + print_ln(banner); /* print a ``banner line'' */ + print_ln(copyright); /* include the copyright notice */ + actual_input=0; + out_mode=normal; + @ + @ + @; + @ + @; + @; + @; +} + +@ 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@> + +@= +{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; kbyte_start; k + +@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: @; + } +@.\\id@>@.\\res@> +#else + switch (*j/id_flag) { + case 1: printf("\\{"); print_id((name_dir+r)); printf("}"); break; + /* |id_flag| */ +@z + + l 1512 +@x + default: @; + } + } +} +@y + default: @; + } +#endif LaTeX + } +} +@z + + l 2075 +@x + +@= +if (next_control==constant) app_str("\\O{"); +@.\\O@> +@y + +@= +#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 +else app_str("\\={"); +@.\\=@> /* verbatim string */ +#endif LaTeX +while (id_first + +@ 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\}}'. + +@= +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{}@> + +@= +#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}'). + +@= { +@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{}@> + +@= { +@z + + l 2442 +@x + if ((a!=' ' && abig_force) { + if (save_mode==outer) { + if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\P",4)==0) + goto reswitch; + @; +@y + if ((a!=' ' && abig_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; + @; +@z + + l 2632 +@x + +@ @= { +out_str("\\O{\\~"); + while ('0'<=*loc && *loc<'8') out(*loc++); +out('}'); +@y + +@ @= { +#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 + +@ @= { +out_str("\\O{\\^"); + while (isxdigit(*loc)) { + out(islower(*loc) ? toupper(*loc):*loc); +@y + +@ @= { +#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 */ + @@; + } 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 + @@; + } 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(); @; + } + finish_line(); out_str("\\inx"); finish_line(); +@.\\inx@> + @; + @; + out_str("\\fin"); finish_line(); +@.\\fin@> + @; + out_str("\\con"); finish_line(); +@.\\con@> +} +@y + finish_line(); @; + } +#if 0 + finish_line(); out_str("\\begin{theindex}"); finish_line(); +#endif + finish_line(); out_str("\\inx"); finish_line(); +@.\\inx@> + @; + @; +#if 0 + out_str("\\end{theindex}\\fin"); finish_line(); +#endif + out_str("\\fin"); finish_line(); +@.\\fin@> + @; + out_str("\\con\\end{document}"); finish_line(); +@.\\con@> +} +@z + + l 3137 +@x +@ @= +switch (cur_name->ilk) { + case normal: if (length(cur_name)==1) out_str("\\|"); + else out_str("\\\\"); break; +@y +@ @= +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\,$\.]'. + +@= +@y + +@ Section numbers that are to be underlined are enclosed in +`\.{\\[}$\,\ldots\,$\.]' or `\.{\\underline}$\,\ldots\,$\.\}' in \LaTeX{}. +@^\LaTeX{}@> + +@= +@z + + l 3159 +@x + out_str(", "); cur_val=cur_xref->num; + if (cur_val + cur_xref=cur_xref->xlink; +} while (cur_xref!=xmem); +@y + out_str(", "); cur_val=cur_xref->num; + if (cur_val@^\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€I h€€_޺€: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€v v€€€€\€€€i€J€€Շ€€€ €c€€ZK3m€€ê·Â€Â€\€€€i€€€S€€d€€€c€€&€<€ZLy€m(€i€Pe€€+€)^€@€€€i€€€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€€€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€HH7 j6€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€€€ 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*8 0fTEXTMPS €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€€€)%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€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€€ €€<€ȸ׫€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秨€€€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,_-€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€€>€€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;€ņ€€Vz c€€(o;€nD> Å¡](`Λ€6€€ €A€€c €r7€€€€€ €Ui^€€g€j}G3€€/|€€€€ €Eɳ€€:{sd€€84]s €"gn€Ҹ<€€T 5 b|€€€€€ b€A\t €i|1I€€€€€. +€ €^/{€€/*€y4€€€{€W0 €{0A.€€k'€€€€ €€qZ^€€€€€K3€5€€CS€€Z €€E€€J`€]€j€.>€€|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€€ €Hh€€Ô€˥€J>#9Y€6€'S€b€Tß°€€€€€|F€€GM€]€އ€€]€Dl?W€€€;G€€€_€ϒ€q€€€z€/€.€€T€€€G€€N"€€~€f€Ly €>Ö¨-$I=$€R€€€~.o U&€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€ €A؇AΡ€O€€{}(9€€A X€€ €€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Ë­PA 8€€€€{€€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 €m5 raj{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€€ ?€hAhpfn NW€+A0ar€ښ€€Jh€€KB#€'€,%€€€€€;€t€>j€3€~€U]2#4 'N€12€Q€_O`€€՞€€u^;?r€€€€]1€€w€#€r€€~X{€€€€€:M€\Q€&€€e€\\€.C|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€€€L l ÒŽC€€€H€€€€hQbWP€€X€+K€€0€€We€R€€€WcU€€bYIi.€\€€€€Do€€€)€€€€G{W€i€Q E€ 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€€€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€€](€;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$A mJ€€€€€€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€%€0z€(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€N c€'€0€ €€e€ʴ€Ö€€^bO€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€€UUR J[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€€€€€,€€+€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€€>€€€_t 2uÕ»h€€€€Z€H€€H€€L€€€˾€UQ€G€B/#€€U&p€o@€ڗ]€r€\€l€#x€€R€€\`P5A€_X\€#Ä€G9€€€ä`Z€\€C5T c{iPtA€GZ+€€€€€€4€s€ 0€€]f€€Yjָ€€€€9[S,€€^+€m Θt€ŗ€2€€]€€€€€€€€B 2梅€€€€խ-€€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€€A X€€ €€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€€€ +€€€+€|X B€%'€>/'€ 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€)€€€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$ {€€`s €€Fm c€[€S]€€€:|€€s€€€HÛ˜€eW€€H€؂ +€\rA€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€tL V€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#€€R g8€€€C{!TN€R€e€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-€9 e€~*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€€€€PC€Ô‚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€4 D|€€€€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€`€08 E€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€€{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€€€€€€€€€€€€€€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€€ €€€"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€ €+,^€€˾€€€]€€€€€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€€C c€3 J$€%U(]€?c€Z€4€ ={€Ya€90€f €€€e€€€U/8€X\*=d0€i€€€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€M z€€ 2€P€€€€&€nx€€X€€yl€€^xn!=€0€€O 0ql€<€€€+ӊ€€ €€ .€C€€€€€€€€€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€€€'€`€€bI8b Kq€€€€€€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|€€€€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ܠ€WDÌŒ€€€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€€X N)y€ r€<€€ѓw€l2€d€€M€[€€€c€€€(€G6y€z€€ğ€:€€€-A?Z€€€+N€\&€€;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€aN€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€€;€(Õ¥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€€€]]€€d H€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€€€€€€~{€€€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-€€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€€€4€P€€O €€ +€u]_€€G+r€#€€,G n2\€€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(€€€€.€L€FUޗ€€€Ë¡3?*7"€€€#€82€€X€€?€€`Xp k€'€€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€a M€%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 € €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'€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€C o€Y;.€-Ê‹e€€E}€j€€ל€q€€{€€€€€ۢ€ €t؟€x€ǫ€ @Ri\/@€d€˼€8€SJ@€€ {€[!€]€ *€€€E€dX K; €%€€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ۭ€€ €€ € + #€€€€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,€€|€:€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,֠€€p€ӎ€€€€€]€€rs€t€€#v€€ )9g€UKK_€X€|€Dt7s€,a€/ €X€JJ€J€6€€(€€GJ€€€;7€\@^€€€€8€€€€iQ€€€y,€4Q€IA€€ +€~,€€€k|3€ Y€:€€€%€€€s 8€€€€€=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€€~€€€€€$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€€ڨ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€g 0€€\€€0€€F€€Ǝ€A€€m€€€€€€€€ˎ€€€€€€jsB€€€€€c8`@)u€€IÔ¹W)휧=€€€su€O€€_€g€~E0€ 1@€G^€€oRO€€€€z33Ë€€€G€k€€y N€:€;€€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€€;€k b€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Þ›n MQ€€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€€€oY r€€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€€€G I€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€`€!€€ɜ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€€ €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€WdW w[Æ„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€€€,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/€€Î€ +pX€€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€%€€€€€€yc€€€eC~€R€€x€͈€€€r€€e€€€^€€€"-€€3e*€{Tav€€Ķ ޶€â¦EǪ€€€!€€€€€€€xG€?€"€€b믊€*€z €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€粡€€€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€:;Ι€€.t€€ €6 M"'!€'€~€]`P0 +€€Xw f€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€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€€€€X EdQ€€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€&€€& €t 7€[€}€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€€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€T NN€7€€€~/agP.€[$":z€Yb€€€€€"vQV"D'€+b€aIdq€€€i€€€€€€YZ!€.I2€€<€g@€€€€€€€?€€€€€S€ €€€?€0h€€€€O bV$€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€€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舊}€€€€€S k€€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,%€€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€?€€g h€0Çš"€€€;|€{!€€€(€€€€€€€€€-3Ïxjf5Y€Z€€€€h€x3€L€e €5€€€€%J€€csrr€€€D9Û<€H€€:€€€*€{&f€aF?Æ´€x€€)ww€Uw#8€%98:9€>m€.€€€€€$i€€\€{jX€;u €$€€5€T€p\)ÄD5G)€€€€€€wճ€3€8K€2l(€€€r€lÆA F€#€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€€:(# ܵ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\€€€€€J U"H€€€K€ €p€E]/R€&€@€€`€[j€s€€€_.Qe€€N€€€€€;€i€1f€€h €8r€€€V€Í$€ 0€2€€€€€yR€A€LcVr€lvA#6Ѐ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€€ X cL@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€r Ze€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€€€€€€t d"€€. €€͌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€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€֫[€€€V 4€đ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€€h q€€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€€€€~€(€€`€€€€y€€€S€€٦€€€€A€*€RJ€€€˧€€€€D€€1Ĭ€&F€Y€ĺ€€W€€$,,€7€€€`€ €@€ €@€€€_€€€O€)€€y€\€€˿'€€€PR€€€G€€€€€€F€€0€€€€MaN€:€€€DP€&€5~€€€€€€J€€[€ؘ€€€€0%€€0~€€Py2€qF€€€€_u8€ €€A€F€€€4Lz^€€€€s|L!YHHaTL€€\€€€rR€4€PL€€h?2e€€€€UYf€€€€>€׵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€€fE d€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<€€€€€€€€€. +€€€||€€€€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€€8 X€^€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;T Fw$€?€€?€,=;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€$V6L 3€€~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ə€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€€&€€€|€€€€€-€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?KA x"€`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€8 fѺ;-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€Ƙ€|#€€~€An 7€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\PQ Q€€?̶€€-€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€€gnn N€€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€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€!€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€€`|€™M y€€W€-{7€€ab€v€€€ lists.webxmbolsc€€=€K€€TEXTMPS €m5€m5&€€€€€ +N)y!aM€\m =€€€€€€€€€y€NeZ€€€€€€a€€€K€€€€C€€€€€v 8€€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€yr t +€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"Lu€€€€n€€€€€€€€€thÉ€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€+€€˖€€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€€€€԰*€E D€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€€€˽€€€€_}}€€€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€€€ֿ€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€.€UP 7y&€=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&gw M€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€€€TJY d€€€"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ϳ€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€€€€€xW 2€Ó”{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€€ +}€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€€€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€r e€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€;€€€O 5j€€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€l x€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 +€€ݚ€€{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€€€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€€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:u vYR€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€6> €€F€€€€=€ɶ€€?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€€|/€€.€zdf€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|€€€€€|€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€€;€€€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€€_€u uN€€€€]€€€€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$:€IEmycoc jÒ€€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€€€€qi z€'€€%€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€€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€€€ÂJ!$#Þ‰4€€€€%e€€€ multitang.chxlsc€€=€D€€€TEXTMPS €m5€€EH€ +€€€€ X€u€vb€€€€f€€t€Ǒ€€€! €MC€|Y€2" K€€€€€€gv€aO€€€€€ze€€€4: +P€ql€€>|€S€"€€V6*w€3€€€c€€€1f€R€€€€F B€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€B 6A €€€$€€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€€€€€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€€€€€€< ȭ€\€ڹ€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 €% J nݪ€܄€€€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€Ή&€€€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€a 3|€€€€^€€€€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€.T s€`€€?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€#€€€€[ᬉu5€#䕞€4€€]R€a€j^3Y€€6€€€€7 maÊœ€€ `K<€o€$€€3€N€€Ԉ€€€€,€€+FRp€€!3p€€"€$8f €se5>€Qr{€€€~€ €€€=€€€'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€Q r6€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^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€nvX#€Ƞ{^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€€x t€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Ø™€€€ €\€;€€€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€€€€€?€€€=+€€€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€€€€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€€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:䀀崴~€傳A V€€€€.€€€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€€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€€€€€€€€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€€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€~+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€€€<€€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€€€€€€€€{ת€€€€ԑ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€Ð4 P:€€€*€€€€€€`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€_€:V Y€Â€Â€Ô +€€@FB€€€€€€O€ +€€€r€€X€x€~.€ +€€9HB@bZ`7€$€l€€3€€€€€€€"€魙€hTcE6pK€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€p NWUu€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€€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€€€ږ€`€_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€€€€І€€_€%€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棒ex zb€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€+€€€€€€€[€€€ڇ€€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€"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;€€€€dP h€|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€€€u n7bnp4%€€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<€€t M€^3I€€€€0€€HG6o€€€H0Ε5 €lM€n_€€[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 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€€€€€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€s H€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€€ֳ伯€€€€[€€€K ir€€€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€€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€€€€€*€*€€€@€€€€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€€Q Rvf€ €€ 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!€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€€gh N)€€ €€€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€€€€D a€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€€€€€€€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€€€ €f f8€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.€&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€vb S€€€-€€ŵ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€ Ծ€i Ny|€€€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€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 €vi T€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Ï ;4Lq€Uz€8P€€€€€ p€€€-€`€ €€Ԝ€3^€€I\€€€€L'€Cf€€y@€€4a€€€J €€YL€€€€|€lY€€d¨֦f'S€0#ʺ"€€I€€ €d€d l€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€€>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€XH b€^€€€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€{'€{€H m +^>€€€!"€€€.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~Ó¨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€€€F xD€€"€€S€~€|€€€€€€€gA€€(,€e€€€è€ǯ)@12€€€€.€Y؄€Xv€ M€L€€2ri€€€€€€^€H€,E+€3€ €€€€2€!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€Es€}€J"E€+€€€?€€€,h!€€T9€€€€\€€o€|ß“Xm€€€€€€S€o€ئ€3O#%5€€6P€€€i€€€€<,€€€ @€=€€€M€ w 1€€€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#q€9S +"=_€€€?€X#V€ɹ€€€2€€€I5€€ֺ€€ 6€€o!Hjf€€F€€w€_€ŧ|,`€€€UE€€€€&€€€€€€9€€YU€€€€/U€€€€Z€€€€€6}*絴€7xJV€€vU€֧€R€*€€i{€K[5€r(€^€€€[€€€>h I€]€€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€BA 6€ €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€€~€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€€\€.€€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€€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€€€€€€€€€€€€(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€€€ €€€€Éš)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€€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€%€Jg 9€€€\€€€=€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€€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€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€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€€€KÇ‹t€ €€-~OSU€€GU€€€z€€^m€€VF€?2}€..€€€€€`'€3€€~€q f€€€€€€€€€€~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)€€€€€€ €€€€~€€€€Li?€m €€DQrN€ €Yܢ€€€€€€q0€@}€€€€$4P€€ zc€*H€€€€€€€€€Ø”31€o€m€€<€^€XW_€€€k€ €AI?€`€v€€bn+€€7O€B€€Í€p€€ €€€€4€€€zK€D€|€m€€<(1I 7€€@€€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€€€)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€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$€€€€.x D€ +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|€x X€€:€€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Ë– €€€m f€€€€ɡ€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€€€€€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`S Ve€€€€€€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€€€€"€>€€Äfk"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%} €€€knRxɘ€€€€€€@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€-*€€€|Ȁ€€I C€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€€€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€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€€?€€€€€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€ʇE j€€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€|€G R€€€€€{€€€€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€jƜ€€€€8€E€M€/€€$'€€€€]€*<{5+!€€€6€€4€€€€€€€ €5€yÕ¦4€aV€€€€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€€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€€€̩€€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€€@,€€€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€~€e Tv€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€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€€?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€€€g iRg€J€/€3 a€€€?€a€f_ 8 A€€€€€€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 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€|€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€y J€€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€€€€- €,e NW€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*b 6€`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 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\€戱wÇ‹"?nlQo€$€豃<@PO#€€€u€S€€€€g€$€1N€t€€€€7З€Q€€€€?f€€€€7€ €c~*€_:€€c"€k€€ t€<€€€ € +€ +€+g:€@]€Z€€€€L€€ WebMakefile.unix€€€^€€TEXTMPS €m5%€m5%U €€€q NW€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€€7 Sfm€(€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€€€oi€€€[€ €'+€€€7k€€ٔ€€_({*,€8Xx15€€€€#€9€4 YG|-€€€և€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€€`€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:€€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€€€€€€~€€€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€||€€€:€`€^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€VS0 Te€€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̧6 n€LÞ­^€q@€*A7€€€€€i€Pj€ i€$€€ܑ€ɧ€]€@€€€r€B€€€€€€h@€D^@€€. M€€\€€x€,€€€ڰ€€CÚ¤Z€ €€€C€€$€€€ €€€€€0€|^€€1X€p? +stacks.webfilens.awkĪ$j€GTEXTMPS €m5€m51R€Z€ N)y€€€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€€€ +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!€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(€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€̹~€т€€€R NW€€€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€>փ€€€€JT5€€C€l]€\5' U={6€€>{€B€Lf€€€yM€tm`€€€_€€€€:m€€€-l€€€b€[€€>€q€nX(Ƿ€€€&€€'€i€k<€€˂€€€g3€;5€€€€€z€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€€€€€€€€€€&€+€%_\€€€€€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€€g 6P€€€€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€1 N7y<€|€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;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€>€€€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`s Z€€^€€€€€€˘aHň€96+ n€L€+FU:r€?yDbL€€€KI€€]Ën€€z€Nk{J€f€€D€G €n€m€ Z.€€B€€€EN€€€€Я€@€€͛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€€€(€€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€€:€[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€€€$€€€€€-€€f k€'`€€€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€€@€€!€€rF G€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€€?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€^€}€€!kR+fnE€(€€€€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€la 9dy&€€€€.€€.€[€€:A€€€€€€€€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€€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/ €€#!€€ ]€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"€:ʋ€€€ €€€y w€€cK€Y€€@€*€fr 7€€€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€€€5 x€Ʈ€€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&€]~X j=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€<€€€€€€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€ߣ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€X s}sO€>€AQ܇^€_€€̒€LϦ€€iğ€€"~€€€N"B€'€€€QO€$1rd+€€H€€€€a€€€€€€0€€€Cup'gS!>€€€7€€€Ƅ€€]€€۷€7€€€ElN€ꮋ€€€€9/W€€ €€$*€#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€ 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"€b jZЬ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€€€€€^? €€€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€€€83TR0 m€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€€D5 E€€€€^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€\>€̉€€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€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€€Q 4€€€€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€€€€욒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€R hkܢ€?:€€"€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€€€Z p €G1@J€9€ۓQk€wc€Pə€q€€€€i +'€€@8€€€€€€€|É™}€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Ó Å€€_€ €€߫€€€€1 z€€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€€P c6b̄€ד€€€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€€+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Þ‘;€€ʻ€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€€€€€€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€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€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€€€€e hSJY$€H€€!?5€€€€€ᇷ€€€H€€€(€€>€0€:€1` ^ 5€>€€[€€浚€,€/ €€Bn&Ò‘|g€j€+n€€€€€€€̱ܟ+€o€=€6u€€nl€X€€.Ge€G2)=€€€€V€€ۉW€_R=q y€€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€€/ €€€€€€\€~€€€€€;׷€€€€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ܫ€€€€+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}SCSk Qj}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€^€|€€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€€eI 0€)€€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€€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Ռ€À€͞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€ysk e<€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€€€*€|€[(gn€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€€€€€€Í´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€€€€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€€€?€€€#€€€€€.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€€<€€€€€G€€€€=~؛€€€€N€g€HX4?€o,5U#€€€€GL€€3y€Уt €€ €€€€€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€€1ÇŒS€<€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€W v€€V€€<>€ +%"^€G)€\€9 w€€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€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>€€裗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€€~Ç· €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€

€€ &€€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{€€€€€€€ 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€€€€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€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€€€€€#€€:{€:{[€€4 8€€>€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 [+€€G75oZ S€€€€= +.{€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€€€€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€€;€>V y€€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€$(€€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€€5€€ƨ€W€(€ íž·€l€TV€ €1€[u3€€€€"S€W€)€€€€€€€=€€ͫQ#€€bo~€H.€yR +€bog€Q€W€€€v€;OL€€€€n,€€€€l 6c€€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€€€q m€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€€€}ч€€€€€gw€€€4€€€1€CV€%y€€€?€l€y€€€€#€#€{€€F€€}€#€€€wTvG€€:€I#€€€€)€€€€U172>:B]_€€€)+^̜€€ ]G?€€€€€D€€QTx€€€€ €€€€€€€€€€€€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.€ڱOd R€`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€i 2€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€€€€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€€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Ûž\@€€D€Wc€Ѱ€y€€€E€€c€w€€{[€Lx?€€[Pe7f€0€€€n€€7€€€(W€€KCW€eF€€€€U€ZB€€<€Jx`'€€€€€w-€€X€€*€€€€l€ꬺγ€<€€€€€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€#€Ø‘[€€€>(€€#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/ €€#!€€€;€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€€€[&v MTI€€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€€|Ê&؆€€€€`€€€€€€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€:€€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$(€ח€ €€€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€€€€€€€%€`€€`€E€€€€f€€[€€€€hG}f€€€€ٙ٘€P€€2W9€n€€3€€Th€€vWUy€^€€b%f€zl€a€眗€'|!vH€€€€€€€+€€€€vj€v€€Y€|€€€d€€€€€€€€d€€€t5Y€€캧€"-H K€]€€4 €)€€w€€д€ޤ€d€€€ €€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€€€={sD t€ C€€€J€€L€M€ €|-kFP+€6R v{€&€€€€€€B<,!ul€'@=€=t€2K#%)€Ԛ€4S€€C&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?€€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€€€€*€€€€€€€€€˷€ €-€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€€€€€€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€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ޒ€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€€)€ Ӗ€€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€;€€˙€€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€€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€€€€€€qaW€,€€€€^€€€€Tb2€x€xM€€*C)=F+L"€€€€ € _4€oxp€a€€€ +€€€a€a€€€€€7€.q€c€€€€€ 3 €€€€€€€i€[?€?€€€€€1 7€€€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€€€€;€€€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*rrig€€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\€>€ +€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%€"m Z€€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€€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€€€€ €€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€?K 0€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€ €\xfl yl€Ͷ€͢€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€€€ €€g 1 €€Ҁ 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€w b€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€V d5€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€+@€:€€€€-€€;>˳@€ €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-֊€€ +€~ű++€€€€€€€€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Ѣ€€FLK s€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}€}€€H R2bEln~€'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€ +€€€'ٿ€(€׌€2Է€€€0wR€^ €€€€ph€Z€€€€ M^j€€€€€V€Q€OE€l€€]w€€>€{€G€€€/f€c +€€ї€[ߪ€|Iy4w~€€R€J€€€€'€v S€€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€€€€€\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€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€€€€€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€*€€€ €J.٠€€x€x€v€:€€€€€€>G€€€tPL€c€€"1̃c1€՘€H 3b€€€€Ä€€H 3€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€ï°§N€٦€€€€€Jw€€M€8YCo0€zW€€[€F€€€5ރ€"€€;È„<€€€€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€\€ €€$€€%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= Òº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?Ȼ€€€FE q_€€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#_€€€̳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€€$€#€€€c o€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€€€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€€€€I N€€€€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ݵ€€}€ +&€€€€€€€€~€€€€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€€€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€^*€.€€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/€+€g H€€€% €FwÈ­+€r€r€;w€€€€+€€j€x€ꔳ€=€z€€É|€€€€€€€€€€€€X?€ €€€€D€9€qF5>€T€qI€Q€2€(€€\€pÇ„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€ӫ€€€'[€€€€.€ 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߶€€€€J c€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*€€f Am0XP9€%€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 €€€0 j€€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€2 W€^€€€€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€€€€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€€€€nLa>Ah€,€ap€6 XeQ€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^u nuG€&€€€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€f3nÇŠ#.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€€€€€€€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€€€€}€QX€€€O€1w€€€CU€ =a Q€: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€ri R€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€€€º€€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€€€€V€€mh^K€S x^€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€€w 5Â€Ó Â€&€€€€€€#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€} €€Nqm E.?€€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€$€€€€€€€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€€}€€(€€-,,€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€b w€€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!€`€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€€€€€Έ)€ €€€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€׬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€€ˣ€€€€€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@.ͧ€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 Ö—Dy k€€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ġ€€€h'€rD샤#€€^€€€€;€€€?Dsbm€j:€€~v€֕G€a€<€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€€€€`L3 q€€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€€€ €€€#W€€€€~ 9%€€€€#€€€u€J€€Ο=3}€˰€€€€€i€€€~€€y€€<€;€qKm€€tY€€.[XU€ZRZ€€€€U€€€€S€€€/€€N€€€€}€€€€€߆€Os€€€€€O€€€€€Ü€€ €s6€ӿ)€€€Ӳ.˾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€+€֤€€€<€€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€€€=€˺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+€2 VTC€€€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/=n 7AG€€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€€€€€-€;|€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€|€€5 kk€€€€€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€€̄iv 5b)€\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€ț€€€€€€in vb€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€€€g A€€€$€€€€€ +\[ 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€€€€€€€€€|߿€€€J G|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€€e€€r€ €X€€ €€€&\€k€€€€Ɩ€€€€rTvy$€€€€€PD6`[€€.;^|\€r|I€€1€€}€€€δ€H€€€€€qtI€€L€wܸjJ€€ǿ€_€€€,f€+t€2€€€€€u\OYB€€$€/€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€€€Ý€€>^€€l X€€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€€€€€€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€W bV€€€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€€€cWv€mE€7€ճ€€€v€€*€€~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€€€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>€€€€€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€-€€€)'€€&€€€€;€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€%€8 D€g€nj}€€€4u€€A€0B-€ujH€%€€J€€€€€7>€ +€€€s€€Cy€5K€€T€€€i€;O€€d€€ -j&€ ?€€W€=y f€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€€€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€€€r w€;€€€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€€€€€€>€€?€^?€€€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€8B r€€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€3€H€زqE€h€a€€ÙG^€s€tP2€ €€€€~Q#€#(€FP€€wP€KÔ…YJ€€w€9n€€ #€LɎ€ +€€8È»z5ÖŒ0K€IfA€€?;R}€€|€€€l€ԥ€€€€(€㩥 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€€€>€<€€€ €€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€%€Pe x|'€€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€€€€'€€!€€€€€€€€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€€€€€€}€?€n;€Ag€€€n€n€€n€€ʧ€]Ӝ€jW€€€7€€€€€g€€€€€>€=r+€€z+€h€€拿€€€:!r€€€z€€h€€~]€€Ñj€\9€^9Z{€?€^€Q€€€€€Gk€€€€ Op5|€")uD|€#€€xV€€€€€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€€€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€€~€€U J€€€€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€€S3 2€€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[€€€€>i>A;€€€>€6€/€`€€€€€€€€x/€€€€N +'€ €ձ€)€Rh€€TJ€!€j€o€€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€€ t€OWOW +€€"€€€x€o <€p)€€€€z€!€€€ HLA€㋹jV€€€€€€=L1€mFhNX Eiu_  €€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€€€]€€ȸ€€^€€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€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€€€€\5k 3€ 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>X 7€ 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€i 0€€?c€;}$€s}?3FRm%€€P€É´s~€{€€€k€€€,€ €€€j 0€*€€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€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(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^€€ÇŠd€€€€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€UO Dsȳ €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Ŀ€€皚€{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€u w€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€€€ã¥Â€^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 +Subject: PC implementation of Spidery WEB +To: Norman Ramsey +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 . 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. + +@= +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. + +@= +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: + +@= +common_init() +{ + strcpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "); + @; + @; + @; + setting_up=1; + @; + 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. + +@= +common_init() +{ + strncpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ",128); + @; + @; + @; + setting_up=1; + @; + 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. +@= + 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. + +@= + pathaddpath(getenv("WEBPATH"),';'); +@z Module 28 Sun Feb 14 01:17:40 1993 + +@x Module 70 Sun Feb 14 01:19:06 1993 +@ @= +#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}. + +@= +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} + # ## 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} + # ## 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 "@ @=" \ + > grammarfile ## avoids overflowing \.{WEAVE} of \.{WEAVE} +! # + # + 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 "@ @=" \ + > grammarfile ## avoids overflowing \.{WEAVE} of \.{WEAVE} +! # + # + 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. +! #= +! 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. +! #= +! 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) { + # + } else { +! temp = sprintf "'%s'", $2 + tokenname[$2] = temp + tokenlength[$2]=1 + } +--- 772,778 ---- + } else if (length($2)>1) { + # + } 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 \## + # + 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 \## + # + 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. + #= + field[pos]=$i ## save this field to compare RHS + # +*************** +*** 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) + } + # + # +--- 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) + } + # + # +*************** +*** 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. + #= + field[pos]=$i ## save this field to compare RHS + # +*************** +*** 1557,1563 **** + if (negation==0) { + test[pos]="(" ## open for a list of good alternatives + } else { +! test[pos]="!(" ## open for a list of bad alternatives + } + # +--- 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 + } + # +*************** +*** 1635,1644 **** + # + } + +! # Wild cards are easy to process + #= + field[pos]=$i ## save this field to compare RHS +! test[pos]="(1)" ## anything matches + highwildcard=pos ## we don't really need this? + # + +--- 1645,1655 ---- + # + } + +! # Wild cards are easy to process, but we do have to remember that +! not even a wild card matches a scrap of category zero. + #= + 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? + # + 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 **** + # + } else if ($2=="pseudo_semi") { + # +! } else if ($2 ~ #=/[a-zA-Z0-9]+/#>) { + ## we recognize no other names + print "Error: unknown token species:", $2 + # +--- 576,582 ---- + # + } else if ($2=="pseudo_semi") { + # +! } else if ($2 ~ #=/[a-zA-ZA-Z0-9]+/#>) { + ## we recognize no other names + print "Error: unknown token species:", $2 + # +*************** +*** 1200,1206 **** + that an item of ilk |fish_like| will get category |fish|. + + #= +! 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 ($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| + # +! } else if ($i ~ #=/^!?[a-z_]+(\*\*?)?$/#>) { ## |cat_pattern| + # +! } else if ($i ~ #=/^!?\(([a-z_]+\|)*[a-z_]+\)(\*\*?)?$/#>){ + # + } else if ($i == "?") { + # +--- 1490,1498 ---- + for (i=1; i<=NF; i++) { + if ($i ~ #=/<.*>/#>) { ## should be |trans_pattern| + # +! } else if ($i ~ #=/^!?[a-zA-Z_]+(\*\*?)?$/#>) { ## |cat_pattern| + # +! } else if ($i ~ #=/^!?\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/#>){ + # + } else if ($i == "?") { + # +*************** +*** 1632,1642 **** + + #= +! 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 ---- + + #= +! 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 + # + 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 + # + temp = substr(temp,2,length(temp)-2) +*************** +*** 1836,1842 **** + alternate = tok[j] + reduced[alternate]=1 + } +! } else if (temp ~ #=/^[a-z_]+(\*\*?)?$/#>) { + # + reduced[temp]=1 + } else if (temp != "?") { +--- 1836,1842 ---- + alternate = tok[j] + reduced[alternate]=1 + } +! } else if (temp ~ #=/^[a-zA-Z_]+(\*\*?)?$/#>) { + # + 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 +! # 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

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
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
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
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 +token - category unorbinop tangleto +token * category binop +token / category binop +token , category camma translation <",\\;"> +token ( category open tangleto +token [ category open tangleto +token { translation <"\\{"> category open tangleto +token ) category close +token ] category close +token } translation <"\\}"> category close +token : category colon tangleto <":"-space> +token # category unop translation <"\\#"> tangleto +#token ` category unop translation <"'"> mathness yes +#token ; category semi +token < category open tangleto +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 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) (sym|math) --> math + +#open close --> math +#math semi --> unop +#math lbrace --> lbrace +#lbrace math close --> math +#lbrace math close --> unop + +# There are rules for if-pseudo-instructions +# + if (sym|math) --> ifmath +ifmath math ignore_scrap --> ifmath +ifmath stmt ignore_scrap --> ifstmt +ifstmt stmt --> ifstmt +ifstmt else if --> if +ifstmt endif --> stmt + +ifmath else --> ifels +ifstmt else ignore_scrap --> ifels +ifels stmt --> ifelstmt +ifelstmt stmt --> ifelstmt +ifelstmt endif --> stmt +ifels endif --> stmt + +# For instructions +# +#-- pseudo instructions +(dw|pseudo) <"\\"-space> --> inst + sym* <"\\"-space> (equ|dw) <"\\"-space> (sym|math) ignore_scrap --> stmt +# dw <"\\"-space> (sym|math) ignore_scrap --> stmt +#-- CPU instructions +<"\\OPbox{"> opcode dot post <"}"-space> --> inst +<"\\OPbox{"> opcode <"}"-space> --> inst + +#-- ext instructions +# + ext <"\\"-space> sym* --> extsym +extsym camma sym* --> extsym +extsym ignore_scrap --> stmt + + glo <"\\"-space> sym --> glosym +glosym camma sym --> glosym +glosym ignore_scrap --> stmt + +#sym* camma sym* --> symlist +#symlist camma sym* --> symlist +# (ext|glo) <"\\"-space> symlist 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 + label label --> sub_label + sub_label label --> sub_label + +# Statements +# +sub_label pure_stmt --> stmt + label pure_stmt --> stmt + pure_stmt --> stmt +#stmt pure_stmt --> stmt + +stmt stmt --> stmt + +#labeled_stmt pure_stmt --> stmt +#stmt labeled_stmt --> stmt +# 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 @. + 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 ' (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 end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin 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 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 continuation ending --> stmt +beginning ending --> stmt +# beginning (stmt|ignore_scrap) --> beginning +beginning stmt --> beginning + +case <"\\"-space> math <"\\"-space> is --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation stmt --> continuation +continuation continuation --> continuation + + +declaration beginning continuation ending --> stmt +declaration beginning ending --> stmt +declaration ending --> stmt +declaration (declaration|stmt) --> declaration + +else --> continuation +elsif <"\\"-space> math <"\\"-space> then --> continuation + +exception --> continuation + +generic declaration --> declaration +generic stmt --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen stmt --> beginning +ifthen <"\\"-space> math <"\\"-space> else --> ifthen +ifthen <"\\"-space> math <"\\"-space> close <"\\"-space> if --> math +ifthen <"\\"-space> math <"\\"-space> elsif --> if + + +is --> math + +loop --> 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 stmt --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + + openlabel math closelabel --> math + +or --> continuation + +private --> beginning + +proc <"\\"-space> math <"\\"-space> is <"\\"-space> unop --> math +proc <"\\"-space> math <"\\"-space> is <"\\"-space> separate --> math +proc <"\\"-space> math <"\\"-space> is --> declaration +proc <"\\"-space> math <"\\"-space> do --> beginning +proc <"\\"-space> math terminator --> declaration + +#record <"\\"-space> at <"\\"-space> math terminator --> beginning +record --> beginning + +select --> beginning + +semi --> terminator + +separate math --> stmt + +stmt declaration --> declaration + +stmt stmt --> stmt + +stmt ending --> stmt + +when <"\\"-space> math arrow --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt ending --> ending +whengroup stmt continuation --> continuation +whengroup stmt 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 end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin 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 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 continuation ending --> stmt +beginning ending --> stmt +# beginning (stmt|ignore_scrap) --> beginning +beginning stmt --> beginning + +case <"\\"-space> math <"\\"-space> is --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation stmt --> continuation +continuation continuation --> continuation + + +declaration beginning continuation ending --> stmt +declaration beginning ending --> stmt +declaration ending --> stmt +declaration (declaration|stmt) --> declaration + +else --> continuation +elsif <"\\"-space> math <"\\"-space> then --> continuation + +exception --> continuation + +generic declaration --> declaration +generic stmt --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen stmt --> beginning +ifthen <"\\"-space> math <"\\"-space> else --> ifthen +ifthen <"\\"-space> math <"\\"-space> close <"\\"-space> if --> math +ifthen <"\\"-space> math <"\\"-space> elsif --> if + + +is --> math + +loop --> 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 stmt --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + + openlabel math closelabel --> math + +or --> continuation + +private --> beginning + +proc <"\\"-space> math <"\\"-space> is <"\\"-space> unop --> math +proc <"\\"-space> math <"\\"-space> is <"\\"-space> separate --> math +proc <"\\"-space> math <"\\"-space> is --> declaration +proc <"\\"-space> math <"\\"-space> do --> beginning +proc <"\\"-space> math terminator --> declaration + +#record <"\\"-space> at <"\\"-space> math terminator --> beginning +record --> beginning + +select --> beginning + +semi --> terminator + +separate math --> stmt + +stmt declaration --> declaration + +stmt stmt --> stmt + +stmt ending --> stmt + +when <"\\"-space> math arrow --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt ending --> ending +whengroup stmt continuation --> continuation +whengroup stmt 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 end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin 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 continuation ending --> stmt +beginning ending --> stmt +# beginning (stmt|ignore_scrap) --> beginning +beginning stmt --> beginning + +case <"\\"-space> math <"\\"-space> is --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation stmt --> continuation +continuation continuation --> continuation + + +declaration beginning continuation ending --> stmt +declaration beginning ending --> stmt +declaration ending --> stmt +declaration stmt --> declaration + +else --> continuation +elsif <"\\"-space> math <"\\"-space> then --> continuation + +exception --> continuation + +generic declaration --> declaration +generic stmt --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen stmt --> beginning +ifthen <"\\"-space> math <"\\"-space> else --> ifthen +ifthen <"\\"-space> math <"\\"-space> close <"\\"-space> if --> math +ifthen <"\\"-space> math <"\\"-space> elsif --> if + + +is --> math + +loop --> 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 stmt --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + + openlabel math closelabel --> math + +or --> continuation + +private --> beginning + +proc <"\\"-space> math <"\\"-space> is <"\\"-space> separate --> math +proc <"\\"-space> math <"\\"-space> is --> declaration +proc <"\\"-space> math terminator --> stmt + +record <"\\"-space> at <"\\"-space> math terminator --> beginning +record --> beginning + +semi --> terminator + +stmt stmt --> stmt + +when <"\\"-space> math arrow --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt ending --> ending +whengroup stmt 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 +@@; +@@; +@@; +@@; +@@; +@@; +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. + +@= + + + + + + + + + + + + + + + + + +@ To implement |empty_stack| we return a stack of length zero. + +@= +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. +@= +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|). + + + + +@ @= +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; + +@ @= +function topit (s:stack) return element + + + + +is +begin + if s.l=0 then raise underflow; end if; + return s.a(s.l); +end topit; + +@ @= + 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 + +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 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 stmt --> stmt + +(open|lsquare) math close --> math + +math lbrace --> lbrace +lbrace stmt --> lbrace +lbrace close --> stmt + +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace stmt --> ifbrace +ifbrace close else <"\\"-space> if --> if +ifbrace close else lbrace --> ifbrace +ifbrace close else newline --> ifline +ifbrace close --> stmt +(ifline|ifmath) stmt else <"\\"-space> if --> if +(ifline|ifmath) stmt else lbrace --> ifbrace +(ifline|ifmath) stmt else newline --> ifline +(ifline|ifmath) stmt else --> ifmath +(ifline|ifmath) stmt --> stmt + +for <"\\"-space> math --> formath +formath lbrace --> forbrace +formath newline --> forline +forbrace stmt --> forbrace +forbrace close --> stmt +(forline|formath) stmt --> 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 + +/*: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"); +} +#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(31byte_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){ +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=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_loc67108864)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_first67108864)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=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_firstdummy.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 +# 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 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 (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 stmt --> structbrace +structbrace rbrace --> struct_head +structbrace 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 --> 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* ] (lbrace|decl_head|stmt) --> fn_decl (lbrace|decl_head|stmt) +[ (simp|decl_head) <"\\"-space> math* ] (lbrace|decl_head|stmt) --> fn_decl (lbrace|decl_head|stmt) +# The following statment will always have braces and never be tagged +fn_decl stmt --> stmt +math colon fn_decl --> fn_decl + +(open|simpopen) [ stmt <"\\"-space> stmt ] --> (open|simpopen) stmt + +lbrace rbrace --> stmt +lbrace stmt --> lbrace +lbrace tagged_stmt --> lbrace +lbrace (math|simp) 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 stmt --> ifbrace +ifbrace tagged_stmt --> ifbrace +ifbrace [ rbrace (newline|ignore_scrap) ] --> ifbrace rbrace +ifbrace rbrace [ else (newline|ignore_scrap) ] --> ifbrace rbrace else +ifbrace rbrace <"\\"-space> else if --> if +ifbrace rbrace <"\\"-space> else lbrace --> forbrace +ifbrace rbrace <"\\"-space> else --> formath +ifbrace 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 stmt else if --> if +ifmath stmt else lbrace --> forbrace +ifmath stmt else --> formath +ifmath stmt --> stmt + +for math --> formath +formath <"\\"-space> lbrace --> forbrace +forbrace stmt --> forbrace +forbrace tagged_stmt --> forbrace +forbrace rbrace --> stmt +formath stmt --> stmt + +# we need an extra indent for switch, becuase the cases will be backed out +switch math lbrace --> switchbrace +switchbrace tagged_stmt --> switchbrace +# This next should never happen +switchbrace stmt --> switchbrace +switchbrace rbrace --> stmt + + + +# handle do-while (while has category for) +do lbrace --> dobrace +dobrace stmt --> dobrace +dobrace tagged_stmt --> dobrace +dobrace rbrace for --> math +do stmt for --> math + +case semi --> stmt +case math semi --> stmt +case colon --> tag +case math colon --> tag +tag tag --> tag +tag stmt --> tagged_stmt + +stmt stmt --> stmt +stmt tagged_stmt --> stmt +semi --> stmt + +# control sequence \8 puts things on the left margin + sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +preproc backslash newline --> preproc +preproc 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 +# 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 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 (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 decl --> structbrace +structbrace 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 --> 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* ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +[ (simp|decl_head) <"\\"-space> math* ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +fn_decl decl --> fn_decl +# The following statment will always have braces and never be tagged +fn_decl stmt --> function +# include stmt here to cover module definition +(stmt|decl|function) function --> function +function decl --> decl + +(stmt|decl) decl --> decl +decl stmt --> stmt +decl tagged_stmt --> stmt + + +lbrace rbrace --> stmt +lbrace stmt --> lbrace +lbrace tagged_stmt --> lbrace +lbrace (math|simp) 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 stmt --> ifbrace +ifbrace tagged_stmt --> ifbrace +ifbrace [ rbrace (newline|ignore_scrap) ] --> ifbrace rbrace +ifbrace rbrace [ else (newline|ignore_scrap) ] --> ifbrace rbrace else +ifbrace rbrace <"\\"-space> else if --> if +ifbrace rbrace <"\\"-space> else lbrace --> forbrace +ifbrace rbrace <"\\"-space> else --> formath +ifbrace 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 stmt else if --> if +ifmath stmt else lbrace --> forbrace +ifmath stmt else --> formath +ifmath stmt --> stmt + +for math --> formath +formath <"\\"-space> lbrace --> forbrace +forbrace stmt --> forbrace +forbrace tagged_stmt --> forbrace +forbrace rbrace --> stmt +formath stmt --> stmt + +# we need an extra indent for switch, becuase the cases will be backed out +switch math lbrace --> switchbrace +switchbrace tagged_stmt --> switchbrace +# This next should never happen +switchbrace stmt --> switchbrace +switchbrace rbrace --> stmt + + + +# handle do-while (while has category for) +do lbrace --> dobrace +dobrace stmt --> dobrace +dobrace tagged_stmt --> dobrace +dobrace rbrace <"\\"-space> for --> math +do stmt for --> math + +case semi --> stmt +case math semi --> stmt +case colon --> tag +case math colon --> tag +tag tag --> tag +tag stmt --> tagged_stmt + +stmt stmt --> stmt +stmt tagged_stmt --> stmt +semi --> stmt + +# control sequence \8 puts things on the left margin + sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +preproc backslash newline --> preproc +preproc 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: +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 +# 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 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 (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 decl --> structbrace +structbrace 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 --> 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* ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +[ (simp|decl_head) <"\\"-space> math* ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +fn_decl decl --> fn_decl +# The following statment will always have braces and never be tagged +fn_decl stmt --> function +# include stmt here to cover module definition +(stmt|decl|function) function --> function +function decl --> decl + +(stmt|decl) decl --> decl +decl stmt --> stmt +decl tagged_stmt --> stmt + + +lbrace rbrace --> stmt +lbrace stmt --> lbrace +lbrace tagged_stmt --> lbrace +lbrace (math|simp) 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 stmt --> ifbrace +ifbrace tagged_stmt --> ifbrace +ifbrace [ rbrace (newline|ignore_scrap) ] --> ifbrace rbrace +ifbrace rbrace [ else (newline|ignore_scrap) ] --> ifbrace rbrace else +ifbrace rbrace <"\\"-space> else if --> if +ifbrace rbrace <"\\"-space> else lbrace --> forbrace +ifbrace rbrace <"\\"-space> else --> formath +ifbrace 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 stmt else if --> if +ifmath stmt else lbrace --> forbrace +ifmath stmt else --> formath +ifmath stmt --> stmt + +for math --> formath +formath <"\\"-space> lbrace --> forbrace +forbrace stmt --> forbrace +forbrace tagged_stmt --> forbrace +forbrace rbrace --> stmt +formath stmt --> stmt + +# we need an extra indent for switch, becuase the cases will be backed out +switch math lbrace --> switchbrace +switchbrace tagged_stmt --> switchbrace +# This next should never happen +switchbrace stmt --> switchbrace +switchbrace rbrace --> stmt + + + +# handle do-while (while has category for) +do lbrace --> dobrace +dobrace stmt --> dobrace +dobrace tagged_stmt --> dobrace +dobrace rbrace for --> math +do stmt for --> math + +case semi --> stmt +case math semi --> stmt +case colon --> tag +case math colon --> tag +tag tag --> tag +tag stmt --> tagged_stmt + +stmt stmt --> stmt +stmt tagged_stmt --> stmt +semi --> stmt + +# control sequence \8 puts things on the left margin + sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +preproc backslash newline --> preproc +preproc 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 + +/*: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"); +} +#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(31byte_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){ +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=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_loc67108864)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_first67108864)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=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_firstdummy.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 +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 + +----------------------------------------- +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 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 + +----------------------------- +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=<>|). If |t=<>|, 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.<>==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 |<>|. +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`=<>| or |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.(<> s) == attach.<>.s; +attach.t.(<> s) == attach.<>.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.<>.s| is what we want. +Second, we have to compute |t| so that +|t=attach.<>.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=<>|, 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 := <>; +{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 <> S = s; + if choice = left -> + t,s := <>, S + [] choice = right -> + t,s := <>, 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 |<>|. +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, <> s + [] <<@tsecond guard@>>>@; -> + t,s := t.r, <> 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.(<> s)) +!<=> +ordered.(attach.<>.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, <> s + [] x >= t.d -> + t,s := t.r, <> 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.<>|&|==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.<>.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=<>|, then let |l=l`| and |r=data in.tree r`|. +Then, for any |t|, +$$\eqalign{ +in.(attach.t.s) &= +|in.(attach.t.(<> Z))|\cr +&=|in.(attach.<>.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, <>; +{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, <> s + [] x >= t.d -> + t,s := t.r, <> 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 <> S = s; + if choice = left -> + t,s := <>, S + [] choice = right -> + t,s := <>, 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 shout 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 --> unop +math lbrace --> lbrace +lbrace math close --> math +# lbrace math close --> unop + +open math close --> math +open close --> math + +? ignore_scrap --> #1 + +if <"\\"-space> math arrow --> ifbegin +ifbegin math box --> if +ifbegin math 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 +@@; +d[v] := 0; +W := {v}; +@@; +{@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| --> + @@; + @@; + 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 mathness no +ilk THEN_like category THEN translation mathness no +ilk ELIF_like category ELIF translation mathness no +ilk ELSE_like category ELSE translation mathness no +ilk FI_like category FI translation mathness no +ilk BEGIN_like category BEGIN translation mathness no +ilk END_like category END translation mathness no +ilk WHILE_like category WHILE translation mathness no +ilk FOR_like category FOR translation mathness no +ilk AS_like category AS +ilk EXEC_like category EXEC +ilk DO_like category DO translation mathness no +ilk OD_like category OD translation mathness no +ilk SWITCH_like category SWITCH translation mathness no +ilk IN_like category IN mathness no translation +ilk CASE_like category CASE translation mathness no +ilk DEFAULT_like category DEFAULT translation mathness no +ilk BREAK_like category BREAK translation mathness no +ilk CONTINUE_like category CONTINUE translation mathness no +ilk NI_like category NI translation mathness no +ilk unop_like category unop translation +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 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 (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 decl --> structbrace +structbrace 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 --> 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* ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +[ (simp|decl_head) <"\\"-space> math* ] (lbrace|decl_head|decl) --> fn_decl (lbrace|decl_head|decl) +fn_decl decl --> fn_decl +# The following statment will always have braces and never be tagged +fn_decl stmt --> function +# include stmt here to cover module definition +(stmt|decl|function) function --> function +function decl --> decl + +(stmt|decl) decl --> decl +decl stmt --> stmt +decl tagged_stmt --> stmt + + +BEGIN stmt --> BEGIN +BEGIN END --> stmt +BEGIN math END --> stmt +lbrace rbrace --> stmt +lbrace stmt --> lbrace +lbrace tagged_stmt --> lbrace +lbrace (math|simp) 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 stmt --> ifbrace +ifbrace tagged_stmt --> ifbrace +ifbrace [ rbrace (newline|ignore_scrap) ] --> ifbrace rbrace +ifbrace rbrace [ else (newline|ignore_scrap) ] --> ifbrace rbrace else +ifbrace rbrace <"\\"-space> else if --> if +ifbrace rbrace <"\\"-space> else lbrace --> forbrace +ifbrace rbrace <"\\"-space> else --> formath +ifbrace rbrace --> stmt + +# IF THEN ELSE FI + IF math --> IFmath +IFmath THEN --> IFTHEN +IFTHEN stmt --> IFTHEN +IFTHEN tagged_stmt --> IFTHEN +# IFTHEN [ (newline|ignore_scrap) ] --> IFTHEN +IFTHEN ELIF math --> IFmath +IFTHEN [ ELSE (newline|ignore_scrap) ] --> IFTHEN ELSE +IFTHEN ELSE --> IFELSE +IFELSE stmt --> IFELSE +IFELSE tagged_stmt --> IFELSE +IFTHEN FI --> stmt +IFELSE 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 stmt else if --> if +ifmath stmt else lbrace --> forbrace +ifmath stmt else --> formath +ifmath stmt --> stmt + +for math --> formath +formath <"\\"-space> lbrace --> forbrace +forbrace stmt --> forbrace +forbrace tagged_stmt --> forbrace +forbrace rbrace --> stmt +formath stmt --> stmt + +# FOR AS EXEC DO OD +FOR math AS math EXEC math --> FORmath +FORmath DO --> FORDO +FORDO stmt --> FORDO +FORDO stmt OD --> stmt +FORDO math OD --> stmt + +# WHILE DO OD +WHILE math DO --> WHILEDO +WHILEDO stmt --> WHILEDO +WHILEDO stmt OD --> stmt +WHILEDO math OD --> stmt + +# SWITCH +SWITCH math IN --> Switch +Switch stmt --> Switch +[ Switch math ] (CASE|BREAK|DEFAULT|NI) --> Switch (CASE|BREAK|DEFAULT|NI) +Switch tagged_stmt --> Switch +# Switch CASE tagged_stmt --> 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 --> switchbrace +switchbrace tagged_stmt --> switchbrace +# This next should never happen +switchbrace stmt --> switchbrace +switchbrace rbrace --> stmt + +# handle do-while (while has category for) +do lbrace --> dobrace +dobrace stmt --> dobrace +dobrace tagged_stmt --> dobrace +dobrace rbrace for --> math +do stmt 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 tag --> tag +tag stmt --> tagged_stmt + +stmt stmt --> stmt +stmt tagged_stmt --> stmt +semi --> stmt + +# control sequence \8 puts things on the left margin + sharp <"{\\let\\\\=\\bf"-space> (simp|if|else) <"}"-indent-"{}"-space> --> preproc +preproc backslash newline --> preproc +preproc 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. +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. + +@= +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. + +@= + + @@/ + @@/ + +@ 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 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 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|. + +@= +@@/ +@@/ + +@ |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 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 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|. + +@= +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. + + +@= +@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 --> tbegin +tbegin ? tbegin --> tbegin +tbegin decl --> tbegin + +[ intro ] constrains --> decl constrains +intro 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 --> conslist +conslist math close so that --> consintro + +consintro decl --> consintro +[ consintro ] (implies|tbegin) --> decl (implies|tbegin) + +simp is gen by --> gclause +gclause open --> glist +glist math comma --> glist +glist math close comma --> gclause +# do the following because converts is also a gclause +glist math close exempts --> exemptions +glist math close --> decl + +exemptions math comma --> exemptions +exemptions math --> decl + +for all open --> forlist +forlist (simp|comma|colon) --> forlist +forlist semi --> forlist +forlist close --> forintro + +[ forintro ] (implies|tbegin|gclause) --> decl (implies|tbegin|gclause) +[ forintro ] simp is gen by --> decl simp is gen by +forintro (relation|decl) --> forintro +forintro forintro --> forintro + +consintro forintro --> consfor +consfor forintro --> consfor + +[ consfor ] (implies|tbegin|gclause) --> decl (implies|tbegin|gclause) +[ consfor ] simp is gen by --> consintro simp is gen by +consfor (relation|decl) --> consfor + +implies (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 (decl|relation) --> decl +relation relation --> relation +relation 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 +#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 +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=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;k1)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(++ilink; +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(kbyte_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 + +@= +typedef short boolean; +typedef char unsigned eight_bits; +extern boolean program; /* \.{WEAVE} or \.{TANGLE}? */ +extern int phase; /* which phase are we in? */ + +@ @= +#include + +@ 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 */ + +@= +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. + +@= +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 */ + +@= +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); +} + +@= +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 */ + +@= +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: +@= +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: +@= +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) + +@= +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 +#ifdef MSDOS +#define index strchr +#endif + +@@; +@@; +@@; +@@; +@; + +@ 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 +@= +extern char the_at_sign; + + +@ @= +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. + +@= 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| */ + +@= +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. + +@= +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: + +@= +common_init() +{ + strncpy(xchr," !\"#$%&'()*+,-./0123456789\ +:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ",@'200); + @; + @; + @; + setting_up=1; + @; + setting_up=0; +} + +@ We use this variable to tell us what to do in |err_print|. +@=char setting_up; + +@ The following system-independent code makes the |xord| array contain +a suitable inverse to the information in |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}' */ + +@= /* 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= +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@> + +@= +#include +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 */ + +@= +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)) + +@= +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. + +@= +prime_the_change_buffer() +{ + change_limit=0; /* this value will be used if the change file ends */ + @; + @; + @; +} + +@ While looking for a line that begins with \.{@@x} in the change file, +we allow lines that begin with \.{@@}, as long as they don't begin with +\.{@@y} or \.{@@z} (which would probably indicate that the change file is +fouled up). + +@= +while(1) { + change_line++; + if (!input_ln(change_file)) return; + if (limit; + @; + 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. + +@= +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. + +@= { + 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}. + +@= +do { + change_line++; + if (!input_ln(change_file)) { + err_print("! Change file ended after @@x"); +@.Change file ended...@> + return; + } +} while (limit==buffer); + +@ @= +{ + change_limit=change_buffer-buffer+limit; + strncpy(change_buffer,buffer,limit-buffer+1); +} + +@ 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|. + +@= +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) + @; + @;@/ + @;@/ + 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 (limit>buffer+1 && buffer[0]==the_at_sign) { + @; + 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. + +@= +reset_input() +{ + limit=buffer; loc=buffer+1; buffer[0]=@` '; + @; + 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. +@= +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 */ + + + +@= +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 */ + +@ @= +get_line() /* inputs the next line */ +{ + restart: + if (changing) changed_module[module_count]=1; + else @; + if (changing) { + @; + if (! changing) { + changed_module[module_count]=1; goto restart; + } + } + loc=buffer; *limit=@` '; + if (*buffer==the_at_sign && (*(buffer+1)==@`i' || *(buffer+1)==@`I')) + @; + 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. +@= + pathaddpath(getenv("WEBPATH"),':'); +@ @= + pathaddname(*argv+2); +@ @= +@i pathopen.h +@ We need to define an |overflow| {\em function} for |pathopen| to call. +@ @= +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. + +@= { + 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 + } + else {cur_line=0; print_where=1;} + } + else { + include_depth--; + err_print("! Too many nested includes"); +@.Too many nested includes@> + } + } + goto restart; +} + +@ @= { + cur_line++; + while (!input_ln(cur_file)) { /* pop the stack or quit */ + print_where=1; + if (include_depth==0) {input_has_ended=1; break;} + else {fclose(cur_file); include_depth--; 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(); +} + +@ @= { + 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) { + @; + @; + 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|. + +@= +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 */ + +@= +typedef struct name_info { + ASCII *byte_start; /* beginning of the name in |byte_mem| */ + ===> @@; +} 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|. + +@= +name_pointer name_ptr; /* first unused position in |byte_start| */ +ASCII *byte_ptr; /* first unused position in |byte_mem| */ + +@ @= +name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */ +name_ptr=name_dir+1; /* |name_dir[0]| will 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. + +@= +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 */ + +@= +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. + +@= +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 */ + @; + @; + if (p==name_ptr) @; + 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|.$$ + +@= +h=*i; while (++i= +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. + +@= { + 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 */ + +@= +union { + struct name_info *Rlink; /* right link in binary search tree for module + names */ + eight_bits Ilk; /* used by identifiers in \.{WEAVE} only */ +} dummy; + +@ @= +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 */ + +@= +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 (krlink| 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|. + +@= +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 + +@= +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. + +@= +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 { + @; + } + 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@> + +@= +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 + +@ 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@> + +@= +wrap_up() { + putchar('\n'); + @; + if (history > harmless_message) exit(1); + else exit(0); +} + +@ @= +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}. + +@= +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| +@=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@> + +@= +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) @@; + else if (!found_change) @@; + else @; + } + else @; + } + if (!found_web) @; + if (!found_change) @; +} + +@ 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. + +@= +{ + if (strlen(*argv) > max_file_name_length-5) + @; + if ((dot_pos=index(*argv,'.'))==NULL) + sprintf(web_file_name,"%s.web",*argv); + else { + sprintf(web_file_name,"%s",*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; +} + +@ @= +{ char *p; + p=dot_pos; + while (*++p != '\0') + if (*p=='.') dot_pos=p; +} + +@ @= +{ + if (strlen(*argv) > max_file_name_length-5) + @; + if ((dot_pos=index(*argv,'.'))==NULL) + sprintf(change_file_name,"%s.ch",*argv); + else sprintf(change_file_name,"%s",*argv); + found_change=1; +} + +@ @= +#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&% +Adds {\tt } to the directories searched for included files.\cr +} +@= +{ + switch((*argv)[1]) { + case 'x': + no_xref=1; + break; + case 'I': + @@; + break; + default: + @; + break; + } +} + +@ @= +{ +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); +} + +@ @= fatal("! Filename %s too long\n", *argv); + +@ @= { +printf("! Unknown option in argument %s\n", *argv); mark_harmless; +} + +@* Output. Here is the code that opens the output file: +@^system dependencies@> + +@= +FILE *C_file; /* where output of \.{TANGLE} goes */ +FILE *tex_file; /* where output of \.{WEAVE} goes */ + +@ @= +scan_args(); +@@; +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 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 { + # + n=0 + while (n + n++ + } + for (node in incoming) { + if (incoming[node]!=0) { + # + } + } + if (cycle==0) { + print "There can't possibly be a cycle in the graph" + } else { + exit 0 ## no error until we check context + } + } + +# #= +for (node in incoming) { + if (incoming[node]==0) { + work[high++]=node + } + } + +# #= +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 + } + } + +# #= +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 +@= +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. +@= +cur_file=end_output_files=output_files+max_files; + +@ @= +{ +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 + @ + 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. +@= +for (;cur_filebyte_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: @; +@y + case module_name: + cur_module_char=*(loc-1); + @; +@z +@x 803 + return(module_name); +@y + if (cur_module_char=='(') { + @ + } + 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 + +/*: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;ipathname+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 +@@; + +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++; + } + @@; + searchpath[++nextpath]=t; +} + +@ @= +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++; + } + @@; + 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@; + } + } + return NULL; +} + +@ @=#include + +@ @= +for(s=pathname,t=searchpath[i]; tpathname+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;ilogfile +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;ilogfile +##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;i1){ +##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;i1&&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;ilogfile +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;imacrofile + + +##: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;ilogfile +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$/){ +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$/){ +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;posNF||$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;posNF||$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;pos1){ +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 %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"@=">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"@=">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"@ @=">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"@;">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"@=">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"@ @=">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"@ @=">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"@ @=">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"@ @=">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"@ @=">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"@=">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"@ @=">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"@=">grammarfile +for(n=1;n<=prodnum;n++){ +if(n%5==0) +print"@ @="\ +>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(reductiongrammarfile +} + +##: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"@=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"@="\ +>wlang +printf"*out_ptr='x'; tex_printf(\"\\\\input %sweb.te\");\n",\ +extension>wlang +printf"@ @=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"@ @=">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"@ @=">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"@=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"@=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"@=">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"@ @="\ +>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"@=">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"@=">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" @;">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 { +# +exitcode=0 +} +#@ +# +# +# +# +#@ +END { +# +print "Writing out lists" > logfile +# +# +# +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. +#= + 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. +#= + if (i<=NF) { + print "Error: leftover fields", $i, "... on line", NR-1 + # + } + + +# To \.{SPIDER}, any line beginning with |"## "| is a comment. +\.{SPIDER} also ignores blank lines. +#= +#=/^##|^ *$/#> { + ## comments, blank lines + print $0 > logfile + next + } + +# But, if \.{SPIDER} encounters a line we don't recognize, it complains. +#= + { + 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. +#= + logfile = "spider.slog" + +# Here we write the names of the key words used in translations. +#= + translationfile = "trans_keys.unsorted" + +# We write tokens out to two files: |scrapfile| for \.{WEAVE}, and +|ttokfile| for \.{TANGLE}. +#= + 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. +#= + reserved = "scraps.web" ## use same file; not enough files + +# We'll also end up writing a list of token names, for name checking +purposes. +#= + 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. +#= + 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. +#= + categoryfile = "names.unsorted" ## cut down on number of output files +# We use a special file to write grammar information: +#= + 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. +#= + 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. +#= + productions = "productions.list" + +# These productions will get fed to {\tt cycle.awk}, which looks for cycles. +#= + 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}). +#= + for (t in translation_keywords) { + print t > translationfile + } + +# #= +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"|. + + +#"|#>= +temp = substr(transstring,2,length(transstring)-2) ## kills awk bug +trcnt = split(temp,trtok,"-") +outstring = "" +for (tridx=1;tridx<=trcnt;tridx++) { + alternate=trtok[tridx] + # + 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 + # + 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. +#= + 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=="") { + 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. +#= +temp = substr(transstring,2,length(transstring)-2) ## kills awk bug +trcnt = split(temp,trtok,"-") +outstring = "" +for (tridx=1;tridx<=trcnt;tridx++) { + alternate=trtok[tridx] + # + 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. +#= +for (i=start_place;i + } +} +# + +# We check for the presence or absence of certain empty strings after +scanning. +#= +if (this_name != "") { + print "Error: name doesn't apply on line", NR-1 + # + } +# #= +if (this_tangleto != "") { + print "Error: tangleto doesn't apply on line", NR-1 + # + } +# #= +if (this_category != "") { + print "Error: category doesn't apply on line", NR-1 + # + } +# #= +if (this_translation != "") { + print "Error: translation doesn't apply on line", NR-1 + # + } +# #= +if (this_category == "") { + print "Error: you must give a category on line", NR-1 + # + } + +#*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 +#= +#=/^default /#> { + print "Setting defaults..." > logfile + start_place=2 + # + # + # + # + 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: +#= + this_translation=default_translation + this_mathness=default_mathness + this_name="" + this_category="" + this_tangleto="" +# When \.{SPIDER} starts up, the defaults are already set: +#= + 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. + +#= +#=/^token /#> { + print "Token", $2 > logfile + if ($2=="identifier") { + # + } else if ($2=="number") { + # + } else if ($2=="newline") { + # + } else if ($2=="pseudo_semi") { + # + } else if ($2 ~ #=/[a-zA-ZA-Z0-9]+/#>) { + ## we recognize no other names + print "Error: unknown token species:", $2 + # + } else { + # + } + categories[this_category]=1 ## is this right? +#^questions#> + next +} + +# Identifiers, numbers (and string literals), newlines, and the special +token \.{pseduo\_semi} are predefined. +#= + # + this_translation="" + start_place=3 + # + # + # + # + # + id_category=this_category + id_mathness=this_mathness + +# We have yet to implement a separate procedure for numerics and strings! +#= + print "Warning: numeric constants and strings are",\ + "identified in this WEAVE." + print "Warning: numeric constants and strings are",\ + "identified in this WEAVE." > logfile + # + this_translation="" + start_place=3 + # + # + # + # + # + number_category=this_category + number_mathness=this_mathness + +# +#= + # + start_place=3 + # + # + # + # + newline_category=this_category + newline_mathness=this_mathness + newline_translation=this_translation + +# +#= + # + start_place=3 + # + # + # + # + 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. +#= + this_string=$2 + # +## print NF, "fields on line", NR-1 ## caught a bug in DEC awk + $2 = this_string +## print NF, "fields on line", NR-1 + # + if (tokens[$2]!="") { + print "Warning: token", $2, "defined twice" + } + tokens[$2]=1 ## remember this token + # + # + # + + +# 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. + +#= +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. +#= + 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|. +#= +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. +#= +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]|. +#= + 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) { + # + } 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.) +#= + 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: +#= + # + this_name=tokenname[$2] + start_place=3 + # + # + 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. +#= + temp = tokenlength[$2] + if (temp > maxtokenlength) { + maxtokenlength=temp + } + +# We're paranoid. +#= + 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}. +#= + tempfile = scrapfile + # + tempfile = ttokfile + # + +# This is how we do it. +#= +print "@ Here we input tokens of more than one character" > tempfile +print "@=" > tempfile +# + +# 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. +#= + for (len=maxtokenlength; len>=2; len--) { + printf "if (loc+%d<=limit) {\n", len-1 > tempfile + # + printf "\t}\n" > tempfile + } + # + +# #= +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 + } + } + + +# #= +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. +#= + print "Writing out predefined scraps" > logfile + # + # + # + # + print "Writing out token scraps" > logfile + # + + + + +# This is how we write out the information for the identifier. +#= + if (id_category != "") { + print "@ @=" > 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 "@;" > 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. +#= + tokennumbers["identifier"]=tokennumber; tokennumber-- + tokenname["identifier"]="identifier" + +# This is how we write out the string or constant scrap, at the end. +#= +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 "@=" > 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. +#= + tokennumbers["constant"]=tokennumber; tokennumber-- + tokenname["constant"]="constant" + tokennumbers["string"]=tokennumber; tokennumber-- + tokenname["string"]="string" + + +# +#= +if (newline_category != "") { + print "@ @=" > scrapfile + transstring=newline_translation + selfstring="small_app(next_control);" + wherestring="in translation of token newline" + append_keyword="small_app" + #"|#> + 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 + } + +# +#= +if (pseudo_semi_category != "") { + print "@ @=" > scrapfile + transstring=pseudo_semi_translation + selfstring="small_app(next_control);" + wherestring="in translation of token pseudo_semi" + append_keyword="small_app" + #"|#> + 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: +#= +print "@ @=" > 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" + #"|#> + 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#> +#= +print "@ @=" > ttokfile +for (t in tokennumbers) { + # + 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 + # + 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. +#= +print "@ @=" > ttokfile +for (t in tokentangleto) { + # + 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 + # + 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=="string"||t=="constant"||t=="identifier") + continue + + + +# This is somewhat like the translation code, but tuned for \.{TANGLE} +#= +oldwherestring = wherestring +wherestring = "for tangleto " wherestring +#@ +transstring=this_tangleto +# +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. +#= + tempfile = scrapfile + # + tempfile = ttokfile + # + +# We use an ugly trick to get the token numbers different for +\.{WEAVE} and \.{TANGLE}: +#= + 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} + # ## 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. +#= + for (t in tokenname) { + temp = tokenname[t] + if (substr(temp,1,1) != "'") { + # + print temp > tokennamefile + } + } + +# #= +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. + +#= +#=/^ilk /#> { + print "Ilk", $2 > logfile + # + # + this_name="" + start_place=3 + # + # + # + 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 ($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#> +#= +#=/^reserved /#> { + print "Reserved word", $2 > logfile + if ($0 !~ #=/ ilk /#>) { + # + } + 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 + # + } + } + # + 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.} +#= + 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. +#= +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. +#= +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 "@=" > 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" + #"|#> + 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. +#= +print "@ @=" > 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?} +#= + 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 + } + } + +# #= + for (i in ilk_translation) { + print i > ilkfile + } + +# #= +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. +#= +#=/-->/#> { + # + # + # + # + # + # + # + # + # + # + # + # + # + 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]|. +#= + 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|. + +#= +trans[pos]="" +for (i=1; i<=NF; i++) { + if ($i ~ #=/<.*>/#>) { ## should be |trans_pattern| + # + } else if ($i ~ #=/^!?[a-zA-Z_]+(\*\*?)?$/#>) { ## |cat_pattern| + # + } else if ($i ~ #=/^!?\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/#>){ + # + } else if ($i == "?") { + # + } 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 + # + } +} +i++ + + +# When we find a mistake, we just abandon the current production. +Decrementing |prodnum| will make it as if this production never happened. +#= + prodnum-- + # + +# We process the translation and add the result to the current +translation for |pos|. +#= +transstring=$i +selfstring="" ## senseless for productions +wherestring= sprintf ("in production on line %d", NR-1) +append_keyword="app" +#"|#> +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. +#= + field[pos]=$i ## save this field to compare RHS + # + # + 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) + } + # + # + +# 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. +#= + field[pos]=$i ## save this field to compare RHS + # + 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 + } + # + 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 + # + 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] ")" + # + + +# 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. +#= + 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. +#= +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. + +#= + 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. + +#= +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 + # +} + +# Wild cards are easy to process, but we do have to remember that +not even a wild card matches a scrap of category zero. +#= + 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? + # + + + +# +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. + + +#= + 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 + # + } + +# Here is the efficient place to update the rightmost (highest) +position of {\it any} category. +#= + 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: +#= +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. +#= + for (pos=1;pos + i++ + } + +# #= + for (pos=highpos;pos + i++ + } +# #= + if (i>NF || $i != field[pos]) { + print "Error: token mismatch is: found", $i, \ + "sought", field[pos], "on line", NR-1 + # + } + +# 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. +#= + ## i points to the target category + if (i>NF) { + print "Error: no target category in production on line", NR-1 + # + } + if ($i ~ #=/##[0-9]+/#>) { ## a number + $i = substr($i,2) ## peel off the \## + # + 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 + # + } + i++ + +# We call this at the end to make sure there aren't unused fields left over +#= + if (i<=NF) { + print "Error: used only " i-1 " of " NF " tokens", \ + "in production on line", NR-1 + # + } + +# After having vetted the whole production, we combine the tests and +translations for each |pos|. +#= + prodtest[prodnum]="" + for (pos=1;pos1) { + prodtest[prodnum]=prodtest[prodnum] " &&\n\t\t" + } + prodtest[prodnum]=prodtest[prodnum] test[pos] + } + +# #= + prodtrans[prodnum]="" + for (pos=lowpos;pos + } + prodtrans[prodnum]=prodtrans[prodnum] trans[highpos] + +# #= + ppstart[prodnum]=lowpos-1 + tokensreduced[prodnum]=highpos-lowpos + +# #= + 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. +# #= +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. +#= +temp = field[pos] +tempa = substr(temp,1,1) +if (tempa != "!") { + if (temp ~ #=/^\(([a-zA-Z_]+\|)*[a-zA-Z_]+\)(\*\*?)?$/#>) { + ## list of alternatives + # + 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_]+(\*\*?)?$/#>) { + # + reduced[temp]=1 + } else if (temp != "?") { + print "Confusion: unintelligible field[pos]:", temp, \ + "in production on line", NR-1 + # + } +} + +# #= +while (temp ~ #=/\*$/#>) { + temp = substr(temp,1,length(temp)-1) +} + +# #= +for (c in categories) { + if (reduced[c] != 1) { + print "Warning: category", c, "never reduced" + } +} + + +# Here's a check for the target token number +#= +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 + # + } + +#*1Writing the scrap reduction code. +Before writing the grammar, we want to define all of the category codes. +#= + 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. +#= + 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... +#= + for (c in categories) { + print c > categoryfile + } + +# #= +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. +#= +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} +#= +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 "@=" > grammarfile +for (n=1; n<=prodnum; n++) { + if (n%5==0) + print "@ @=" \ + > grammarfile ## avoids overflowing \.{WEAVE} of \.{WEAVE} + # + # + printf "if (%s) {\n\t/* %d: {\\tt %s} */\n%s",\ + prodtest[n],n,this_string,prodtrans[n] > grammarfile + # + print "\tgoto end_prods;" > grammarfile + printf "} " > grammarfile + } +printf "\n" > grammarfile +print "end_prods:" > grammarfile + +# We do different things for a category that is unnamed. +#= + 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 grammarfile + } + +# This is the place we check for errors. +#^append check#> +#^reduce check#> +#= +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. +#= + 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. +#= +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. +#= +#=/^language /#> { + language = $2 + extension=language + for (i=3; i + } + } + # + # + next +} + +# #= +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 "@=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 "@=" \ + > wlang + printf "*out_ptr='x'; tex_printf(\"\\\\input %sweb.te\");\n", \ + extension > wlang + printf "@ @=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. +#= + 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. +#= +#=/^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 + # + } + } 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. +#= +#=/^module /#> { + for (i=2;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 + # + } + } + # + next +} + +# Here's how we rig it: +#= +if (mod_def_cat!="") { + print "@ @=" > 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 "@ @=" > 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.'' +#= +#=/^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" + # + } + next +} + +# We write the at sign out to the grammar file and to \.{TANGLE}'s token file +#= + tempfile = grammarfile + # + tempfile = ttokfile + # + +# It's trivially done +#= + 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 "@=char the_at_sign = at_sign;" > tempfile + print " " > tempfile + +# We provide a default at sign: +#= + 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. +#= +#=/^comment /#> { + print $0 > logfile + for (i=2; i$/#>) { + transstring = $i + wherestring = "in \"comment begin\" on line " NR-1 + # + begin_comment_string = outstring + i++ + } else { + print "Error: \"comment begin\" must have a restricted translation" + # + } + } 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 + # + end_comment_string = outstring + } else { + print "Error: \"comment end\" must have a restricted translation" + # + } + i++ + } else { + print "Error: bad comment attribute:", $i + # + } + } + # + # + 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. + +#= +print "@ Here we recognize the comment start seqence" > ttokfile +print "@=" > 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 +#= +print "@ @=" \ + > 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 +#= +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 "@=" > 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. +#= +printf "@ Here we recognize end of comments" > scrapfile +printf "@d comments_end_with_newline = %d\n",comments_end_with_newline >scrapfile +print "@=" > 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 " @;" > 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. +#= + 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. +#= +if (macrofile!="") { + this_string=substr(begin_comment_string,2,length(begin_comment_string)-2) + # + 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) + # + 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" + # + } + + + +# Escaping \TeX's specials is pretty easy: +#= +texof["\\"]="\\BS" +texof["{"]="\\{" +texof["}"]="\\{" +texof["$"]="\\$" +texof["&"]="\\amp" +texof["##"]="\\##" +texof["^"]="\\H" +texof["_"]="\\_" +texof["~"]="\\TI" +texof["%"]="\\%" + +# +#= +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. +#= +#=/^line /#> { + print $0 > logfile + for (i=2; i$/#>) { + transstring = $i + wherestring = "in \"line begin\" on line " NR-1 + # + sharp_line_open = outstring + i++ + } else { + print "Error: \"line begin\" must have a restricted translation" + # + } + } else if ($i=="end") { + i++ + if ($i ~ #=/^<.*>$/#>){ + transstring = $i + wherestring = "in \"line end\" on line " NR-1 + # + sharp_line_close = outstring + } else { + print "Error: \"line end\" must have a restricted translation" + # + } + i++ + } else { + print "Error: bad line attribute:", $i, "on line", NR-1 + # + } + } ## |for| + # + next +} + +# We have to give \.{TANGLE} the strings for \&{\##line} commands. +#= + 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 +#= +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. +#= +#=/^date /#> { + ## date returned as ``Fri Dec 11 11:31:18 EST 1987'' + mo = month[$3] + day = $4 + year = $7 + time = $5 + # + 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 +#= +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"|. +#= + 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 +@@; +@@; +@@; +@@; + +main (ac, av) +char **av; +{ + argc=ac; argv=av; + program=tangle; + @; + 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@> + +@= +typedef struct { + eight_bits *tok_start; /* pointer into |tok_mem| */ + sixteen_bits text_link; /* relates replacement texts */ +} text; +typedef text *text_pointer; + +@ @= +text text_info[max_texts]; +text_pointer text_info_end=text_info+max_texts-1; +text_pointer text_ptr; /* first unused position in |text_info| */ +eight_bits tok_mem[max_toks]; +eight_bits *tok_mem_end=tok_mem+max_toks-1; +eight_bits *tok_ptr; /* first unused position in |tok_mem| */ + +@ @= +text_info->tok_start=tok_ptr=tok_mem; +text_ptr=text_info+1; text_ptr->tok_start=tok_mem; + /* this makes replacement text 0 of length zero */ + +@ If |p| is a pointer to a 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 */ + +@ @= +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 */ + +@= +text_pointer last_unnamed; /* most recent replacement text of unnamed module */ + +@ @= 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|. + +@= +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 */ + +@= +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. + +@= +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; +{ + @; + 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; +} + +@ @= +#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; +@; + if (cur_repl->text_link==0) { /* macro definition */ + if (cur_name->ilk==macro) { + @; + } + } else if (cur_repl->text_linktext_link+text_info; /* stay on the same level */ + cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start; + return; + } + stack_ptr--; /* go down to the previous level */ + if (stack_ptr>stack) cur_state=*stack_ptr; +} + + +@ @= +number_of_parameters=*(cur_repl->tok_start); +@; +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; + + +@ @= +#ifdef TRACE_MACROS +if (tracing>1) { + printf("\nUnstacking %d parameters",number_of_parameters); + } +#endif 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 +@= +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) { + @; + @; + } else + out_char(a); /* one-byte token */ + else { + a=(a-@'200)*@'400+*cur_byte++; + switch (a/@'24000) { /* |@'24000=(@'250-@'200)*@'400| */ + case 0: + @; + cur_val=a; out_char(identifier); break; + case 1: @; + default: cur_val=a-@'50000; if (cur_val>0) cur_mod=cur_val; + out_char(module_number); + } + } + return 1; +} + + +@ @= +push_level(name_ptr-*cur_byte++); goto restart; +@ @= +#ifdef TRACE_MACROS +if (tracing>2) { + printf (" [#%d]",*cur_byte); + } +#endif TRACE_MACROS + +@ @= +if (name_dir[a].ilk==macro) { + @; + @; + push_level(name_dir+a); + cur_byte++; /* skip number of parameters */ + goto restart; +} else if (name_dir[a].ilk==simple) { + @; + push_level(name_dir+a); + goto restart; +} + +@ @= +#ifdef TRACE_MACROS +if (tracing>2) { + printf("\nExpanding macro ("); print_id(name_dir+a); + printf("=nd[%d])",a); + } +#endif TRACE_MACROS + +@ @= +#ifdef TRACE_MACROS +if (tracing>2) { + printf("\nExpanding parameter ("); print_id(name_dir+a); + printf("=nd[%d])",a); + } +#endif TRACE_MACROS + + +@ @= +{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) { + @; + } + 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. +@ @= +short balances[@'200]; +@ @= +{ int i; +for (i=0;i<@'200;i++) balances[i]=0; +@; +} +@ Eventually we will want {\tt SPIDER} to set balances. +For now let's try just tossing in parenthesis, braces, and square brackets. +@= +balances[@`(']=1; +balances[@`)']=-1; +balances[@`[']=1; +balances[@`]']=-1; +balances[@`{']=1; +balances[@`}']=-1; + +@ @= +{ int bal; /* used to balance parentheses in parameter lists */ + eight_bits b, oldb; + sixteen_bits c; +bal=0; +@; +while (1) { + b=*cur_byte++; + if (b==param) { /* convert to name reference */ + b=*cur_byte++; + @; + 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) { + @; + 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@>) { + @; + } else { + @; + 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; +@; +} + +@ @= +name_pointer parm_ptr; /* used while stacking parameters */ + +@ @<|b| opens verbatim or string@>=(b==string||b==constant) +@ @= +app_repl(b); +oldb=b; +@; +while((b=*cur_byte++)!=oldb) { +@; + app_repl(b); + if (cur_byte>=cur_end) + confusion("string or constant didn't end in token list"); +} +@"| (|#ifdef TRACE_MACROS|)@>; + + + +@ @= +#ifdef TRACE_MACROS +if(tracing>2) printf(" <"); +#endif TRACE_MACROS +@ @= +#ifdef TRACE_MACROS +if (tracing>2) printf("%c",b); +#endif TRACE_MACROS +@ @"| (|#ifdef TRACE_MACROS|)@>= +#ifdef TRACE_MACROS +if(tracing>2) printf(">"); +#endif 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 + +@ @= +#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 + +@ @= +#ifdef TRACE_MACROS +if (tracing>2) { + printf (" <"); + if (@'37"); +} +#endif TRACE_MACROS + +@ @= +#ifdef TRACE_MACROS +if (tracing>2) { + printf ("\nScanning #%d...", number_of_parameters+1); + } +#endif 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. + +@= + 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:
@> + } + 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 */ + +@= +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 +@= +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. +@= +cur_out_file=end_output_files=output_files+max_files; + +@ @= +{ +if (cur_out_file>output_files) { + for (an_output_file=cur_out_file; + an_output_filetext_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; + @; + 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; + } + @@; + } + 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. +@= +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| */ + @; + 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@>@; + @/@t\4@>@; + @@; + 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; + } +} + +@ @= +#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= +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 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 `\.{@@*}' */ + +@= +eight_bits ccode[128]; /* meaning of a char following \.{@@} */ + +@ @= { + 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: +@=short tracing; +@ @=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. + +@= +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++); + @@; + 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 +@= +name_pointer cur_module; /* name of module just scanned */ + +@ @= +#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; + @; + } + 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; + } + @@; + loc++; + if (isdigit(c) || c=='\\' || c=='.') @@;/*spider*/ + else if (isalpha(c) || c=='_' || c=='$') @@;/*spider*/ + else if (c=='\'' || c=='\"') @@;/*spider*/ + else if (c==at_sign) @@; + else if (c==' ' || c==tab_mark) { + continue; /* ignore spaces and tabs */ + } + mistake: @@; + return(c); + } +} + +@ @= {/*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); +} + +@ @= {/*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|. + +@= {/*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. + +@= { + 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); + @; + case string: @; +#ifdef DEBUG + case trace: tracing=*(loc-1)-'0'; continue; +#endif DEBUG + case ascii_constant: @; + case octal: @; + case hex: @; + default: return(c); + } +} + +@ @=/*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); + +@ @= { + id_first=loc; + while ('0'<=*loc && *loc<'8') loc++; + id_loc=loc; + return(octal); +} + +@ @= { + id_first=loc; + while (isxdigit(*loc)) loc++; + id_loc=loc; + return(hex); +} + + +@ @= { + ASCII *k; /* pointer 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=='(') { + @@; + } + 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.) + +@=mod_text[0]=' '; + +@ @= +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; + @; + loc++; 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 (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. + +@= { + 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;} + +@= +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) {@;} + /* 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) { + @@; + 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) { + @; + } + 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. +@= +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 +@= +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| */ + +@ @= +next_param_name=0; +next_param_name_text=param_name_texts; +param_names[next_param_name]=next_param_name_text; + +@ @=@; + +@ @= +@; +while (id_first= +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= +@@; +@; +@; +if (next_control!= @`=') { + err_print("! You must put an = sign before the macro replacement text"); + @; +} +@; +app_repl(next_param_name); /* store number of parameters in |tok_mem| */ +scan_repl(macro); +p->equiv=(ASCII *)cur_text; +@; +@; + +@ @= +#ifdef TRACE_MACROS +if (tracing>1) { + printf("\nScanning definition of macro "); print_id(p); + } +#endif 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 + + +@ @= +@@; +if (next_control==@`(') { + do { + @; + @@; + } while (next_control==@`,'); + if (next_control != @`)') { + err_print("! Macro parameter list must end with )"); + @; + } + next_control=get_next(); /* first token following parameter list */ +} + + +@ @= +if (next_control!=identifier) { + err_print("! Macro name must be an identifier"); +@.Macro name must be an identifier@> + @; +} 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: "); + } +} + +@ @= +@; +if (next_control!=identifier) { + err_print("! Macro parameter name not an identifier"); +@.Macro parameter name...@> + @; +} else { + if (parameter_number(id_first,id_loc)!=0) { + err_print("! Duplicate parameters in macro definition"); +@.Duplicate parameters...@> + @; + } else { + @; + } +} + + +@ @= +while ((next_control=get_next())==@`\n'); + +@ We modify this from the old tangle: + +@= +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 { + @; + a=cur_module-name_dir; + app_repl((a / @'400)+@'250); + app_repl(a % @'400); + @; break; + } +case constant: case string: + @; +case ascii_constant: + @; +case octal: + @; break; +case hex: + @; 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. + +@= +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);} + +@ @= { + ASCII *try_loc=loc; + while (*try_loc==' ' && try_loc +} + +@ @= + 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; + +@ @= { + 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... +@= { +long sum=0; +while (id_first @"04000000) err_print("! Octal constant exceeds @@\"04000000"); + } +app_repl(constant); +app_decimal(sum); +app_repl(constant); +} + +@ @= { +long sum=0; +while (id_first @"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=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. + +@= +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); + @; + @; +} + +@ 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 +@= +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; + @; + 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. +@= +@; +p->ilk=normal; /* turn off macro replacement and hope for the best */ +goto done_scanning; + + +@ @= +switch (next_control) { + case begin_unnamed: p=name_dir; break; + case module_name: p=cur_module; + @; + break; + default: return; +} +@; +scan_repl(module_name); /* now |cur_text| points to the replacement text */ +@; + +@ @= +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; +} + +@ @= +store_two_bytes((sixteen_bits)(@'150000+module_count)); /* |@'150000==@'320*@'400| */ + +@ @= +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_linktext_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 +@@; +@@; +@@; +@@; + +main (ac, av) +char **av; +{ + argc=ac; argv=av; + program=weave; + common_init(); + @; + printf(banner); /* print a ``banner line'' */ + @; + phase_one(); /* read all the user's text and store the cross-references */ + phase_two(); /* read all the text again and translate it to \TeX\ form */ + phase_three(); /* output the cross-reference index */ +#ifdef STAT + @; +#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. + +@= +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. + +@= +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; + +@ @= +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 + +@= +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) { + @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 +@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
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|. + +@= +typedef sixteen_bits token; +typedef token *token_pointer; +typedef token_pointer *text_pointer; + +@ The first position of |tok_mem| +that is unoccupied by replacement text is called |tok_ptr|, and the first +unused location of |tok_start| is called |text_ptr|. +Thus, we usually have |*text_ptr=tok_ptr|. + +@= +token tok_mem[max_toks]; /* tokens */ +token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */ +token_pointer tok_start[max_texts]; /* directory into |tok_mem| */ +token_pointer tok_ptr; /* first unused position in |tok_mem| */ +text_pointer text_ptr; /* first unused position in |tok_start| */ +text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */ +#ifdef STAT +token_pointer max_tok_ptr; /* largest value of |tok_ptr| */ +text_pointer max_text_ptr; /* largest value of |text_ptr| */ +#endif STAT + +@ @= +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|. + +@= +eight_bits ccode[128]; /* meaning of a char following \.{@@} */ + +@ @= +{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@>@@; +@# +/*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. + +@= +#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. + + + +@= +name_pointer cur_module; /* name of module just scanned */ +int math_flag; + +@ @= +#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++); + @@; + if (see_vertical && c==vertical_char) { + if (*loc==vertical_char && loc < limit) { + loc++; + } else { + return vertical_bar; + } + } + if (isdigit(c)) @@; /*spider*/ + else if (isalpha(c) || c=='_') @@;/*spider*/ + else if (c=='\'' || c=='"') @@;/*spider*/ + else if (c==at_sign) @@; + else if (c==' ' || c==tab_mark) continue; /* ignore spaces and tabs */ + mistake: @@; + return(c); + } +} + +@ @= +while ((next_control=get_next(0))==@`\n'); + +@ @= {/*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|. + +@= { + 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... +@= { + 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... +@= { + 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|. + +@= {/*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. + +@= { + 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: + @}@>@; + case module_name: + @@; + case verbatim: @@; + case ascii_constant: /* fake into looking like quoted char */ + @; + case octal: @; + case hex: @; + default: return(ccode[c]); + } +} + +@ The occurrence of a module name sets |xref_switch| to zero, +because the module name might (for example) follow \&{int}. + +@= { + ASCII *k; /* pointer into |mod_text| */ + cur_module_char=c; /* remember |'<'| or |'('| */ + @; + 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); +} + +@ @=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.) + +@=mod_text[0]=' '; + +@ @= +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; + @; + loc++; 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 (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 */ +} + +@ @= { + 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. + +@= { + 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. + +@= +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) + @; +changed_module[module_count]=change_exists; + /* the index changes if anything does */ +phase=2; /* prepare for second phase */ +@; +} + +@ @= +{ + 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 */ + } + @; + @; + @; + 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=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_control0) { + 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\,$\.{@@>}. + +@= +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=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. + +@= +name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */ + +@ When we get to the following code we have |next_control>=format|. + +@= +while (next_control<=definition) { /* |format| or |definition| */ + xref_switch=def_flag; /* implied \.{@@!} */ + if (next_control==definition) next_control=get_next(1); + else @; + outer_xref(); +} + +@ Error messages for improper format definitions will be issued in phase +two. Our job in phase one is to define the |ilk| of a properly formatted +identifier, and to fool the |new_xref| routine into thinking that the +identifier on the right-hand side of the format definition is not a +reserved word. + +@= { + 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|. + +@= +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. + +@= +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:
@> + } + 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
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:
@> + } + 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); + } +} + +@ @=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. + +@= +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 (bout_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. + +@= +out_ptr=out_buf+1; out_line=1; +@ + +@ 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= +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) @; + 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. + +@= +{ + 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; klimit && (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. + +@= 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@> + @; + } + } else { + if (get_line()==0) { + err_print("! Input ended in mid-comment"); +@.Input ended in mid-comment@> + loc=buffer+1; @; + } + } + + c=*(loc++); + if (c==vertical_char) return(bal); + @; + if (phase==2) app_tok(c); + @; + } +} + + + +@ @= +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--; @; + } +} +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. + +@= +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. + +@= +typedef struct { + eight_bits cat; + eight_bits mathness; + union { + text_pointer Trans; + ===> @@; + } trans_plus; +} scrap; +typedef scrap *scrap_pointer; + +@ @d trans = trans_plus.Trans /* translation texts of scraps */ +@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))) + + +@= +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 + +@ @= +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: @; + } + } +} +#endif DEBUG + +@ @= +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@; + +@= +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. + +@= { + /* |ignore_scrap| becomes part of the grammar */ + @@; + 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 +@@; +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=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. +@= + +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 && nxlink; + } + @; +} + +@ 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|. + +@= + 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; + } + @; +#ifdef DEBUG + @; +#endif DEBUG + pp--; /* we next say |pp++| */ +} + +@ @= +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; @; +#ifdef DEBUG + @; +#endif DEBUG + pp--; /* we next say |pp++| */ + return; + } + for (i=j; i= +while (1) { + @; + 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; + @; +} + +@ If we get to the end of the scrap list, category codes equal to zero are +stored, since zero does not match anything in a production. + +@= +if (lo_ptrcat=hi_ptr->cat; lo_ptr->mathness=(hi_ptr)->mathness; + lo_ptr->trans=(hi_ptr++)->trans; + } + for (i=lo_ptr+1;i<=pp+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. + +@= +#ifdef DEBUG +int tracing; /* can be used to show parsing details */ +#endif DEBUG + +@ @= { + 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; + @; + @; +} + +@ 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. + +@= { + @; + 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); +} + +@ @= +#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 + +@ @= +#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; + 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; + +@ @= +@; +switch (next_control) { + @@; + case string: case constant: case verbatim: @; + break; + case @`\n': @; break; + case identifier: @; break; + case TeX_string: @; 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: +@ +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 +@= +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@> + +@= +if (next_control==constant) app_str("\\O{"); +@.\\O@> +else if (next_control==string) app_str("\\.{"); +@.\\.@> +else app_str("\\={"); +@.\\=@> +while (id_first + @@; + app_tok(*id_first++); +} +small_app('}'); +@@; + +@ @= +switch (*id_first) { + case ' ':case '\\': + case '%':case '$': case '^':case '`': + case '#': + case '{': case '}': case '~': case '&': case '_': + small_app('\\'); break; + + } + +@ @= +app_str("\\hbox{"); while (id_first@; + + +@ 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; /* spider */ + @; + } + else { + C_parse(0); + } +} +} + +@ @= + 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 */ + + +@ @= +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 */ + +@= typedef int mode; +typedef struct { + token_pointer end_field; /* ending location of token list */ + token_pointer tok_field; /* present location within token list */ + boolean mode_field; /* interpretation of control tokens */ +} output_state; +typedef output_state *stack_pointer; + +@ @d cur_end = cur_state.end_field /* current ending location in |tok_mem| */ +@d cur_tok = cur_state.tok_field /* location of next output token in |tok_mem| */ +@d cur_mode = cur_state.mode_field /* current mode of interpretation */ +@d init_stack = stack_ptr=stack;cur_mode=outer /* initialize the stack */ + +@= +output_state cur_state; /* |cur_end|, |cur_tok|, |cur_mode| */ +output_state stack[stack_size]; /* info for non-current levels */ +stack_pointer stack_ptr; /* first unused location in the output state stack */ +stack_pointer stack_end=stack+stack_size-1; /* end of |stack| */ +#ifdef STAT +stack_pointer max_stack_ptr; /* largest value assumed by |stack_ptr| */ +#endif STAT + +@ @= +#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. + +@= +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: @; break; + case mod_name: @; break; + case math_bin: case math_rel: case math_op: + @; break; + case cancel: c=0; while ((a=get_output())>=indent && a<=big_force) { + if (a==indent) c++; if (a==outdent) c--; + } + @; + goto reswitch; + case big_cancel: c=0; + while (((a=get_output())>=indent || a==' ') && a<=big_force) { + if (a==indent) c++; if (a==outdent) c--; + } + @; + goto reswitch; + case indent: case outdent: case opt: case backup: case break_space: + case force: case big_force: @; 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. +@= +out('\\'); +if (a==identifier) + if (length(cur_name)==1) out('|')@; +@.\\|@> + else out('\\')@; +@.\\\\@> +else out('&')@; /* |a==res_word| */ +@.\\\&@> +out_name(cur_name); + +@ @= +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. + +@= +if (a@; + +@ 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}'). + +@= { + b=a; save_mode=cur_mode; c=0; + while (1) { + a=get_output(); + if (a==cancel || a==big_cancel) { + @; + goto reswitch; /* |cancel| overrides everything */ + } + if ((a!=' ' && abig_force) { + if (save_mode==outer) { + if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\P",4)==0) + goto reswitch; + @; + 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= + 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. + +@= { + 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(':'); @; + out_str((is_file? "\\XF":"\\X")); +} + +@ @= +k=cur_name->byte_start; k_limit=(cur_name+1)->byte_start; +cur_mod_name=cur_name; +while (k@; + if (b!=vertical_char) out(b)@; + else { + @@; + save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1; + *limit=vertical_char; output_C(); + loc=save_loc; limit=save_limit; + } +} + +@ @= +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. + +@= +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) @@; + 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; + } +} + +@ @= { + 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) @; +} + +@ 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@> + +@= +int save_line; /* former value of |out_line| */ +ASCII *save_place; /* former value of |out_ptr| */ + +@ @= { + module_count++; + @; + save_position; + @; + @; + @; + @; + @; +} + +@ 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. + +@= +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. + +@= 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: @; break; + case hex: @; 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= { +out_str("\\O{\\~"); + while ('0'<=*loc && *loc<'8') out(*loc++); +out('}'); +} + +@ @= { +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. + +@= +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) @@; + else @; + 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 */ +} + +@ +@= { + small_app(backup); app_str("\\D"); /* this will produce `\&{define}' */ +@.\\D@> +@@; + 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); + @; + if (next_control==@`=') { + small_app('\\'); small_app('S'); /* equivalence sign */ + @@; + } 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 */ + } +} + +@ @=goto punt_the_definition; + +@ @= +@@; +if (next_control==@`(') { + small_app(@`('); + do { + @@; + if (next_control==identifier) { + small_app(id_flag+id_lookup(id_first, id_loc,normal)-name_dir); + @@; + } else { + err_print("! Improper 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 )"); + @; + } + @@; + /* first token following parameter list */ +} + + + + +@ @= { + app_str("\\F"); app_scrap(SP_ignore_scrap,no_math); + /* this will produce `\&{format}' */ +@.\\F@> +@@; +/* 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 */ + @@; + 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); + @@; + } + } + /* 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. + +@= +name_pointer this_module; /* the current module name, or zero */ + +@ @= +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; + @; + } + while (next_control<=module_name) { + outer_parse(); + @; + } + finish_C(); +} + +@ @= +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); +@ +/* this forces a line break unless `\.{@@+}' follows */ + +@ @= +if (next_control + 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); + @ + next_control=get_next(1); + } +} + +@ Cross references relating to a named module are given after the module ends. + +@= +if (this_module>name_dir) { + @; + 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|. + +@= +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. + +@= + 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"); + @; + out('.'); +} + +@ The following code distinguishes three cases, according as the number +of cross-references is one, two, or more than two. Variable |q| points +to the first cross-reference, and the last link is a zero. + +@= +q=cur_xref; if (q->xlink->num>flag) out('s'); /* plural */ +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 */ +} + +@ @= +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. + +@= +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(); @; + } + finish_line(); out_str("\\inx"); finish_line(); +@.\\inx@> + @; + @; + out_str("\\fin"); finish_line(); +@.\\fin@> + @; + 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. + +@= +sixteen_bits k_module; /* runs through the 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. + +@= +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. + +@= { +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|. + +@ @= +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 */ + +@= +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 + +@ @= +#ifdef STAT +max_sort_ptr=scrap_info; +#endif STAT + + +@ The desired alphabetic order is specified by the |collate| array; namely, +|collate[0]= +ASCII collate[102]; /* collation order */ + +@ We use the order $\hbox{null}<\.\ <\hbox{other characters}<\.\_< +\.A=\.a<\cdots<\.Z=\.z<\.0<\cdots<\.9.$ + +@= +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_ptr=scrap_info; unbucket(1); +while (sort_ptr>scrap_info) { + cur_depth=sort_ptr->depth; + if (blink[sort_ptr->head-name_dir]==0 || cur_depth==infinity) + @@; + else @; +} + +@ @= { + 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); +} + +@ @= { + cur_name=sort_ptr->head; + do { + out_str("\\:"); +@.\\:@> + @; + @; + cur_name=blink[cur_name-name_dir]; + } while (cur_name); + --sort_ptr; +} + +@ @= +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\,$\.]'. + +@= +@; +do { + out_str(", "); cur_val=cur_xref->num; + if (cur_val + cur_xref=cur_xref->xlink; +} while (cur_xref!=xmem); +out('.'); finish_line(); + +@ List inversion is best thought of as popping elements off one stack and +pushing them onto another. In this case |cur_xref| will be the head of +the stack that we push things onto. + +@= +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. +@=boolean do_file; +@ @= +do_file=(1==1); +mod_print(root); +do_file=(1==0); +mod_print(root); + + + +@ @= +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 + @; +#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 + +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 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 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 stmt --> stmt + +(open|lsquare) math close --> math + +# make exponentials superscripts +math <"^{"> exponent math <"}"> --> math + +math lbrace --> lbrace +lbrace stmt --> lbrace +lbrace close --> stmt + +if <"\\"-space> math --> ifmath +ifmath lbrace --> ifbrace +ifmath newline --> ifline +ifbrace stmt --> ifbrace +ifbrace close else <"\\"-space> if --> if +ifbrace close else lbrace --> ifbrace +ifbrace close else newline --> ifline +ifbrace close --> stmt +(ifline|ifmath) stmt else <"\\"-space> if --> if +(ifline|ifmath) stmt else lbrace --> ifbrace +(ifline|ifmath) stmt else newline --> ifline +(ifline|ifmath) stmt else --> ifmath +(ifline|ifmath) stmt --> stmt + +for <"\\"-space> math --> formath +formath lbrace --> forbrace +formath newline --> forline +forbrace stmt --> forbrace +forbrace close --> stmt +(forline|formath) stmt --> 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 end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin 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 continuation ending --> stmt +beginning ending --> stmt +beginning (stmt|ignore_scrap) --> beginning + +case <"\\"-space> math <"\\"-space> is --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation (stmt|ignore_scrap) --> continuation +continuation continuation --> continuation + + +declaration beginning continuation ending --> stmt +declaration beginning ending --> stmt +declaration ending --> stmt +declaration (stmt|ignore_scrap) --> declaration + +else --> continuation +elsif <"\\"-space> math <"\\"-space> then --> continuation + +exception --> continuation + +generic declaration --> declaration +generic (stmt|ignore_scrap) --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen stmt --> beginning +ifthen <"\\"-space> math <"\\"-space> else --> ifthen +ifthen <"\\"-space> math <"\\"-space> close <"\\"-space> if --> math +ifthen <"\\"-space> math <"\\"-space> elsif --> if + + +is --> math + +loop --> 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 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 stmt --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + + openlabel math closelabel --> math + +or --> continuation + +private --> beginning + +proc <"\\"-space> math is <"\\"-space> separate --> math +proc <"\\"-space> math is --> declaration +proc <"\\"-space> math terminator --> stmt + +record <"\\"-space> at <"\\"-space> math terminator --> beginning +record --> beginning + +semi --> terminator + +stmt stmt --> stmt + +when <"\\"-space> math arrow --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt ending --> ending +whengroup stmt whengroup --> whengroup + +where --> 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 annotation_group 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. + (annotation_group|virtual_group) --> 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 end newline +macros begin +\def\commentbegin{{\tt -- }} +macros end + +line begin 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 continuation ending --> stmt +beginning ending --> stmt +beginning (stmt|ignore_scrap) --> beginning + +case <"\\"-space> math <"\\"-space> is --> beginning + +close semi --> ending +close <"\\"-space> ? semi --> ending +close <"\\"-space> ? <"\\"-space> ? semi --> ending + +continuation (stmt|ignore_scrap) --> continuation +continuation continuation --> continuation + + +declaration beginning continuation ending --> stmt +declaration beginning ending --> stmt +declaration ending --> stmt +declaration (stmt|ignore_scrap) --> declaration + +else --> continuation +elsif <"\\"-space> math <"\\"-space> then --> continuation + +exception --> continuation + +generic declaration --> declaration +generic (stmt|ignore_scrap) --> generic + +if <"\\"-space> math <"\\"-space> then --> ifthen +ifthen stmt --> beginning +ifthen <"\\"-space> math <"\\"-space> else --> ifthen +ifthen <"\\"-space> math <"\\"-space> close <"\\"-space> if --> math +ifthen <"\\"-space> math <"\\"-space> elsif --> if + + +is --> math + +loop --> 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 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 stmt --> stmt +math terminator --> stmt + +open close --> math +open math close --> math +open [ math semi ] --> open math + + openlabel math closelabel --> math + +or --> continuation + +private --> beginning + +proc <"\\"-space> math is <"\\"-space> separate --> math +proc <"\\"-space> math is --> declaration +proc <"\\"-space> math terminator --> stmt + +record <"\\"-space> at <"\\"-space> math terminator --> beginning +record --> beginning + +semi --> terminator + +stmt stmt --> stmt + +when <"\\"-space> math arrow --> whengroup +[ when <"\\"-space> math ] terminator --> math terminator +whengroup stmt ending --> ending +whengroup stmt whengroup --> whengroup + +where --> 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 annotation_group 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. + (annotation_group|virtual_group) --> 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 <> in annotations +# and ignores <> 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 <> 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 <> 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 +@@; +@@; +@@; +@@; +@@; +@@; +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. + +@= +--: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. + +@= +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. +@= +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|). + + + + +@ @= +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; + +@ @= +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; + +@ @= + 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 + @ + @ + @ + @ + @ + @ + @ + @ + end +} def + +@ Four arguments as described above. +@= +/uniqueid exch def +/strokewidth exch def +/newfontname exch def +/basefontname exch def + +@ @= +/basefontdict basefontname findfont def + +@ @= +/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.) + +@= +basefontdict /UniqueID known not => + {/numentries numentries 1 add def} if + +@ @= +/outfontdict numentries dict def + +@ @= +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 + +@= +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|. +@= +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 @ +@ +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@> +@= +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. +@= +/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 +@ +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 + +token [ category open translation +token ] category close translation +token { translation <"\\{"> category open +token } translation <"\\}"> category close +token < category open translation +token > category close translation +token # category hash translation <"\\#"> +# use mathness no here to avoid extra space after / +token / category slash tangleto 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 tangleto <""> +token <= category dent translation 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 math --> slashed_math +slashed_math* def --> math +[ slashed_math ] (close|end) --> math (close|end) + + newline newline --> ignore_scrap + newline --> ignore_scrap + +# want indent inside open/close pairs +open math close --> math +# could have empty procedure +open close --> math + +slash math --> slashed_math + +number hash number --> math +number --> math +math math --> math + +begin --> math + 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 + +token .^ category binop translation <"\\ro{.\\^}"> tangleto +token .* category binop translation <"\\ro{.*}"> tangleto +token .+ category binop translation <"\\ro{.+}"> tangleto +token ./ category binop translation <"\\ro{./}"> tangleto +token ^ category binop translation <"\\eo\\^"> +token ** category binop translation <"\\eo\\^"> +token := category binop translation <"\\ro\\leftarrow"> +token != category binop translation <"\\ro\\NEQ"> tangleto +token <> category binop translation <"\\ro\\NEQ"> tangleto +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 +token '( category listopen translation <"'("> tangleto +token '[ category listopen translation <"'["> tangleto +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 +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 + ignore_scrap ? --> #2 + 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 --> stmt +simp binop stmt --> stmt +simp <"\\bo"> unorbinop stmt --> stmt +<"\\uo"> (unop|unorbinop) stmt --> stmt + +quote ? --> simp +simp comma simp --> simp +simp terminator --> stmt +stmt stmt --> stmt + +# Lists and vectors +open simp 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 close --> simp + +# Function calls +simp open <"$\\,$"> close --> simp +simp open <"\\Ri"-cancel> simp close --> simp + +# Procedure definitions +(mode|procmode) proc --> proc +proc stmt* stmt --> stmt +(simp|stmt) proc --> proc + +# Declarations +mode (terminator|open) --> #2 +mode stmt --> stmt +proc stmt begin [ decl stmt* ] --> proc stmt begin stmt +(decl|clear|switch|do) stmt* --> stmt + +# Blocks +[ simp ] end --> stmt end + begin end --> simp + begin stmt end terminator --> stmt +[ begin stmt end ] !terminator --> simp !terminator +progn_begin end --> simp + progn_begin stmt end terminator --> stmt +[ progn_begin stmt end ] !terminator --> simp !terminator + +# For statements in all flavours +for for --> for +for [ simp colon simp ] --> for simp +for [ simp <"\\Rs"> (step|until|switch) simp ] --> for simp +[ for simp <"\\Rs"> do simp ] (comma|close|else|end) --> simp (comma|close|else|end) + for simp <"\\Rs"> do simp terminator --> stmt + for simp <"\\Rs"> do stmt --> stmt + +# If statements +if simp <"\\Rs"> then --> ifthen +ifthen simp <"\\Rs"-outdent-force> else --> ifelse +[ ifelse simp ] (comma|close|else|end) --> simp (comma|close|else|end) +[ (if|ifthen) simp ] (comma|close|end) --> simp (comma|close|end) + (ifthen|ifelse) simp terminator --> stmt + (ifthen|ifelse) stmt --> stmt + +# Where +[ simp <"\\Rs"-opt-1> where simp ] (close|else|end) --> simp (close|else|end) +simp <"\\Rs"-opt-1> where simp terminator --> stmt + +# Return statement +[ return simp ] (close|else|end) --> simp (close|else|end) + return simp terminator --> stmt + return stmt --> stmt + +# Repeat statements +[ repeat <"\\Rs"-opt-7-indent> simp until simp ] (comma|close|else|end) --> simp (comma|close|else|end) + repeat <"\\Rs"-opt-7-indent> simp until simp terminator --> stmt + +# Labels +!for [ simp colon <"\\Rs"-cancel> (simp|end) ] --> !for #4 + +# Module use +stmt module_scrap terminator --> 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 +@@; +@@; +@@; +@@; +@y +@u +#define NEWLINES_IN_MACROS +@@; +@@; +@@; +@@; +@z + +@x + if (isdigit(c) || c=='\\' || c=='.') @@;/*spider*/ + else if (isalpha(c) || c=='_' || c=='$') @@;/*spider*/ + else if (c=='\'' || c=='\"') @@;/*spider*/ +@y + if (isdigit(c)) @@;/*spider*/ + else if (isalpha(c) || c=='_' || c=='!') @@;/*spider*/ + else if (c=='\"') @@;/*spider*/ +@z + +@x +@ @= {/*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 +@ @= {/*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|. + +@= {/*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|. + +@= {/*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)) @@; /*spider*/ + else if (isalpha(c) || c=='_') @@;/*spider*/ + else if (c=='\'' || c=='"') @@;/*spider*/ +@y + if (isdigit(c)) @@;/*spider*/ + else if (isalpha(c) || c=='_' || c=='!') @@;/*spider*/ + else if (c=='\"') @@;/*spider*/ +@z + +@x +@ @= {/*spider*/ + id_first=--loc; + while (isalpha(*++loc) || isdigit(*loc) || *loc=='_'); + id_loc=loc; return(identifier); +} +@y +@ @= {/*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|. + +@= {/*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|. + +@= {/*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 + +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 + +# 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 exptupling rparen --> atexp +lsqbracket rsqbracket --> atexp +lsqbracket explist rsqbracket --> atexp +lparen expblock rparen --> atexp +let dec in exp end --> atexp +lparen exp rparen --> atexp + +exp comma exp --> exptupling +exptupling comma exp --> exptupling + +exp semi exp --> expblock +expblock semi exp --> expblock + +lsqbracket [ exp ] --> lsqbracket explist +lsqbracket [ explist comma exp ] --> lsqbracket explist + +id equals exp --> exprow +exprow comma 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 match --> exp +raise exp --> exp +if exp then exp else exp --> exp +while exp do exp --> exp +case exp of match --> exp +fn match --> 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* withtype typbind --> dec +abstype datbind* with dec end --> dec +abstype datbind* withtype typbind with dec end --> dec +exception exbind* --> dec +local dec in dec end --> dec +open longvarlist --> dec +dec dec --> dec +dec semi 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 exp ] --> fun prefvalbind +fun [ id* atpatlist colon ty equals exp ] --> fun prefvalbind +fun [ prefvalbind vertbar op id atpatlist colon ty equals exp ] --> fun prefvalbind +fun [ prefvalbind vertbar id atpatlist colon ty equals exp ] --> fun prefvalbind +fvalbind and [ op id* atpatlist colon ty equals exp ] --> fvalbind and prefvalbind +fvalbind and [ vertbar id* atpatlist colon ty equals exp ] --> fvalbind and prefvalbind +fvalbind and [ prefvalbind vertbar op id atpatlist colon ty equals exp ] --> fvalbind and prefvalbind +fvalbind and [ prefvalbind vertbar id atpatlist colon ty equals exp ] --> 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 dec end --> exp + +# whereever the SML grammar has strdec, have to use dec too +structure strbind --> dec + +structure [ id* colon sigexp equals exp ] --> structure strbind +structure [ id* colon id equals exp ] --> structure strbind +structure [ id* equals exp ] --> structure strbind +strbind and id* colon sigexp equals exp --> strbind +strbind and id* colon id equals exp --> strbind +strbind and id* equals exp --> strbind + +# whereever the SML grammar has sigexp, have to use id too +sig spec end --> sigexp + +signature sigbind --> sigdec +sigdec sigdec --> sigdec +sigdec semi sigdec --> sigdec + +signature [ id* equals sigexp ] --> signature sigbind +signature [ id* equals id ] --> signature sigbind +sigbind and id* equals sigexp --> sigbind +sigbind 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 spec --> spec +spec semi spec --> spec + +val [ id* colon ty ] --> val valdesc +valdesc and id* colon ty --> valdesc + +type [ tyvarseq id* ] --> type typdesc +typdesc 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 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 and id* of ty --> condesc +condesc and id* --> condesc + +exception [ id* of ty ] --> exception exdesc +exception [ id* ] --> exception exdesc + +exdesc and id* of ty --> exdesc +exdesc and id* --> exdesc + +structure [ id* colon sigexp ] --> structure strdesc +structure [ id* colon id ] --> structure strdesc +strdesc and id* colon sigexp --> strdesc +strdesc 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 and longvar equals longvar --> shareq +shareq and type longvar equals longvar --> shareq + +functor funbind --> fundec +fundec fundec --> fundec +fundec semi fundec --> fundec + +functor [ id* lparen id colon sigexp rparen colon sigexp equals exp ] --> functor funbind +functor [ id* lparen id colon sigexp rparen equals exp ] --> functor funbind +funbind and id* lparen id colon sigexp rparen colon sigexp equals exp --> funbind +funbind and id* lparen id colon sigexp rparen equals exp --> funbind + +sigdec --> topdec +fundec --> topdec +dec --> topdec +use scon --> topdec + + +topdec topdec --> topdec +topdec semi 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 +To: Norman Ramsey +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)) @@; /*spider*/ +! else if (isalpha(c) || (c=='_' && (*loc=='_' || isalpha(*loc)))) @@;/*spider*/ + else if (c=='\'' || c=='"') @@;/*spider*/ + else if (c==at_sign) @@; + else if (c==' ' || c==tab_mark) continue; /* ignore spaces and tabs */ +--- 543,549 ---- + } + } + if (isdigit(c)) @@; /*spider*/ +! else if (isalpha(c) || c=='_') @@;/*spider*/ + else if (c=='\'' || c=='"') @@;/*spider*/ + else if (c==at_sign) @@; + else if (c==' ' || c==tab_mark) continue; /* ignore spaces and tabs */ +*************** +*** 557,563 **** + + @ @= {/*spider*/ + id_first=--loc; +! while (isalpha(*++loc) || isdigit(*loc) || *loc=='_' || *loc=='\''); + id_loc=loc; return(identifier); + } + +--- 557,563 ---- + + @ @= {/*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 translation <"\\SL{"> mathness maybe +token .] category close tangleto <")"> translation <"}"> mathness maybe +token [= category open tangleto 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 translation <"\\'{"> mathness maybe +token '' category tick tangleto 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 mathness yes translation <"\\wedge"> +token || category binop tangleto 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 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 dec end --> sig_body +signature <"\\"-space> id* equal sig_body --> dec +functor [ <"\\"-space> id* ] --> functor funhead +functor funhead pat equal struct_object --> dec +struct dec 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 ] (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 multimath ] (semi|val|fun|type|let|struct|openop|and|end|close|in) --> val valbody (semi|val|fun|type|let|struct|openop|and|end|close|in) + val valbody and --> val + val valbody --> dec +datatop <"\\"-space-indent> codeuse --> datahead +datatop <"\\"-space> ty* <"\\"-space-indent> equal --> 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* choice ] id of --> datam id of +datam <"\\"-space> id* 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 choice --> datam +[ (datat|datam) <"\\"-space> id ] (semi|val|fun|type|datatype|let|struct|openop|end|in) --> dec (semi|val|fun|type|datatype|let|struct|openop|end|in) +[ datahead ] (semi|val|fun|type|datatype|let|struct|openop|end|in) --> dec (semi|val|fun|type|datatype|let|struct|openop|end|in) +datat <"\\"-space> id (and|withtype) --> datatop +datahead (and|withtype) --> datatop +datatype --> datatop +abstype --> datatop +datahead with dec 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) [ let ] --> (equal|arrow) letf +!(ignore_scrap|equal|arrow) [ let ] --> !(ignore_scrap|equal|arrow) letf +letf dec in (math|multimath) end --> multimath +local dec in dec end --> dec + +dec semi --> dec +[ (math|multimath) semi ] dec --> dec dec +[ (math|multimath) ] dec --> dec dec +dec [ (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 dec ] !(semi|ignore_scrap) --> dec !(semi|ignore_scrap) + +[ case <"\\"-space> (math|multimath) of multimatch ] (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) +[ fn (multimatch|match) ] (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) handle (multimatch|match) ] (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 math ] (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 multimath ] (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) 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 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 and --> fun +fun [ funhead <"\\"-space> pat <"\\"-space> equal math ] !(binop|handle|math|id|open|multimath|ignore_scrap) --> fun funbody !(binop|handle|math|id|open|multimath|ignore_scrap) +fun [ funhead <"\\"-space> pat <"\\"-space> equal multimath ] !(binop|handle|math|id|open|multimath|ignore_scrap) --> fun funbody !(binop|handle|math|id|open|multimath|ignore_scrap) + +equal [ multimath ] --> equal math +[ if <"\\"-space> (math|multimath) <"\\"-space> then (math|multimath) else (math|multimath) ] (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 <"\\"-space> (math|multimath) ] (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) comma (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 math close ] !(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 math 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) 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 multimath close ] --> (then|semi|else|in|equal|arrow) multimath +!(then|semi|else|in|equal|arrow) [ open multimath close ] --> !(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 }} +} +\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 + % + % + %; + % + + % 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. + %= +datatype Decl = + Var_Decl of string * Term + | Val_Decl of string * Term + | Rec_Decl of string * Term +and + %; + + %*|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 = Var of string + % $\Me{\Sy}\En\Co\St=\Co\Tp{\En\ME{\Sy}}{\St}$ + %= + fun Me (Var x) e c s = c (lookup x e ,s) + |; + + % Integer constants. + %= + |: Numeral of int + % $\Me{\Nu}\En\Co\St=\Co\Tp{{\bf V}\ME{\Nu}}{\St}$ + %= + |= 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. + %= + |: 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]$ + %= + |= 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$ + %= + |= 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. + %= + |= 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. + %= + |: 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}$ + %= + |= 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. + %= + |: 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. + %= + |= 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. + %= + |: 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. + %= + |= 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. + %= + |: 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}$ + %= + |= 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. + %= + |: Fst of Term + % $\Me{{\tt fst}~\Ex}\En\Co\St=\Co\Tp{\pi_1(\Me{\Ex}\En\CO\St)}{\St}$ + %= + |= 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. + %= + |: Snd of Term + % $\Me{{\tt snd}~\Ex}\En\Co\St=\Co\Tp{\pi_2(\Me{\Ex}\En\CO\St)}{\St}$ + %= + |= 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. + %= + |: 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$ + %= + |= 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. + %= + |: Seq of Term * Term + % $\Me{\Ex_1{\tt ;}\Ex_2}\En\Co\St=\Me{\Ex_1}\En\{\Me{\Ex_2}\En\Co\}\St$ + %= + |= 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}. + %= + |: 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$ + %= + |= 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. + %= + |: Ref of Term + % $\Me{{\tt ref}~\Ex}\En\Co\St=\Co\Tp{\Lo}{\St[\Me{\Ex}\En\CO\St/\Lo]}$ + %= + |= 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. + %= + |: Deref of Term + % $\Me{{\tt .}\Ex}\En\Co\St=\Co\Tp{\St\ME{\Me{\Ex}\En\CO\St}}{\St}$ + %= + |= 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. + %= + |: 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]}$ + %= + |= 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. + %= + |: 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}$ + %= + |= 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. + %= + |: 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}$ + %= + |= 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. + %= + |: Neg of Term + % $\Me{{\tt -}\Ex}\En\Co\St=\Co\Tp{-\Me{\Ex}\En\CO\St}{\St}$ + %= + |= 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. + %= + |: 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}$ + %= + |= Me (Less (E1,E2)) e c s = + Me E1 e (fn (intValue V1,_) => + Me E2 e (fn (intValue V2,_) => c (boolValue (V1 raise NotInteger) s + |_ => raise NotInteger) s + |; + + % Calculate the boolean complement of the expression. + %= + |: Not of Term + % $\Me{\neg\Ex}\En\Co\St=\Co\Tp{\neg\Me{\Ex}\En\CO\St}{\St}$ + %= + |= 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. + %= +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. + %= +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 '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. + %= +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. + %= + 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. + %=fun fix f x = f (fix f) x; + + % The empty continuation. + %=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. + %= + 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 (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. + %= + 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. + %= + 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 + %= + 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 (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 +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 ::= +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 --> math +at --> math +decl decl --> decl +decl simp* colon <"\\MO"-indent-force> --> mbar +decl simp [ simp* ] --> decl simp math +dollar dollar --> math +dollar --> unop + in open --> wbegin +in --> math +# following for semantic equations and attribute declarations +lbrace (decl) close --> 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 (math|decl) close --> 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 math close --> math + + + +math 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 bar --> mbar +mbar math semi --> decl + +mcolon math semi --> decl +mcolon math close --> close +mcolon math comma --> mcmcom + +mcmcom math comma --> mbar +mcmcom math colon <"\\MO"> --> mcolon + + +math comma <"\\,"> math --> math + + +on --> math +open math close --> math +open close --> math +# The following doesn't do indentation right +# question math colon ? - - > #4 + question math colon --> condbegin +[ condbegin math ] (semi|close|comma|colon) --> math (semi|close|comma|colon) + +less <"\\LN"> simp <"\\RN"> greater --> math +less <"<"> --> binop +greater <">"> --> binop + +literal --> math +simp --> math +tbegin decl --> decl +transform <"\\;"> math --> tbegin +wbegin math close --> math +wbegin close --> math +# following for leaving commas in last clause in with statements +wbegin mcmcom close --> math +with math (math|semi) --> math +with math <"\\,"> open --> wbegin + +# let statements +math <"\\"-space-opt-3> and <"\\"-space> math --> math +(forcelet|let) math semi --> forcelet +forcelet math in <"\\"-space> open --> letopen +letopen math close --> math +let math in <"\\"-space> open --> letopen +# following recognizes semi as a possible terminator as well as separator +forcelet in <"\\"-space> open --> 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 = +@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 = +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 + +@ +@ = +const infinity := 10.0 ** 200 +for k : 2 .. m +@ +@ +@ +end for + +@ +@ = +body procedure least_cost +c_star(1) := l(0,n) +@ +@ +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|. +@ = +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 +@ +@ +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. +@ = +c_star(k) := c_k(0) +assert relation (c_star(k), c_star(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. + +@ +@ = +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 + record --> recordbody +# Eat up a newline, if present (this is to allow free formatting of the record). +(recordbody|unionbody|casebody) newl --> #1 +recordbody idtypespec --> recordbody +# End rule for record, union, and case: +(recordbody|unionbody|casebody) end <"\\"-space> (record|union|case) --> 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 + union <"\\"-space> idtypespec <"\\"-space> of --> unionbody + union colon typespec <"\\"-space> of --> unionbody +(unionbody|casebody) labelexpn --> #1 +unionbody idtypespec --> 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 --> 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 --> 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 + 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 + begin --> stmt +reserved end ilk end_like +ilk end_like category end + 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 --> stmt + else --> stmt + elsif <"\\"-space> expn <"\\"-space> then --> 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 --> 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 --> casebody +casebody stmt --> 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 --> stmt +# The "end for" rule is in fgm. + +# fgm: the common "end ..." rule: + 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 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 --> modulestub +modulestub stmt --> modulestub +modulestub subproghead newl --> modulestub +modulestub 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: +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 + record --> recordbody +# Eat up a newline, if present (this is to allow free formatting of the record). +(recordbody|unionbody|casebody) newl --> #1 +recordbody idtypespec --> recordbody +# End rule for record and union: +(recordbody|unionbody) end <"\\"-space> (record|union) --> 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 + union <"\\"-space> idtypespec <"\\"-space> of --> unionbody + union colon typespec <"\\"-space> of --> unionbody +(unionbody|casebody) labelexpn --> #1 +unionbody idtypespec --> 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 --> 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 --> 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 + 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 + begin --> stmt +reserved end ilk end_like +ilk end_like category end + 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 --> stmt + else --> stmt + elsif <"\\"-space> expn <"\\"-space> then --> 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 --> 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 --> casebody +casebody stmt --> casebody +casebody 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 --> stmt +# The "end for" rule is in fgm. + +# fgm: the common "end ..." rule: + 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 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 --> modulestub +modulestub stmt --> modulestub +modulestub subproghead newl --> modulestub +modulestub 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] [-I] [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 +#include +@i pathopen.h +static char at_sign = '@@'; + +main(argc,argv) + int argc; char **argv; +{ + FILE *fp; + + @@; + + 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); + } +} + +@ @= +while (--argc>0) + if (switchar(**++argv)) + switch(*++(*argv)) { + case 'a': + ++*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 \#}. +@= +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 */ + @@; + } else if (c=='\n') goto end_line; + } else if (c=='\n') goto end_line; + } + } while ((c=getc(fp))!=EOF); + fclose(fp); +} + +@ @= +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. +@= +fprintf(stderr,"Usage:\n"); +fprintf(stderr,"\tfilesplit prefix numbers...\n"); +exit(1); + + +@ @c +#include +main (argc, argv) + int argc; + char ** argv; +{ + char *prefix; + @; + + + if (argc--<3) { + @; + } + + prefix = *++argv; + argc--, argv++; + @; + 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. +@= + int from_line, to_line; + int this_line; /* the number of the next line scheduled to be + printed */ + +@ +@= +multi_output=1; +@; +printing=0; +from_line=0; +this_line=1; +while (argc!=0) { + @; + @; + while (this_line != to_line) { + @; + } + @; + from_line = to_line; + printing = next_printing; + } +@; +while (1) { + @; + } +finish: + @; + + +@ We ended prematurely if |from_line!=to_line|. +@= +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. +@= + FILE *output; + char filename[255]; + int sequence_number=0; + int multi_output; +@ @= +if (!strcmp(prefix,"-")) { + output=stdout; + multi_output=0; + } + +@ @= +if (printing && multi_output) { + sprintf(filename,"%s%05d", prefix, sequence_number++); + if ((output=fopen(filename,"w"))==NULL) { + @; + } + } + +@ @= +if (printing && multi_output) fclose(output); + +@ Here's how the copying works +@= +while ((c=getchar())!=EOF) { + if (printing) putc(c,output); + if (c=='\n') { + this_line++; + break; + } + } +if (c==EOF) goto finish; +@ @=char c; + +@ Since we determine sign when we read the target, we save the sign to set +|printing| the next time around. +@=int printing, next_printing; + + + +@ Here's our argument processing: +@ @= +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); + } + + +@ @= +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 +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 , 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| */ + +@= +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. + +@= +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{|}~ "); + @; + @; +} + +@ The following system-independent code makes the |xord| array contain +a suitable inverse to the information in |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@> + +@= /* nothing needs to be done */ + +@ +@d text_char = char /* the data type of characters in text files */ + + +@= +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 + +@= +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 +@= +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 + +@= +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. + +@= +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();} + +@= + 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|. + +@= + 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@> + +@= + 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 + +@= +@!int history; + + +@ We must initialize this variable at the very beginning. + +@= +history=spotless; +@ At the end of the job we may want to print out the 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)) @; + @; +} + +@ End of file is special if this file is the master 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@> + +@= +(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@> + } +@@; +input_organization[i].limit=final_limit; + +@ We have to check for end of file in the middle of reading +@= +if (input_organization[i].limit==0 && c==EOF) + @@; + + + + + 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 +/*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=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_ch0))actual_input--; +} +if(input_has_ended&&(actual_input==0))return; +test_input= (next_available_file); +i= actual_input; +while((test_input==(next_available_file))&&(i100) +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 +@@; +@@; +@@; +@@; +@# +main (argc, argv) + int argc; + char **argv; +{ + int i,j; + + @@; + if (verbose) + print_ln(banner); /* print a ``banner line'' */ + @; + @; + @; + @; + /* here files should be closed if the operating system requires it */ + @ + jump_out(); +} + +@ The guts of the program are simple: we drag each line through the mud: +@= +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"); +@; + + +@ 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. + +@= +for (i=1; i + +@ 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. + +@= +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. +@= +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=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'))); +} + +@ @=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'))); +} + +@ @=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); +} + +@ @=boolean file_open(); + +@ This procedure opens all the input files. + +@c +@@;@% + open_input() /* prepare to read |input_files| */ +{ +int i; + @; + actual_input=0; +no_ch=0; +while (++no_ch + 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. +@= + 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. + +@= + init_change_file(i,b) + int i; + boolean b; +{ + @; + @; +} + + +@ 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). + +@= +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}. + +@= +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= +common_init(); +for (i=0; i; + @; + @; + @; +} + + +@ If |test_input| is |none|, no change file is tested. + +@d none = (next_available_file) + +@= +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 + 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; +} +} + + +@ @= +if (prod_chf) { + loop { + @; + @; + @; +} +} else +if (test_input==none) put_line(actual_input); + + +@ Check whether we have to start a change file entry. + +@= +{ + 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. + +@= +{ + 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. + +@= +{ + 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; + } + } +} + + +@ @= +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... +@= +if (++lines_processed % 100 == 0 && verbose) { + if (lines_processed % 500 == 0) + fprintf(stderr,"%d",lines_processed); + else + fprintf(stderr,"."); + } + +@ @=long int lines_processed=0; +@ @=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@> + +@= +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 +@@@@; +@@@@; +@@@@; +@@@@; +@@# +main (argc, argv) + int argc; + char **argv; +{ + int i,j; + + @@@@; + print_ln(banner); /* print a ``banner line'' */ + @@; + @@; + @@; + @@; + /* here files should be closed if the operating system requires it */ + @@; + jump_out(); +} + +@@ The guts of the program are simple: we drag each line through the mud: +@@= +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"); +@@; + + +@@ 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. + +@@= +for (i=1; i + +@@ 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. + +@@= +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. +@@= +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=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'))); +} + +@@ @@=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'))); +} + +@@ @@=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); +} + +@@ @@=boolean file_open(); + +@@ This procedure opens all the input files. + +@@c +@@@@;@@% + open_input() /* prepare to read |input_files| */ +{ +int i; + @@; + actual_input=0; +no_ch=0; +while (++no_ch + 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. +@@= + 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. + +@@= + init_change_file(i,b) + int i; + boolean b; +{ + @@; + @@; +} + + +@@ 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). + +@@= +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}. + +@@= +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= +common_init(); +for (i=0; i; + @@; + @@; + @@; +} + + +@@ If |test_input| is |none|, no change file is tested. + +@@d none = (next_available_file) + +@@= +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 + 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; +} +} + + +@@ @@= +if (prod_chf) { + loop { + @@; + @@; + @@; +} +} else +if (test_input==none) put_line(actual_input); + + +@@ Check whether we have to start a change file entry. + +@@= +{ + 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. + +@@= +{ + 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. + +@@= +{ + 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; + } + } +} + + +@@ @@= +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... +@@= +if (++lines_processed % 100 == 0) { + if (lines_processed % 500 == 0) + fprintf(stderr,"%d",lines_processed); + else + fprintf(stderr,"."); + } + +@@ @@=long int lines_processed=0; +@@ @@=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@@> + +@@= +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@>@ +program TIE(out_file); + label end_of_TIE; {go here to finish} + const @@; + type @@; + var @@; + @t\4@>@@; + procedure initialize; + var @@; + begin @ + 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@> + +@= +@{@&@=$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@> + +@= +@!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 + +@= +@!history:integer; + + +@ We must initialize this variable at the very beginning. + +@= +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. + +@= +@!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|} + +@= +@!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. + +@= +@!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. + +@= +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|. + +@= +@!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. + +@= +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|. + +@= +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 + +@= +@!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(term_in,'TTY:','/I') + + +@ Similarly we initialize terminal output to a file that +should be associated to the user's terminal interactively. +@^system dependencies@> + +@= +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 @; + @; + end; +exit: end; + + +@ End of file is special if this file is the master 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@> + +@= +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. + +@= +@!in_file_modes=(@!search,@!test,@!reading,@!ignore);@/ +@!file_types=(@!master,@!chf); + + +@ The following data structures join all informations needed to use +these input files. + +@= +@!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. + +@= +@!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 + +@= +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|. + +@= +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@> + +@= +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_len0 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. + +@= +begin + print_nl('Please enter the name of the master file: '); +@.Please enter the name ...@> + update_terminal; + @; + rd_file; + if name_field.nam_len=0 then + fatal_error('! Illegal file name'); +@.Illegal file name@> + @; + 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. + +@= +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@> + +@= +begin + print_ln('Please enter the name of change file ',no_ch:1); + print('or 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@> + +@= +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; + + +@ +@= + 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@>@ +procedure open_input; {prepare to read |input_files|} +label done; +var i:integer; +begin + @; + @; + 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 + @; + 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. + +@= +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|. + +@= +@!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@> + +@= +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. + +@= +procedure init_change_file(i:integer;b:boolean); +label continue, done, exit; +begin + with input_organization[i] do + begin + @; + @; + 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). + +@= +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}. + +@= +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. + +@= +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 + @; + @; + @; +exit: end; + + +@ If |test_input| is |none|, no change file is tested. + +@d none == (max_file_index+1) + +@= +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 + 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 + + +@ @= +if prod_chf then +begin + loop @+ begin + @; + @; + @; + end; +done: +end else +if test_input=none then put_line(actual_input) + + +@ Check whether we have to start a change file entry. + +@= +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. + +@= +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. + +@= +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 + + +@ @= +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 + + +@ @= +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. + +@= +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} + @; + @; + open_input; + @; + @; + @; +end_of_TIE: + {here files should be closed if the operating system requires it} + @; +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@> + +@= +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} -- cgit v1.2.3