home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / snobol / vanilla.arc / PM.EXE / arc / SNOBOL4.MAN
Text File  |  1990-07-31  |  365KB  |  9,312 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.                                           
  8.                                           
  9.                                           
  10.                                           
  11.           *****************************************************************
  12.           *                                                               *
  13.           *                                                               *
  14.           *                        VANILLA SNOBOL4                        *
  15.           *                                                               *
  16.           *                 TUTORIAL AND REFERENCE MANUAL                 *
  17.           *                                                               *
  18.           *           (c) Copyright 1985, 1988 by Catspaw, Inc.           *
  19.           *                                                               *
  20.           *****************************************************************
  21.                                           
  22.                                           
  23.                                           
  24.                                     Mark B. Emmer
  25.                                           
  26.                                     Catspaw, Inc.
  27.                                     P.O. Box 1123
  28.                              Salida, Colorado 81201 USA
  29.                               Telephone: (719) 539-3884
  30.             
  31.  
  32.             Vanilla SNOBOL4 and all accompanying documentation are copy-
  33.             righted materials.  However, they may be copied and shared
  34.             provided the following terms are adhered to:
  35.  
  36.             1. No fee greater than $10 is charged for use, copying or dis-
  37.                tribution.
  38.  
  39.             2. SNOBOL4.EXE and all documentation are not modified in any
  40.                way, and are distributed together.
  41.  
  42.             3. The manual may not be packaged with any other product.
  43.  
  44.             4. Neither SNOBOL4+ (our commercial product), nor its printed
  45.                manual, may be copied.
  46.  
  47.             Vanilla SNOBOL4 was released because we believe many people
  48.             would enjoy programming in SNOBOL4, if there was a version of
  49.             the language that was widely and freely available.  Contribu-
  50.             tions are NOT requested.  Enjoy and share it!
  51.  
  52.  
  53.  
  54.  
  55.  
  56.                                                           TABLE OF CONTENTS
  57.           -----------------------------------------------------------------
  58.  
  59.  
  60.  
  61.                               PART I -- GETTING STARTED
  62.  
  63.           Chapter 1      Getting Started                                  1
  64.             1.1            About This Manual.........................1
  65.             1.2            Installing Vanilla SNOBOL4................1
  66.             1.3            An Example................................2
  67.  
  68.           Chapter 2      First Program                                    4
  69.             2.1            A First Program...........................4
  70.             2.2            Interactive Statement Execution...........6
  71.  
  72.  
  73.                                  PART II -- TUTORIAL
  74.  
  75.           Chapter 3      Fundamentals                                     8
  76.             3.1            Simple Data Types.........................8
  77.             3.2            Simple Operators.........................10
  78.             3.3            Variables................................14
  79.  
  80.           Chapter 4      Control Flow and Functions                      17
  81.             4.1            Success and Failure......................17
  82.             4.2            A SNOBOL4 Statement......................18
  83.             4.3            Built-In Functions.......................19
  84.  
  85.           Chapter 5      Input/Output and Keywords                       23
  86.             5.1            Input/Output.............................23
  87.             5.2            Keywords.................................26
  88.             5.3            Programs Without Pattern Matching........28
  89.  
  90.           Chapter 6      Pattern Matching                                30
  91.             6.1            Introduction.............................30
  92.             6.2            Specifying Pattern Matching..............31
  93.             6.3            Subject String...........................31
  94.             6.4            Pattern Subsequents and Alternates.......32
  95.             6.5            Simple Pattern Matches...................33
  96.             6.6            The Pattern Data Type....................34
  97.             6.7            Capturing Match Results..................34
  98.             6.8            Unknowns.................................35
  99.             6.9            Pattern Matching with Replacement........42
  100.             6.10           Sample Programs..........................44
  101.             6.11           Anchored and Unanchored Matching.........48
  102.  
  103.           Chapter 7      Additional Operators and Data Types             49
  104.             7.1            Indirect Reference.......................49
  105.             7.2            Unevaluated Expressions..................52
  106.             7.3            Immediate Assignment.....................53
  107.             7.4            Arrays...................................55
  108.             7.5            Tables...................................57
  109.             7.6            The Name Operator........................61
  110.  
  111.  
  112.  
  113.                                        - i -                                 
  114.  
  115.  
  116.  
  117.  
  118.  
  119.           Chapter 8      Program-Defined Objects                         63
  120.             8.1            Program-Defined Functions................63
  121.             8.2            Program-Defined Data Types...............71
  122.             8.3            Program-Defined Operators................74
  123.  
  124.           Chapter 9      Advanced Topics                                 77
  125.             9.1            The ARBNO Function.......................77
  126.             9.2            Recursive Patterns.......................78
  127.             9.3            Quickscan and Fullscan...................78
  128.             9.4            Other Primitive Patterns.................80
  129.             9.5            Other Functions..........................82
  130.             9.6            Other Unary Operators....................83
  131.             9.7            Run-time Compilation.....................83
  132.  
  133.           Chapter 10     Debugging and Program Efficiency                86
  134.             10.1           Debugging and Tracing....................86
  135.             10.2           Execution Tracing........................90
  136.             10.3           Program Efficiency.......................93
  137.  
  138.           Chapter 11     Concluding Remarks                              95
  139.  
  140.  
  141.                             PART III -- REFERENCE MANUAL
  142.  
  143.           Chapter 12     Introduction                                    96
  144.             12.1           Language Background......................96
  145.  
  146.           Chapter 13     Running a SNOBOL4 Program                       98
  147.             13.1           Basic Command Line Format................98
  148.             13.2           Providing Your Own Parameters............99
  149.             13.3           Command Line Examples...................100
  150.  
  151.           Chapter 14     Statements                                     101
  152.             14.1           Comment Statements......................101
  153.             14.2           Control Statements......................101
  154.             14.3           Program Statements......................102
  155.             14.4           Continuation Statements.................105
  156.             14.5           Multiple Statements.....................105
  157.             14.6           The END Statement.......................106
  158.  
  159.           Chapter 15     Operators                                      107
  160.             15.1           Unary Operators.........................107
  161.             15.2           Binary Operators........................108
  162.  
  163.           Chapter 16     Keywords                                       109
  164.             16.1           Protected Keywords......................109
  165.             16.2           Unprotected Keywords....................110
  166.             16.3           Special Names...........................112
  167.  
  168.           Chapter 17     Data Types and Conversion                      113
  169.             17.1           Data Type Names.........................113
  170.             17.2           Data Type Conversion....................116
  171.  
  172.  
  173.  
  174.  
  175.  
  176.                                        - ii -                                
  177.  
  178.  
  179.  
  180.  
  181.  
  182.           Chapter 18     Patterns and Pattern Functions                 121
  183.             18.1           Primitive Patterns......................121
  184.             18.2           Primitive Pattern Functions.............122
  185.  
  186.           Chapter 19     Built-In Functions                             124
  187.  
  188.           Chapter 20     System Messages                                138
  189.             20.1           Initial Messages........................138
  190.             20.2           Termination Messages....................138
  191.             20.3           Compilation Messages....................139
  192.             20.4           Execution Error Messages................141
  193.             20.5           Execution Trace Messages................144
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.                                       - iii -                                
  240.  
  241.  
  242.  
  243.  
  244.  
  245.                                                                   Chapter 1
  246.  
  247.  
  248.                                                                INSTALLATION
  249.           -----------------------------------------------------------------
  250.  
  251.             Welcome to the world of SNOBOL4!  It's a world where you can
  252.           manipulate text and search for patterns in a simple and natural
  253.           manner.  SNOBOL4 is a completely general programming language,
  254.           and its magic extends far beyond the world of text processing.
  255.           Concise, powerful programs are easy to write.  In addition,
  256.           SNOBOL4's pattern programming provides a new way to work with
  257.           computers.  If you would like to add SNOBOL4 to your repertoire
  258.           of problem-solving tools, and learn why so many people are
  259.           excited about it, read on.
  260.  
  261.  
  262.                                 1.1 ABOUT THIS MANUAL
  263.  
  264.             This manual is divided into three parts.  This part, "Getting
  265.           Started," shows you how to create and run small programs with
  266.           SNOBOL4.
  267.  
  268.             Part II, "Tutorial," is addressed to the beginning SNOBOL4 pro-
  269.           grammer.  It assumes a modest knowledge of general programming
  270.           concepts, and experience with another high-level language, such
  271.           as BASIC, C, FORTRAN, or Pascal.  Readers without any programming
  272.           background may wish to consult books written with them in mind:
  273.           "A SNOBOL4 Primer" and "SNOBOL Programming for the Humanities,"
  274.           listed in the file SNOBOL4.DOC.
  275.  
  276.             Part III, "Reference," is a complete description of Vanilla
  277.           SNOBOL4.  If you are already familiar with the SNOBOL4 language,
  278.           you may wish to skip the tutorial section and proceed directly to
  279.           the reference section for specific details.  Later, you can
  280.           return to the tutorial section for fresh insight into the lan-
  281.           guage's use.
  282.  
  283.  
  284.                            1.2 INSTALLING VANILLA SNOBOL4
  285.  
  286.  
  287.           1.2.1 System Requirements
  288.  
  289.             SNOBOL4 requires the following:
  290.  
  291.             1. IBM PC, XT, AT, or any other 8086/88/186/286/386 family com-
  292.                puter.  Your computer need not be an IBM PC look-alike;
  293.                SNOBOL4 requires MS-DOS compatibility only.
  294.  
  295.             2. PC- or MS-DOS, Version 2.0 or above.
  296.  
  297.             3. 105K bytes of free RAM memory.
  298.  
  299.  
  300.  
  301.  
  302.        Getting Started                 - 1 -                     Installation
  303.  
  304.  
  305.  
  306.  
  307.  
  308.           1.2.2 Making a Backup Copy
  309.  
  310.             The Vanilla SNOBOL4 distribution disk should never be used for
  311.           production work.  Always make a backup copy, and use it for your
  312.           day-to-day activities:
  313.  
  314.             1. Use the DOS FORMAT command to initialize a new, blank
  315.                diskette.
  316.  
  317.             2. If your system has two 5-1/4 inch diskette drives, place the
  318.                SNOBOL4 diskette in drive A, and the new disk in drive B,
  319.                and type:
  320.  
  321.                DISKCOPY A: B:
  322.  
  323.             3. If you have only one diskette drive, enter:
  324.  
  325.                DISKCOPY A: A:
  326.  
  327.                and follow the instructions for swapping diskettes.  The
  328.                Vanilla SNOBOL4 diskette is the Source diskette, while the
  329.                newly formatted diskette is the Target.
  330.  
  331.             If you have a fixed disk, you may create a subdirectory for
  332.           SNOBOL4, and copy all of the SNOBOL4 disk to it.
  333.  
  334.  
  335.           1.2.3 Initial Checkout
  336.  
  337.             Place your backup disk in the default drive, and play a game of
  338.           Tick-Tack-Toe.  Our examples will assume a two-drive system,
  339.           using drive B as the default drive.  If you have a one-drive sys-
  340.           tem, or are running SNOBOL4 from the fixed disk, your screen will
  341.           display a different default drive letter (A or C).  Enter:
  342.  
  343.                B>SNOBOL4 TICTAC
  344.  
  345.             The SNOBOL4 program should load, and compile the Tick-Tack-Toe
  346.           program.  The game will begin execution, and display instruc-
  347.           tions.
  348.  
  349.  
  350.                                    1.3 AN EXAMPLE
  351.  
  352.             Just to get a feel for where we're going, let's take a look at
  353.           a small SNOBOL4 program.  It produces a sorted list of the words
  354.           in a file, along with a count of how many times each word ap-
  355.           pears.  Don't be concerned if you don't understand the program; I
  356.           just want to give you a taste of the language:
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.        Getting Started                 - 2 -                     Installation
  366.  
  367.  
  368.  
  369.  
  370.  
  371.                * Trim input, set up constants, and create table to
  372.                *  hold word counts
  373.                        &TRIM   =  1
  374.                        WRDPAT  =  BREAK(&LCASE) SPAN(&LCASE "-'") . WORD
  375.                        TALLY   =  TABLE()
  376.                
  377.                * Read a line, convert upper case letters to lower case
  378.                READ    LINE     =  REPLACE(INPUT,&UCASE,&LCASE) :F(CONVERT)
  379.                
  380.                * Get and remove next word from LINE, place in variable WORD
  381.                NEXTWRD LINE  WRDPAT =                            :F(READ)
  382.                
  383.                * Increment the count for this word
  384.                        TALLY[WORD] =  TALLY[WORD] + 1            :(NEXTWRD)
  385.                
  386.                * Convert the table to an array
  387.                CONVERT RESULT  =  CONVERT(TALLY, "ARRAY")        :F(NONE)
  388.                
  389.                * Display the results
  390.                        OUTPUT  =  "Word Counts"
  391.                        I       =  1
  392.                PRINT   OUTPUT  =  RESULT[I,1] " - " RESULT[I,2]  :F(END)
  393.                        I       =  I + 1                          :(PRINT)
  394.                NONE    OUTPUT  =  "There aren't any words!"
  395.                END
  396.  
  397.             Running the program with the sample text on the disk as input
  398.           would produce a usage count like this:
  399.  
  400.                Word Counts
  401.                hark - 2
  402.                the - 1
  403.                lark - 1
  404.                at - 2
  405.                heaven's - 1
  406.                 . . .
  407.  
  408.             Notice some of the things that seem to occur so effortlessly
  409.           here:  A word is defined to be any combination of lower case let-
  410.           ters, hyphen, and apostrophe.  Data from the file are converted
  411.           to lower case.  A table of word counts uses the words themselves
  412.           as subscripts.  The table is converted to an array in one state-
  413.           ment, and printed without any knowledge of the array's size.
  414.           Finally, because the definition of a word is contained in one
  415.           succinct pattern, it's easy to modify the program to catalog
  416.           other kinds of text patterns.
  417.  
  418.             Excluding comments and the END statement, there are 12 working
  419.           statements in this program---and this program uses only a frac-
  420.           tion of SNOBOL4's power.  How much work would it be to write such
  421.           a program in any other language you are familiar with?  Is it
  422.           possible that there is something unique about SNOBOL4?
  423.  
  424.             Let's go on now to write a simple first program.
  425.  
  426.  
  427.  
  428.        Getting Started                 - 3 -                     Installation
  429.  
  430.  
  431.  
  432.  
  433.  
  434.                                                                   Chapter 2
  435.  
  436.  
  437.                                                               FIRST PROGRAM
  438.           -----------------------------------------------------------------
  439.  
  440.  
  441.                                  2.1 A FIRST PROGRAM
  442.  
  443.             For the following exercises, you should have SNOBOL4 available
  444.           on your default disk drive, or in your default directory if a
  445.           fixed disk is used.  This manual assumes that drive B is your
  446.           default disk drive, and will show the DOS prompt as "B>".  Users
  447.           with other hardware configurations may see "A>" or "C>".
  448.  
  449.             We will begin with a very simple program, one that prints a
  450.           greeting on your computer's display screen.  It will familiarize
  451.           you with the mechanics of running a SNOBOL4 program.  Every line
  452.           you enter from the keyboard (or "console") should end by pressing
  453.           the ENTER key (marked ─┘).
  454.  
  455.             You start the system by typing SNOBOL4 CON at the DOS command
  456.           prompt B>.  SNOBOL4 displays two title lines and prompts you to
  457.           enter your program with a question mark on each line:
  458.  
  459.                B>SNOBOL4 CON
  460.                
  461.                Vanilla SNOBOL4      Version 2.14.
  462.                (c) Copyright 1984,1988 Catspaw, Inc. All Rights Reserved.
  463.                Enter program, terminate with "END"
  464.                ?
  465.  
  466.             Now enter the program.  Use the tab character to begin the
  467.           indented line, and be sure to place blanks on each side of the
  468.           equal sign:
  469.  
  470.                ?       OUTPUT = 'Hello world!'
  471.                ?END
  472.                
  473.                No errors
  474.                
  475.                Hello world!
  476.                
  477.                B>
  478.  
  479.             As you enter each line, it is compiled into a compact internal
  480.           notation.  The first program line begins with a tab; the second
  481.           is flush left.  The word END is special; it signals SNOBOL4 that
  482.           you have finished entering program lines.  It must appear at the
  483.           left margin to be recognized.  After the END statement is
  484.           entered, SNOBOL4 begins to run your program.
  485.  
  486.             This program consists of one "assignment statement."
  487.           Assignment takes the value on the right side of the equals sign,
  488.  
  489.  
  490.  
  491.        Getting Started                 - 4 -                    First Program
  492.  
  493.  
  494.  
  495.  
  496.  
  497.           and stores it in the "variable" on the left.  The value on the
  498.           right is the character string literal 'Hello world!'.  The
  499.           variable's name is OUTPUT, which is a special name in SNOBOL4;
  500.           values assigned to it are displayed on the screen.  After the
  501.           assignment statement is performed, control flows into the END
  502.           statement and the program stops.
  503.  
  504.             SNOBOL4 only provides DOS in-line editing as you enter your
  505.           program.  It is not a program editor, and does not save your pro-
  506.           gram or let you correct mistakes in previous program lines.  Usu-
  507.           ally, you'll want to prepare your program in a disk file.
  508.  
  509.             Try creating a program file in DOS.  The symbol ^Z represents
  510.           the DOS End-of-File character, which terminates the DOS COPY com-
  511.           mand.  It is created by entering control-Z or pressing function
  512.           key 6.
  513.  
  514.                B>COPY CON HELLO.SNO
  515.                        OUTPUT = 'Hello world!'
  516.                END
  517.                ^Z
  518.                        1 File(s) copied
  519.                B>
  520.  
  521.             Now you can have SNOBOL4 read and execute your program from
  522.           file HELLO.SNO:
  523.  
  524.                B>SNOBOL4 HELLO.SNO
  525.                
  526.                Vanilla SNOBOL4      Version 2.14.
  527.                (c) Copyright 1984,1988 Catspaw, Inc. All Rights Reserved.
  528.                
  529.                No errors
  530.                
  531.                Hello world!
  532.                
  533.                B>
  534.  
  535.             Of course, the program file could also have been created with
  536.           your program text editor.  If you are using a word processor,
  537.           remember to produce an unadulterated ASCII file, free of any spe-
  538.           cial format controls.
  539.  
  540.             SNOBOL4 assigns a unique number to each program statement.  The
  541.           statement number and line number are displayed whenever an error
  542.           message is produced.  To get a listing of your program with
  543.           SNOBOL4's statement numbers, try:
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.        Getting Started                 - 5 -                    First Program
  555.  
  556.  
  557.  
  558.  
  559.  
  560.                B>SNOBOL4 HELLO /L=CON
  561.                
  562.                Vanilla SNOBOL4      Version 2.14.
  563.                (c) Copyright 1984,1988 Catspaw, Inc. All Rights Reserved.
  564.                1               OUTPUT = 'Hello world!'
  565.                2       END
  566.                
  567.                No errors
  568.                
  569.                Hello world!
  570.                
  571.                B>
  572.  
  573.             The first line, on which you typed SNOBOL4, is called the com-
  574.           mand line.  It may contain options that alter SNOBOL4's behavior.
  575.           The option /L= tells SNOBOL4 to send a listing of your source
  576.           file to the specified file or device.  Another device, such as
  577.           PRN:, would print a listing on your printer.  Other command line
  578.           options are discussed in Chapter 13, "Running a SNOBOL4 Program."
  579.  
  580.             In this example we omitted the file name extension.  SNOBOL4
  581.           will supply the .SNO extension for the source file if it is
  582.           absent.
  583.  
  584.             You've now run a simple SNOBOL4 program in two ways: by typing
  585.           it in directly, and by creating a disk file.
  586.  
  587.  
  588.                          2.2 INTERACTIVE STATEMENT EXECUTION
  589.  
  590.             It's very helpful to "try out" simple statements as they are
  591.           introduced in the text.  There is a SNOBOL4 program called
  592.           CODE.SNO on the distribution diskette to help you do this.  Try
  593.           it now with a few simple statements.  Type END or control-Z to
  594.           stop the program.
  595.  
  596.                B>SNOBOL4 CODE
  597.                
  598.                Vanilla SNOBOL4      Version 2.14.
  599.                (c) Copyright 1984,1988 Catspaw, Inc. All Rights Reserved.
  600.                
  601.                No errors
  602.                
  603.                Enter SNOBOL4 statements:
  604.                ?       OUTPUT = 'HELLO AGAIN!'
  605.                HELLO AGAIN!
  606.                Success
  607.                ?       OUTPUT = 16
  608.                16
  609.                Success
  610.                ?END
  611.                
  612.                B>
  613.  
  614.  
  615.  
  616.  
  617.        Getting Started                 - 6 -                    First Program
  618.  
  619.  
  620.  
  621.  
  622.  
  623.             Feel free to experiment---you can't break anything by using
  624.           this program.  At most, you will get a SNOBOL4 error, and return
  625.           to the DOS command prompt.  In that case, just start SNOBOL4 and
  626.           CODE.SNO over again.
  627.  
  628.             Whenever you see examples in the text that begin with a ques-
  629.           tion mark, they are meant to be tried with CODE.SNO.  In the text
  630.           I'll omit the word Success most of the time unless it is relevant
  631.           to the concept being presented, although it will still appear on
  632.           your display.  I'll also try to restrict the examples to upper
  633.           case, so you can set the CAPS LOCK mode on your computer, and
  634.           type without using the shift key.
  635.  
  636.             Let's now proceed to the tutorial.
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664.  
  665.  
  666.  
  667.  
  668.  
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675.  
  676.  
  677.  
  678.  
  679.  
  680.        Getting Started                 - 7 -                    First Program
  681.  
  682.  
  683.  
  684.  
  685.  
  686.                                                                   Chapter 3
  687.  
  688.  
  689.                                                                FUNDAMENTALS
  690.           -----------------------------------------------------------------
  691.  
  692.             SNOBOL4 is really a combination of two kinds of languages:  a
  693.           conventional language, with several data types and a simple but
  694.           powerful control structure, and a pattern language, with a struc-
  695.           ture all its own.  The conventional language is not block struc-
  696.           tured, and may appear old-fashioned.  The pattern language,
  697.           however, remains unsurpassed, and is unique to SNOBOL4.
  698.  
  699.             You should try to master the conventional portion of SNOBOL4
  700.           first.  When you're comfortable with it, you can move on to pat-
  701.           tern matching.  Pattern matching by itself is a very large sub-
  702.           ject, and this manual can only offer an introduction.  The sample
  703.           programs accompanying Vanilla SNOBOL4, as well as the many
  704.           SNOBOL4 books available from Catspaw can be studied for a deeper
  705.           understanding of patterns and their application.
  706.  
  707.             We'll begin by discussing data types, operators, and variables.
  708.  
  709.  
  710.                                 3.1 SIMPLE DATA TYPES
  711.  
  712.             SNOBOL4 has several different basic types, but has a mechanism
  713.           to define hundreds more as aggregates of others.  Initially,
  714.           we'll discuss the two most basic:  integers and strings.
  715.  
  716.  
  717.           3.1.1 Integers
  718.  
  719.             An integer is a simple whole number, without a fractional part.
  720.           In SNOBOL4, its value can range from -32767 to +32767.  It ap-
  721.           pears without quotation marks, and commas should not be used to
  722.           group digits.  Here are some acceptable integers:
  723.  
  724.                14    -234    0    0012    +12832    -9395    +0
  725.  
  726.             These are incorrect in SNOBOL4:
  727.  
  728.              13.4             fractional part is not allowed
  729.  
  730.              49723            larger than 32767
  731.  
  732.              -                number must contain at least one digit
  733.  
  734.              3,076            comma is not allowed
  735.  
  736.             Use the CODE.SNO program to test different integer values.  Try
  737.           both legal and illegal values.  Here are some sample test lines:
  738.  
  739.  
  740.  
  741.  
  742.  
  743.        Tutorial                        - 8 -                     Fundamentals
  744.  
  745.  
  746.  
  747.  
  748.  
  749.                Enter SNOBOL4 statements:
  750.                ?       OUTPUT = 42
  751.                42
  752.                ?       OUTPUT = -825
  753.                -825
  754.                ?       OUTPUT = 73768
  755.                Compilation error: Erroneous integer, re-enter:
  756.  
  757.  
  758.           3.1.2 Reals
  759.  
  760.             Vanilla SNOBOL4 does not include real numbers.  They are
  761.           available in SNOBOL4+, Catspaw's highly enhanced implementation
  762.           of the SNOBOL4 programming language.
  763.  
  764.  
  765.           3.1.3 Strings
  766.  
  767.             A string is an ordered sequence of characters.  The order of
  768.           the characters is important: the strings AB and BA are different.
  769.           Characters are not restricted to printing characters; all of the
  770.           256 combinations possible in an 8-bit byte are allowed.
  771.  
  772.             Normally, the maximum length of a string is 5,000 characters,
  773.           although you can tell SNOBOL4 to accept longer strings.  A string
  774.           of length zero (no characters) is called the null string.  At
  775.           first, you may find the idea of an empty string disturbing:  it's
  776.           a string, but it has no characters.  Its role in SNOBOL4 is simi-
  777.           lar to the role of zero in the natural number system.
  778.  
  779.             Strings may appear literally in your program, or may be created
  780.           during execution.  To place a literal string in your program, en-
  781.           close it in apostrophes (')1 or double quotation marks (").
  782.           Either may be used, but the beginning and ending marks must be
  783.           the same. The string itself may contain one type of mark if the
  784.           other is used to enclose the string.  The null string is repre-
  785.           sented by two successive marks, with no intervening characters.
  786.           Here are some samples to try with CODE.SNO:
  787.  
  788.  
  789.  
  790.  
  791.  
  792.  
  793.  
  794.  
  795.  
  796.  
  797.           ____________________
  798.  
  799.             1 Apostrophe (single quote) should not be confused with the
  800.           grave accent mark (`) which appears next to it on some computer
  801.           keyboards.  The grave accent may not be used as a string
  802.           delimiter.
  803.  
  804.  
  805.  
  806.        Tutorial                        - 9 -                     Fundamentals
  807.  
  808.  
  809.  
  810.  
  811.  
  812.                ?       OUTPUT = 'STRING LITERAL'
  813.                STRING LITERAL
  814.                ?       OUTPUT = "So is this"
  815.                So is this
  816.                ?       OUTPUT = ''
  817.                
  818.                ?       OUTPUT = 'WHO COINED THE WORD "BYTE"?'
  819.                WHO COINED THE WORD "BYTE"?
  820.                ?       OUTPUT = "WON'T"
  821.                WON'T
  822.  
  823.  
  824.                                 3.2 SIMPLE OPERATORS
  825.  
  826.             If data is the raw material, operators are the tools that do
  827.           the work.  Some operators, such as + and -, appear in all pro-
  828.           gramming languages, and pocket calculators.  But SNOBOL4 provides
  829.           many more, some of which are unique to the SNOBOL4 language.
  830.           SNOBOL4 also allows you to define your own operators.  We'll
  831.           examine just a few basic operators below.
  832.  
  833.  
  834.           3.2.1 Unary vs. Binary
  835.  
  836.             SNOBOL4 operators require either one or two items of data,
  837.           called operands.  For example, the minus sign (-) can be used
  838.           with one object.  In this form, the operator is considered unary:
  839.  
  840.                -6
  841.  
  842.           or as a binary operator with two operands:
  843.  
  844.                4 - 1
  845.  
  846.             In the first case, the minus sign negates the number.  The sec-
  847.           ond example subtracts 1 from 4.  The minus sign's meaning depends
  848.           on the context in which it appears.  SNOBOL4 has a very simple
  849.           rule for determining if an operator is binary or unary:
  850.  
  851.                Unary operators are placed immediately to the left of
  852.                their operand.  No blank or tab character may appear
  853.                between operator and operand.
  854.  
  855.                Binary operators have one or more blank or tab charac-
  856.                ters on each side.
  857.  
  858.             The blank or tab requirement for binary operators causes prob-
  859.           lems for programmers first learning SNOBOL4.  Most other lan-
  860.           guages make these white space characters optional.  Omitting the
  861.           right hand blank after a binary operator will produce a unary
  862.           operator, and while the statement may be syntactically correct,
  863.           it will probably produce unexpected results.  Fortunately, blanks
  864.           and binary operators quickly become a way of SNOBOL4 life, and
  865.           after some initial forgetfulness there are few problems.
  866.  
  867.  
  868.  
  869.        Tutorial                        - 10 -                    Fundamentals
  870.  
  871.  
  872.  
  873.  
  874.  
  875.           3.2.2 Some Binary Operators
  876.  
  877.  
  878.           Operation:     Assignment
  879.           Symbol:        = (equals sign)
  880.  
  881.             You've already met one binary operator, the equals sign (=).
  882.           It appeared in the first sample program:
  883.  
  884.                        OUTPUT = 'Hello world!'
  885.  
  886.             It assigns, or transfers, the value of the object on the right
  887.           ('Hello world!') to the object on the left (variable OUTPUT).
  888.  
  889.  
  890.           Operation:     Arithmetic
  891.           Symbols:       **, *, /, +, -
  892.  
  893.             These characters provide the arithmetic operations---exponenti-
  894.           ation, multiplication, division, addition, and subtraction
  895.           respectively.  Each is assigned a priority, so SNOBOL4 knows
  896.           which to perform first if more than one appear in an expression.
  897.           Exponentiation is performed first, followed by multiplication,
  898.           division, and finally addition and subtraction.  SNOBOL4 is
  899.           unusual in giving multiplication higher priority than division;
  900.           most programming languages treat them equally.
  901.  
  902.             You may use parentheses to change the order of operations.
  903.           Division of an integer by another integer will produce a trun-
  904.           cated integer result; the fractional result is discarded.  Try
  905.           the following:
  906.  
  907.                ?       OUTPUT = 3 - 6 + 2
  908.                -1
  909.                ?       OUTPUT = 2 * (10 + 4)
  910.                28
  911.                ?       OUTPUT = 7 / 4
  912.                1
  913.                ?       OUTPUT = 3 ** 5
  914.                243
  915.                ?       OUTPUT = 10 / 2 * 5
  916.                1
  917.                ?       OUTPUT = (10 / 2) * 5
  918.                25
  919.  
  920.             When the same operator occurs more than once in an expression,
  921.           which one should be performed first?  The governing principle is
  922.           called associativity, and is either left or right.  Multiple
  923.           instances of *, /, + and - are performed left to right, while
  924.           **'s are performed right to left.  Again, parentheses may be used
  925.           to change the default order.  Try a few examples:
  926.  
  927.  
  928.  
  929.  
  930.  
  931.  
  932.        Tutorial                        - 11 -                    Fundamentals
  933.  
  934.  
  935.  
  936.  
  937.  
  938.                ?       OUTPUT = 24 / 4 / 2
  939.                3
  940.                ?       OUTPUT = 24 / (4 / 2)
  941.                12
  942.                ?       OUTPUT = 2 ** 2 ** 3
  943.                256
  944.                ?       OUTPUT = (2 ** 2) ** 3
  945.                64
  946.  
  947.             Here's the first bit of SNOBOL4 magic: what happens if either
  948.           operand is a string rather than an integer or real number?  The
  949.           action taken is one which is widespread throughout the SNOBOL4
  950.           language; the system tries to convert the operand to a suitable
  951.           data type.  Given the statement
  952.  
  953.                ?       OUTPUT = 14 + '54'
  954.                68
  955.  
  956.           SNOBOL4 detects the addition of an integer and a string, and
  957.           tries to convert the string to a numeric value.  Here the conver-
  958.           sion succeeds, and the integers 14 and 54 are added together.  If
  959.           the characters in the string do not form an acceptable integer,
  960.           SNOBOL4 produces the error message "Illegal data type."
  961.  
  962.             SNOBOL4 is strict about the composition of strings being con-
  963.           verted to numeric values: leading or trailing blanks or tabs are
  964.           not allowed.  The null string is permitted, and converted to
  965.           integer 0.  Try producing some arithmetic errors:
  966.  
  967.                ?       OUTPUT = 14 + ' 54'
  968.                Execution error #1, Illegal data type
  969.                Failure
  970.                ?       OUTPUT = 'A' + 1
  971.                Execution error #1, Illegal data type
  972.                Failure
  973.  
  974.           Note:  Error numbers are listed in Chapter 20, "System Messages."
  975.  
  976.  
  977.           Operation:     Concatenation
  978.           Symbols:       blank or tab
  979.  
  980.             This is the fundamental operator for assembling strings.  Two
  981.           strings are concatenated simply by writing one after the other,
  982.           with one or more blank or tab characters between them.  There is
  983.           no explicit symbol for concatenation (it is special in this
  984.           regard), the white space between two objects serves to define
  985.           this operator.  The blank or tab character merely specifies the
  986.           operation; it is not included in the resulting string.
  987.  
  988.             The string that results from concatenation is the right string
  989.           appended to the end of the left.  The two strings remain
  990.           unchanged and a third string emerges as the result.  Try a few
  991.           simple concatenations with CODE.SNO:
  992.  
  993.  
  994.  
  995.        Tutorial                        - 12 -                    Fundamentals
  996.  
  997.  
  998.  
  999.  
  1000.  
  1001.                ?       OUTPUT = 'CONCAT' 'ENATION'
  1002.                CONCATENATION
  1003.                ?       OUTPUT = 'ONE,' 'TWO,' 'THREE'
  1004.                ONE,TWO,THREE
  1005.                ?       OUTPUT = 'A'                 'B'       'C'
  1006.                ABC
  1007.                ?       OUTPUT = 'BEGINNING '   'AND '   'END.'
  1008.                BEGINNING AND END.
  1009.  
  1010.             The string resulting from concatenation can not be longer than
  1011.           the maximum allowable string size.
  1012.  
  1013.             The concatenation operator works only on character strings, but
  1014.           if an operand is not a string, SNOBOL4 will convert it to its
  1015.           string form.  For example,
  1016.  
  1017.                ?       OUTPUT = (20 - 17)  ' DOG NIGHT'
  1018.                3 DOG NIGHT
  1019.                ?       OUTPUT = 19  (12 / 3)
  1020.                194
  1021.  
  1022.             In the first case, concatenation's right operand is the string
  1023.           ' DOG NIGHT', but the left operand is an integer expression
  1024.           (20 - 17).  SNOBOL4 performs the subtraction, converts the result
  1025.           to the string '3', and produces the final result '3 DOG NIGHT'.
  1026.           In the second example, the integer operands are converted to the
  1027.           strings '19' and '4', to produce the result string '194'.  This
  1028.           is not exactly good math, but it is correct concatenation.
  1029.  
  1030.             You must be careful however.  If you accidentally omit an
  1031.           operator, SNOBOL4 will think you intended to perform concatena-
  1032.           tion.  In the example above, perhaps we omitted a minus sign and
  1033.           had really meant to say:
  1034.  
  1035.                ?       OUTPUT = 19 - (12 / 3)
  1036.                15
  1037.  
  1038.             It is always possible for concatenation to automatically con-
  1039.           vert a number to a string.  But there is one important exception
  1040.           when SNOBOL4 doesn't try to do this: if either operand is the
  1041.           null string, the other operand is returned unchanged.  It is not
  1042.           coerced into the string data type.  If the first example were
  1043.           changed to:
  1044.  
  1045.                ?       OUTPUT = (20 - 17)  ''
  1046.                3
  1047.  
  1048.           the result is the INTEGER 3.  You'll find you'll use this aspect
  1049.           of null string concatenations extensively in your SNOBOL4 pro-
  1050.           gramming.
  1051.  
  1052.             Before we proceed, let's think about the null string one more
  1053.           time as the string equivalent of the number zero.  First of all,
  1054.           adding zero to a number does not change its value, and concatena-
  1055.  
  1056.  
  1057.  
  1058.        Tutorial                        - 13 -                    Fundamentals
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064.           ting the null string with an object doesn't change it, either.
  1065.           Second, just as a calculator is cleared to zero before adding a
  1066.           series of numbers, the null string can serve as the starting
  1067.           place for concatenating a series of strings.
  1068.  
  1069.  
  1070.           3.2.3 Some Unary Operators
  1071.  
  1072.             There aren't many interesting unary operators at this point in
  1073.           your tour of SNOBOL4.  Most of them appear in connection with
  1074.           pattern matching, discussed later.  Note, however, that all unary
  1075.           operations are performed before binary operations, unless prece-
  1076.           dence is altered by parentheses.
  1077.  
  1078.  
  1079.           Operation:     Arithmetic
  1080.           Symbols:       +, -
  1081.  
  1082.             These unary operators require a single numeric operand, which
  1083.           must immediately follow the operator, without an intervening
  1084.           blank or tab.  Unary minus (-) changes the arithmetic sign of its
  1085.           operand; unary plus (+) leaves the sign unchanged.  If the
  1086.           operand is a string, SNOBOL4 will try to convert it to a number.
  1087.           The null string is converted to integer 0.  Coercing a string to
  1088.           a number with unary plus is a noteworthy technique.  Try unary
  1089.           plus and minus with CODE.SNO:
  1090.  
  1091.                ?       OUTPUT = -(3 * 5)
  1092.                -15
  1093.                ?       OUTPUT = +''
  1094.                0
  1095.  
  1096.  
  1097.                                     3.3 VARIABLES
  1098.  
  1099.             A variable is a place to store an item of data.  The number of
  1100.           variables you may have is unlimited, provided you give each one a
  1101.           unique name.  Think of a variable as a box, marked on the outside
  1102.           with a permanent name, able to hold any data value or type.  Many
  1103.           programming languages require that you formally declare what kind
  1104.           of entity the box will contain---integer, real, string, etc.---
  1105.           but SNOBOL4 is more flexible.  A variable's contents may change
  1106.           repeatedly during program execution.  The size of the box con-
  1107.           tracts or expands as necessary.  One moment it might contain an
  1108.           integer, then a 2,000 character string, then the null string; in
  1109.           fact, any SNOBOL4 data type.
  1110.  
  1111.             There are only a few rules about composing a variable's name
  1112.           when it appears in your program:
  1113.  
  1114.             1. The name must begin with an upper- or lower-case letter.
  1115.  
  1116.             2. If it is more than one character long, the remaining charac-
  1117.                ters may be any combination of letters, numbers, or the
  1118.  
  1119.  
  1120.  
  1121.        Tutorial                        - 14 -                    Fundamentals
  1122.  
  1123.  
  1124.  
  1125.  
  1126.  
  1127.                characters period (.) and underscore (_).
  1128.  
  1129.             3. The name may not be longer than the maximum line length (120
  1130.                characters).
  1131.  
  1132.             Here are some correct SNOBOL4 names:
  1133.  
  1134.                WAGER     P23     VerbClause     SUM.OF.SQUARES     Buffer
  1135.  
  1136.             Normally, SNOBOL4 performs "case-folding" on names.  Lower-case
  1137.           alphabetic characters are changed to upper-case when they appear
  1138.           in names---Buffer and BUFFER are equivalent.  Naturally, case-
  1139.           folding of data does not occur within a string literal.  Case-
  1140.           folding can be disabled by the command line option /C.
  1141.  
  1142.             In some languages, the initial value of a new variable is
  1143.           undefined.  SNOBOL4 guarantees that a new variable's initial
  1144.           value is the null string.  However, except in very small pro-
  1145.           grams, you should always initialize variables.  This prevents
  1146.           unexpected results when a program is modified or a program seg-
  1147.           ment is reexecuted.
  1148.  
  1149.             You store something in a variable by making it the object of an
  1150.           assignment operation.  You can retrieve its contents simply by
  1151.           using it wherever its value is needed.  Using a variable's value
  1152.           is nondestructive; the value in the box remains unchanged.  Try
  1153.           creating some variables using CODE.SNO:
  1154.  
  1155.                ?       ABC = 'EGG'
  1156.                ?       OUTPUT = ABC
  1157.                EGG
  1158.                ?       D = 'SHELL'
  1159.                ?       OUTPUT = abc d             (Same as ABC D)
  1160.                EGGSHELL
  1161.                ?       OUTPUT = NONESUCH          (New variable is null)
  1162.                
  1163.                ?       OUTPUT = ABC NULL D
  1164.                EGGSHELL
  1165.                ?       N1 = 43
  1166.                ?       D = 17
  1167.                ?       OUTPUT = N1 + D
  1168.                60
  1169.                ?       output = ABC D
  1170.                EGG17
  1171.  
  1172.             OUTPUT is a variable with special properties; when a value is
  1173.           stored in its box, it is also displayed on your screen.  There is
  1174.           a corresponding variable named INPUT, which reads data from your
  1175.           keyboard.  Its box has no permanent contents.  Whenever SNOBOL4
  1176.           is asked to fetch its value, a complete line is read from the
  1177.           keyboard and used instead.  If INPUT were used twice in one
  1178.           statement, two separate lines of input would be read.  Try these
  1179.           examples:
  1180.  
  1181.  
  1182.  
  1183.  
  1184.        Tutorial                        - 15 -                    Fundamentals
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190.                ?       OUTPUT = INPUT
  1191.                TYPE ANYTHING YOU DESIRE
  1192.                TYPE ANYTHING YOU DESIRE
  1193.                ?       TWO.LINES = INPUT '-AND-' INPUT
  1194.                FIRST LINE
  1195.                SECOND LINE
  1196.                ?       OUTPUT = TWO.LINES
  1197.                FIRST LINE-AND-SECOND LINE
  1198.  
  1199.             SNOBOL4 variables are global in scope---any variable may be
  1200.           referenced anywhere in the program.
  1201.  
  1202.  
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210.  
  1211.  
  1212.  
  1213.  
  1214.  
  1215.  
  1216.  
  1217.  
  1218.  
  1219.  
  1220.  
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232.  
  1233.  
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246.  
  1247.        Tutorial                        - 16 -                    Fundamentals
  1248.  
  1249.  
  1250.  
  1251.  
  1252.  
  1253.                                                                   Chapter 4
  1254.  
  1255.  
  1256.                                                  CONTROL FLOW AND FUNCTIONS
  1257.           -----------------------------------------------------------------
  1258.  
  1259.  
  1260.                                4.1 SUCCESS AND FAILURE
  1261.  
  1262.             Success and failure are as important in SNOBOL4 as they are in
  1263.           life.  Success and failure are unmistakable signals; something
  1264.           either worked, or it didn't.  Significant program conciseness is
  1265.           achieved by recognizing that data values and signals are funda-
  1266.           mentally different entities.
  1267.  
  1268.             The elements of a statement provide values and signals as com-
  1269.           putation proceeds.  SNOBOL4 accumulates both, and stops executing
  1270.           a particular statement when it finds it cannot succeed.  Program
  1271.           flow can be altered based upon this success or failure.
  1272.  
  1273.             The success signal will have a value result associated with it.
  1274.           In situations in which the signal itself is the desired object,
  1275.           the result value may only be the null string.  The failure signal
  1276.           has no associated value.  (In some instances, it may be helpful
  1277.           to view failure as meaning "failure to produce a result.")
  1278.  
  1279.             Previously, we introduced the variable INPUT, which reads a
  1280.           line from the keyboard.  In general, INPUT can be made to read
  1281.           from any disk file.  The line read may be any character string,
  1282.           including the null string if it is an empty line.  If any string
  1283.           might appear, then there is no special value we can test for to
  1284.           detect End-of-File.  Success and failure provide an elegant
  1285.           alternative to testing for special values.
  1286.  
  1287.             When we retrieve a value from INPUT, we normally get a string
  1288.           and a success signal.  But when End-of-File is encountered, we
  1289.           get a failure signal instead, and no value.
  1290.  
  1291.             Since control-Z (or function key 6) allows you to enter an End-
  1292.           of-File from the keyboard, we can easily demonstrate this type of
  1293.           failure.  As you've noticed, the CODE.SNO program reports the
  1294.           success or failure of each statement.  So far, all examples have
  1295.           succeeded.  Now try this one:
  1296.  
  1297.                ?       OUTPUT = INPUT
  1298.                ^Z
  1299.                Failure
  1300.  
  1301.             Success and failure are control signals, and appear only during
  1302.           the execution of a statement.  They cannot be stored in a vari-
  1303.           able, which holds values only.
  1304.  
  1305.             There is much more which can be done with success and failure,
  1306.           but to understand their use, you'll need to know how SNOBOL4
  1307.  
  1308.  
  1309.  
  1310.        Tutorial                        - 17 -      Control Flow and Functions
  1311.  
  1312.  
  1313.  
  1314.  
  1315.  
  1316.           statements are constructed.
  1317.  
  1318.  
  1319.                                4.2 A SNOBOL4 STATEMENT
  1320.  
  1321.             In general, a SNOBOL4 statement looks like this:
  1322.  
  1323.                Label   Statement body                                 :GOTO
  1324.  
  1325.             The label is optional, and is omitted by placing a blank or tab
  1326.           in the first character position.  The GOTO is also optional, and
  1327.           can be eliminated simply by omitting it and the colon.  In fact,
  1328.           even the statement body is optional.  You can have a program line
  1329.           consisting of just a label or a GOTO field.
  1330.  
  1331.  
  1332.           4.2.1 The Label Field
  1333.  
  1334.             SNOBOL4 normally executes the statements of a program in
  1335.           sequence.  The ability to transfer control from one statement to
  1336.           another, perhaps conditionally, makes SNOBOL4 much more usable.
  1337.  
  1338.             Labels provide names for statements.  If present, they must
  1339.           begin in the first character position of a statement, and must
  1340.           start with a letter or number.  Additional characters may be any-
  1341.           thing but blank or tab.  Like variable names, lower-case letters
  1342.           are equivalent to upper-case when case-folding (the default).
  1343.  
  1344.  
  1345.           4.2.1 The GOTO Field
  1346.  
  1347.             Transfer of control is made possible by the GOTO.  It inter-
  1348.           rupts the normal sequential execution of statements by telling
  1349.           SNOBOL4 which statement to execute after the present one.  The
  1350.           GOTO field appears at the end of the statement, preceded by a
  1351.           colon (:), and has one of these forms:
  1352.  
  1353.                                                 :(label)
  1354.                                                 :S(label)
  1355.                                                 :F(label)
  1356.                                                 :S(label1) F(label2)
  1357.  
  1358.             White space is required before the colon.  "Label" is the name
  1359.           given the target statement, and must be enclosed in parentheses.
  1360.           If the first form is used, execution resumes at the referenced
  1361.           statement, unconditionally.  In the second and third forms,
  1362.           transfer occurs only if the statement has succeeded or failed,
  1363.           respectively.  Otherwise, execution proceeds to the next state-
  1364.           ment in line.  If the fourth form is used, transfer is made to
  1365.           label1 if the statement succeeded, or to label2 if it failed.  A
  1366.           statement with a label and a GOTO would look like this:
  1367.  
  1368.                COPY    OUTPUT = INPUT           :F(DONE)
  1369.  
  1370.  
  1371.  
  1372.  
  1373.        Tutorial                        - 18 -      Control Flow and Functions
  1374.  
  1375.  
  1376.  
  1377.  
  1378.  
  1379.             Now let's write a short program which copies keyboard input to
  1380.           the screen, and reports the total number of lines.  If you are an
  1381.           accurate typist, you can type it into SNOBOL4 directly.  Other-
  1382.           wise, you should use your text editor to create a file containing
  1383.           the program text.  First stop the CODE.SNO program by typing END:
  1384.  
  1385.                ?END
  1386.                
  1387.                B>SNOBOL4 CON
  1388.                
  1389.                Vanilla SNOBOL4      Version 2.14.
  1390.                (c) Copyright 1984,1988 Catspaw, Inc. All Rights Reserved.
  1391.                Enter program, terminate with "END"
  1392.                ?       N = 0
  1393.                ?COPY   OUTPUT = INPUT           :F(DONE)
  1394.                ?       N = N + 1                :(COPY)
  1395.                ?DONE   OUTPUT = 'THERE WERE ' N ' LINES'
  1396.                ?END
  1397.                
  1398.                No errors
  1399.                
  1400.                TYPE IN A TEST LINE
  1401.                TYPE IN A TEST LINE
  1402.                
  1403.                AND ANOTHER
  1404.                AND ANOTHER
  1405.                
  1406.                ^Z
  1407.                THERE WERE 2 LINES
  1408.                
  1409.                B>
  1410.  
  1411.             We start the line count in variable N at 0.  The next statement
  1412.           has a label, COPY, a statement body, and a GOTO field.  It is an
  1413.           assignment statement, and begins execution by reading a line of
  1414.           input.  If INPUT successfully obtains a line, the result is
  1415.           stored in OUTPUT.  The GOTO field is only testing for failure, so
  1416.           SNOBOL4 proceeds to the next statement, where N is incremented,
  1417.           and the unconditional GOTO transfers back to statement COPY.
  1418.  
  1419.             When an End-of-File is read, variable INPUT signals failure.
  1420.           Execution of this statement terminates immediately, without per-
  1421.           forming the assignment, and transfers to the statement labeled
  1422.           DONE.  The number of lines is displayed, and control flows into
  1423.           the END statement, stopping the program.
  1424.  
  1425.  
  1426.                                4.3 BUILT-IN FUNCTIONS
  1427.  
  1428.             A function is analogous to an operator; it operates on data to
  1429.           produce a result.  The data objects are called the arguments of
  1430.           the function.  The result returned---the function of the argu-
  1431.           ments---may have two components: the success or failure signal;
  1432.           and for success, a value.  The value may be any data type.
  1433.  
  1434.  
  1435.  
  1436.        Tutorial                        - 19 -      Control Flow and Functions
  1437.  
  1438.  
  1439.  
  1440.  
  1441.  
  1442.             A function is used by writing its name and a list of arguments
  1443.           enclosed by parentheses:
  1444.  
  1445.                        FUNCTION_NAME(ARG1, ARG2, ..., ARGn)
  1446.  
  1447.             It may appear in your program anywhere a constant is allowed---
  1448.           in expressions, patterns, even as the argument of another func-
  1449.           tion.  If the function has more than one argument, they should be
  1450.           separated by commas.  If trailing arguments are omitted, SNOBOL4
  1451.           will supply the null string instead.  Some functions, such as one
  1452.           that returns the current date, have no arguments at all.
  1453.  
  1454.             SNOBOL4 provides a large number of predefined functions, and
  1455.           allows you to define your own.  The large repertoire of built-in
  1456.           functions makes SNOBOL4 programming easier.  Most functions are
  1457.           concerned with pattern matching, input/output, and advanced fea-
  1458.           tures of the language.  Here we'll introduce a few simple
  1459.           conditional, numeric, and string functions to give you an idea of
  1460.           the variety.  Try them interactively with CODE.SNO.
  1461.  
  1462.  
  1463.           4.3.1 Conditional Functions
  1464.  
  1465.             These functions fail or succeed depending upon their arguments.
  1466.           They are sometimes called predicate functions because the success
  1467.           of an expression using them is predicated upon their success.  If
  1468.           they succeed, they return the null string as their value.
  1469.  
  1470.              Function         Succeeds if:
  1471.  
  1472.              IDENT(S,T)       S and T are identical.  S and T may be con-
  1473.                               stants or variables with any data type.  To
  1474.                               be identical, the arguments must have the
  1475.                               same data type and value.  Since omitted ar-
  1476.                               guments default to the null string, IDENT(S)
  1477.                               succeeds if S is the null string.
  1478.  
  1479.              DIFFER(S,T)      S and T are different.  DIFFER is the oppo-
  1480.                               site of IDENT.  DIFFER(S) succeeds if S is
  1481.                               not the null string.
  1482.  
  1483.              EQ(X,Y)          Integers X and Y are equal.  X and Y must be
  1484.                               integers, or strings which can be converted
  1485.                               to integers.
  1486.  
  1487.              NE(X,Y)          Integers X and Y are not equal.
  1488.  
  1489.              GE(X,Y)          Integer X is greater than or equal to Y.
  1490.  
  1491.              GT(X,Y)          Integer X is greater than Y.
  1492.  
  1493.              LE(X,Y)          Integer X is less than or equal to Y.
  1494.  
  1495.              LT(X,Y)          Integer X is less than Y.
  1496.  
  1497.  
  1498.  
  1499.        Tutorial                        - 20 -      Control Flow and Functions
  1500.  
  1501.  
  1502.  
  1503.  
  1504.  
  1505.              INTEGER(X)       X is an integer, or a string which can be
  1506.                               converted to an integer.
  1507.  
  1508.              LGT(S,T)         String S is lexically greater than string T
  1509.                               using a character-by-character comparison.
  1510.  
  1511.             Leading blanks may be used in front of a argument for readabil-
  1512.           ity.  Here are some exercises for CODE.SNO:
  1513.  
  1514.                ?       N = 3
  1515.                ?       EQ(N, 3)
  1516.                Success
  1517.                ?       IDENT(N, 3)
  1518.                Success
  1519.                ?       EQ(3, "3")
  1520.                Success
  1521.                ?IDENT(3, "3")                   (integer and string)
  1522.                Failure
  1523.                ?       EQ(N, 4)
  1524.                Failure
  1525.                ?       NE(N, 4)
  1526.                Success
  1527.                ?       INTEGER(N)
  1528.                Success
  1529.                ?       INTEGER('47')
  1530.                Success
  1531.                ?       DIFFER('ABC', 'abc')
  1532.                Success
  1533.                ?       IDENT('a' 'b' 'c', 'abc')
  1534.                Success
  1535.                ?       LGT('ABC', 'ABD')
  1536.                Failure
  1537.  
  1538.             When any of these functions succeed, they return a null string.
  1539.           Since other statement elements are not altered when concatenated
  1540.           with the null string, this provides an easy way to interpose
  1541.           tests and construct loops.  Suppose we execute the statement:
  1542.  
  1543.                        N = LT(N,10) N + 1       :S(LOOP)
  1544.  
  1545.             Function LT fails if N is 10 or greater.  If the statement
  1546.           fails, the assignment is not performed, and execution continues
  1547.           with the next statement.  However, if LT succeeds, its null
  1548.           string value is concatenated with the expression N + 1, and the
  1549.           result is assigned to N.  This has the effect of increasing N by
  1550.           1 and transferring to statement LOOP until N reaches 10.
  1551.  
  1552.             If we concatenated several conditional functions together, and
  1553.           they all succeeded, the result would still be the null string.
  1554.           If any function failed, the entire concatenation would fail.
  1555.           This gives us a simple way to produce a successful result if a
  1556.           number of conditions are all true.  For example, the expression:
  1557.  
  1558.                        INTEGER(N) GE(N,5) LE(N,100)
  1559.  
  1560.  
  1561.  
  1562.        Tutorial                        - 21 -      Control Flow and Functions
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.           succeeds if N is an integer between 5 and 100.
  1569.  
  1570.  
  1571.           4.3.2 Other Functions
  1572.  
  1573.             These functions always succeed; all but REMDR and SIZE return a
  1574.           string result.
  1575.  
  1576.              DATE()           Return current date and time as a string.
  1577.  
  1578.              DUPL(S,N)        Duplicate string S, N times.
  1579.  
  1580.              REMDR(X,Y)       Produce the remainder (modulus) of X / Y.
  1581.  
  1582.              REPLACE(S1,S2,S3)     Return string S1 after performing the
  1583.                               character replacements specified by strings
  1584.                               S2 and S3.  S2 specifies which characters to
  1585.                               replace, and S3 specifies what to replace
  1586.                               them with.
  1587.  
  1588.              SIZE(S)          Return the number of characters in string S.
  1589.  
  1590.              TRIM(S)          Return string S with trailing blanks removed.
  1591.  
  1592.             Exercises for CODE.SNO:
  1593.  
  1594.                ?       OUTPUT = 'THE DATE AND TIME ARE: ' DATE()
  1595.                THE DATE AND TIME ARE: 10-19-87 11:49:33.90
  1596.                ?       OUTPUT = DUPL('ABC', 20)
  1597.                ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC
  1598.                ?       OUTPUT = SIZE('ZIPPY')
  1599.                5
  1600.                ?       OUTPUT = SIZE('')
  1601.                0
  1602.                ?       OUTPUT = TRIM('TRAILING BLANKS  ') 'GONE'
  1603.                TRAILING BLANKSGONE
  1604.                ?       OUTPUT = REPLACE('spoon','po','PO')
  1605.                sPOOn
  1606.  
  1607.  
  1608.  
  1609.  
  1610.  
  1611.  
  1612.  
  1613.  
  1614.  
  1615.  
  1616.  
  1617.  
  1618.  
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624.  
  1625.        Tutorial                        - 22 -      Control Flow and Functions
  1626.  
  1627.  
  1628.  
  1629.  
  1630.  
  1631.                                                                   Chapter 5
  1632.  
  1633.  
  1634.                                                   INPUT/OUTPUT AND KEYWORDS
  1635.           -----------------------------------------------------------------
  1636.  
  1637.  
  1638.                                   5.1 INPUT/OUTPUT
  1639.  
  1640.             We've already performed simple input and output with variables
  1641.           INPUT and OUTPUT.  In this chapter, you'll learn more about
  1642.           SNOBOL4's I/O capabilities.
  1643.  
  1644.             SNOBOL4 can communicate with up to 16 different files at once.
  1645.           A "file" is either a disk file or a device, such as a printer.
  1646.           Every file is identified by a "unit number," which is an integer
  1647.           between 1 and 16.  You chose the numbers when you select the
  1648.           files you wish to use.  The particular numbers chosen have no
  1649.           special significance; they just distinguish one file from
  1650.           another.
  1651.  
  1652.             Actual input or output of data is performed by "associating" a
  1653.           variable with a unit number and a direction.  When a statement
  1654.           tries to use the variable's value, a line is read from the asso-
  1655.           ciated file.  When a value is stored in the variable, a line is
  1656.           written to the associated file.  INPUT and OUTPUT are variables
  1657.           whose association with the keyboard and screen were preset by
  1658.           SNOBOL4.  For historical reasons, they use unit numbers 5 and 6
  1659.           respectively.
  1660.  
  1661.             Strings are the only data type which can be transferred to and
  1662.           from files.  A successful input operation always returns a
  1663.           string.  During output, nonstring objects, such as integers, are
  1664.           automatically converted to their string form.
  1665.  
  1666.             The functions INPUT and OUTPUT (not to be confused with the
  1667.           variables INPUT and OUTPUT) are provided to attach a unit number
  1668.           to a variable, and optionally, to a particular file.  Their names
  1669.           are distinguished from the variables of the same names by appear-
  1670.           ing as functions, that is, with parentheses and an argument list.
  1671.  
  1672.  
  1673.           5.1.1 Associating File Names and Units
  1674.  
  1675.             There are two ways to tell SNOBOL4 what file will be used with
  1676.           a particular unit number:
  1677.  
  1678.             1. As an option on the SNOBOL4 command line, like this:
  1679.  
  1680.                B>SNOBOL4 PROGRAM /2=ADDRESS.TXT /8=RESULT.DAT
  1681.  
  1682.                Here, unit number 2 is associated with the file named
  1683.                'ADDRESS.TXT', and unit number 8 with file 'RESULT.DAT'.  It
  1684.                will still be necessary to use the INPUT or OUTPUT function
  1685.  
  1686.  
  1687.  
  1688.        Tutorial                        - 23 -       Input/Output and Keywords
  1689.  
  1690.  
  1691.  
  1692.  
  1693.  
  1694.                described below to associate variables with these unit num-
  1695.                bers.  This method works best when different files will be
  1696.                used each time the program is run.
  1697.  
  1698.             2. Use a string containing the file name as the fourth argument
  1699.                to the INPUT or OUTPUT function, as in:
  1700.  
  1701.                        INPUT(..., 2, ..., 'ADDRESS.TXT')
  1702.  
  1703.                This method is better when the file name will not change, or
  1704.                is a string derived from a dialogue with the user, or is
  1705.                produced from a string calculation.
  1706.  
  1707.                A file name consisting of a single hyphen ("-") is reserved,
  1708.                and specifies the MS-DOS standard input file when used with
  1709.                the INPUT function, or the standard output file when used
  1710.                with the OUTPUT function.  These standard input or output
  1711.                files may be redirected on the command line using the MS-DOS
  1712.                redirection operators ("<filename" and ">filename").
  1713.  
  1714.  
  1715.           5.1.2 Input
  1716.  
  1717.             This function associates a variable with data read from a file:
  1718.  
  1719.                        INPUT('variable', unit, length, 'file')
  1720.  
  1721.             It succeeds and returns the null string if the file was found
  1722.           and successfully opened, and fails otherwise.  Length is an
  1723.           optional integer that specifies the line length.  If the file
  1724.           name argument is omitted, SNOBOL4 consults the command line to
  1725.           find the file to use with this unit.
  1726.  
  1727.             For example, to open file TEXT.IN for input as unit 1, and as-
  1728.           sociate variable READLINE with it, we would say
  1729.  
  1730.                        INPUT('READLINE', 1, , 'TEXT.IN')    :S(OK)
  1731.                        OUTPUT = 'Could not find file'       :(END)
  1732.                OK       . . .
  1733.  
  1734.             If the file name were specified on the command line as
  1735.           /1=TEXT.IN, we only need the first two arguments to INPUT:
  1736.  
  1737.                        INPUT('READLINE', 1)            :S(OK)
  1738.                        OUTPUT = 'Could not find file'  :(END)
  1739.                OK       . . .
  1740.  
  1741.             To read a line from the file, we simply use READLINE in a
  1742.           statement.  The statement fails when the End-of-File is read:
  1743.  
  1744.                        LINE = READLINE                 :F(END.OF.FILE)
  1745.  
  1746.  
  1747.  
  1748.  
  1749.  
  1750.  
  1751.        Tutorial                        - 24 -       Input/Output and Keywords
  1752.  
  1753.  
  1754.  
  1755.  
  1756.  
  1757.             Each file-associated variable will have a line length associ-
  1758.           ated with it (80 characters unless SNOBOL4 is told otherwise in
  1759.           the length argument).  Normally, reading stops at each end-of-
  1760.           line character (carriage return).  If more than the line length
  1761.           has been read, the extra characters are discarded.  If a short
  1762.           line is encountered, SNOBOL4 pads the line with blanks to produce
  1763.           the full line length.  The end-of-line character is not included
  1764.           in the string returned.
  1765.  
  1766.             Blank padding is another historic feature from the days when
  1767.           most input was on punch cards.  The next section, "Keywords,"
  1768.           will show you how to disable it.  You can also use the TRIM func-
  1769.           tion to remove superfluous trailing blanks.  The previous state-
  1770.           ment then becomes:
  1771.  
  1772.                        LINE = TRIM(READLINE)      :F(END.OF.FILE)
  1773.  
  1774.             When READLINE encounters the End-of-File, its failure signal is
  1775.           propagated outward, causing function TRIM to fail.  This failure
  1776.           is detected in the GOTO field in the usual manner.
  1777.  
  1778.  
  1779.           5.1.3 Output
  1780.  
  1781.             This function associates a variable with data written to a
  1782.           file.  If the file does not exist, it is created.  If it already
  1783.           exists, its previous contents are discarded.
  1784.  
  1785.                        OUTPUT('variable', unit, length, 'file')
  1786.  
  1787.             The function succeeds and returns the null string if the file
  1788.           was successfully opened for output, and fails otherwise.
  1789.  
  1790.             We write data to the file by assigning it to the associated
  1791.           variable.  In this example, we will use a variable called PRINT,
  1792.           and the DOS device PRN: with a line length of 132 characters:
  1793.  
  1794.                        OUTPUT('PRINT', 2, 132, 'PRN:')   :S(PRTOK)
  1795.                        OUTPUT = 'Could not attach printer'  :(END)
  1796.                PRTOK   PRINT  = 'Text Listing - ' DATE()
  1797.                         . . .
  1798.  
  1799.             If the string assigned to an output variable is longer than the
  1800.           line length, SNOBOL4 will output as many lines as necessary of
  1801.           the standard line length to accommodate the string.  SNOBOL4 sup-
  1802.           plies the carriage return and line feed characters at the end of
  1803.           each line.
  1804.  
  1805.             Once again, the output file name could be given on the command
  1806.           line (/2=PRN:).  The function call would then look like this:
  1807.  
  1808.                        OUTPUT('PRINT', 2, 132)           :S(PRTOK)
  1809.                         . . .
  1810.  
  1811.  
  1812.  
  1813.  
  1814.        Tutorial                        - 25 -       Input/Output and Keywords
  1815.  
  1816.  
  1817.  
  1818.  
  1819.  
  1820.           5.1.4 Changing I/O Defaults
  1821.  
  1822.             Having INPUT and OUTPUT associated with the keyboard and screen
  1823.           may be altered in the SNOBOL4 command line.  A surprising number
  1824.           of programs can be written this way, using only the variables
  1825.           INPUT and OUTPUT for I/O.  The command line phrase /I=FILENAME,
  1826.           associates INPUT with the named file, and /O=FILENAME does the
  1827.           same for OUTPUT.  SNOBOL4 makes all the associations for you; no
  1828.           call to the INPUT or OUTPUT function is required.
  1829.  
  1830.             SNOBOL4 also provides the pre-associated variable SCREEN.
  1831.           Using SCREEN allows your program to post messages to the display
  1832.           even if OUTPUT has been redirected elsewhere.
  1833.  
  1834.             If we have a program written in terms of variables INPUT and
  1835.           OUTPUT, it can be run without alteration with different data
  1836.           files.  For example, the following program will copy INPUT to
  1837.           OUTPUT, and place the line length and a blank in front of each
  1838.           line:
  1839.  
  1840.                LOOP    S = TRIM(INPUT)                 :F(END)
  1841.                        OUTPUT = SIZE(S) ' ' S          :(LOOP)
  1842.                END
  1843.  
  1844.             Suppose we associate file TEXT.IN with INPUT, and TEXT.OUT with
  1845.           OUTPUT.  We've supplied the morning song from Shakespeare's
  1846.           Cymbeline in file TEXT.IN, and the program above in file
  1847.           LENGTH.SNO.  You can run it like this:
  1848.  
  1849.                B>SNOBOL4 LENGTH /I=TEXT.IN /O=TEXT.OUT
  1850.                
  1851.                Vanilla SNOBOL4      Version 2.14.
  1852.                (c) Copyright 1984,1988 Catspaw, Inc. All Rights Reserved.
  1853.                
  1854.                No errors
  1855.                
  1856.                B>TYPE TEXT.OUT
  1857.                44 Hark! hark! the lark at heaven's gate sings,
  1858.                 . . .
  1859.  
  1860.             SNOBOL4 will supply the default file name extensions .IN and
  1861.           .OUT for the /I and /O options, so the command line could be
  1862.           shortened to:
  1863.  
  1864.                B>SNOBOL4 LENGTH /I=TEXT /O=TEXT
  1865.  
  1866.  
  1867.  
  1868.  
  1869.  
  1870.  
  1871.  
  1872.  
  1873.  
  1874.  
  1875.  
  1876.  
  1877.        Tutorial                        - 26 -       Input/Output and Keywords
  1878.  
  1879.  
  1880.  
  1881.  
  1882.  
  1883.                                     5.2 KEYWORDS
  1884.  
  1885.             Input/Output allows your program to communicate with the out-
  1886.           side world.  Your program may also communicate with the SNOBOL4
  1887.           system itself.  Keywords allow you to modify SNOBOL4's behavior,
  1888.           and to obtain information from the system.  A keyword consists of
  1889.           the ampersand character (&) followed by an alphabetic name.  They
  1890.           are used in a statement in the same way as a variable.  They
  1891.           either provide values or have values assigned to them.  Numeric
  1892.           keywords are restricted to integer values.
  1893.  
  1894.           -----------------------------------------------------------------
  1895.  
  1896.           &TRIM                            Remove trailing blanks
  1897.  
  1898.             Normally, short lines read from a file are padded with blank
  1899.           characters to the standard line length.  In LENGTH.SNO, we used
  1900.           the function TRIM(INPUT) to remove those blanks.  A simpler
  1901.           method assigns an integer value to keyword &TRIM to control
  1902.           padding.  If &TRIM is set to a nonzero value, blanks are not
  1903.           appended, and any trailing blanks are removed.  A statement to do
  1904.           this looks like this:
  1905.  
  1906.                        &TRIM = 1
  1907.  
  1908.             Since trailing blanks are usually not desired, you'll often see
  1909.           this statement at the beginning of many SNOBOL4 programs.
  1910.  
  1911.           -----------------------------------------------------------------
  1912.  
  1913.           &MAXLNGTH                        Maximum string length
  1914.  
  1915.             This keyword controls the maximum permissible string length.
  1916.           Its initial value is 5000, but it may be set to any positive
  1917.           integer from 0 to 32767.  Setting it to 0 is going to severly re-
  1918.           strict what you can do, since only the null string will be avail-
  1919.           able to you!
  1920.  
  1921.           -----------------------------------------------------------------
  1922.  
  1923.           &DUMP                            Termination dump of variables
  1924.  
  1925.             This keyword is useful for debugging programs because it tells
  1926.           SNOBOL4 to display the values of your variables when your program
  1927.           terminates.  Setting &DUMP to a positive, nonzero integer causes
  1928.           the variable names to be sorted alphabetically.  A negative inte-
  1929.           ger produces a unsorted dump.  Zero is the default value, inhibi-
  1930.           ting the dump.  Only variables with nonnull values are displayed.
  1931.  
  1932.  
  1933.  
  1934.  
  1935.  
  1936.  
  1937.  
  1938.  
  1939.  
  1940.        Tutorial                        - 27 -       Input/Output and Keywords
  1941.  
  1942.  
  1943.  
  1944.  
  1945.  
  1946.           -----------------------------------------------------------------
  1947.  
  1948.           &ALPHABET                        Complete character set
  1949.  
  1950.             This keyword contains a 256 character string, the computer's
  1951.           entire character set in ascending sequence.  It is called a pro-
  1952.           tected keyword because it cannot be modified by your program.
  1953.  
  1954.           -----------------------------------------------------------------
  1955.  
  1956.           &LCASE                           Lower case letters
  1957.  
  1958.             This keyword contains the 26 lower case alphabetic characters,
  1959.           "abcdefghijklmnopqrstuvwxyz".
  1960.  
  1961.           -----------------------------------------------------------------
  1962.  
  1963.           &UCASE                           Upper case letters
  1964.  
  1965.             This keyword contains the 26 upper case alphabetic characters,
  1966.           "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
  1967.  
  1968.  
  1969.                         5.3 PROGRAMS WITHOUT PATTERN MATCHING
  1970.  
  1971.             You now have the ingredients to create some simple programs.
  1972.           However, if this were all of the SNOBOL4 language, there would be
  1973.           very little reason to use it.  We'll get to pattern matching
  1974.           shortly, where you'll find many new, challenging concepts.
  1975.           First, however, you should be comfortable with the preceding
  1976.           material.
  1977.  
  1978.             Take a few minutes to examine and run the following programs.
  1979.  
  1980.  
  1981.           5.3.1 File Counts - FCOUNTS.SNO
  1982.  
  1983.             This program counts the number of characters and lines in a
  1984.           file.  Because real numbers are not available in Vanilla SNOBOL4,
  1985.           you should only use this program with input files smaller than
  1986.           32,767 characters.
  1987.  
  1988.                        &TRIM  = 1
  1989.                        CHARS  = 0
  1990.                NEXTL   CHARS  = CHARS + SIZE(INPUT)    :F(DONE)
  1991.                        LINES  = LINES + 1              :(NEXTL)
  1992.                DONE    OUTPUT = CHARS ' characters'
  1993.                        OUTPUT = +LINES ' lines read'
  1994.                END
  1995.  
  1996.  
  1997.  
  1998.  
  1999.  
  2000.  
  2001.  
  2002.  
  2003.        Tutorial                        - 28 -       Input/Output and Keywords
  2004.  
  2005.  
  2006.  
  2007.  
  2008.  
  2009.             In such a small program, it's permissible to rely upon the fact
  2010.           that the system initializes LINES to the null string.  The first
  2011.           use of the statement:
  2012.  
  2013.                        LINES  = LINES + 1              :(NEXTL)
  2014.  
  2015.           converts LINES from the null string to an integer value.  We used
  2016.           the expression +LINES in the last statement to produce an integer
  2017.           0 (instead of the null string), if the input file were empty.  To
  2018.           count the characters and lines in a file, use the /I= option, as
  2019.           in:
  2020.  
  2021.                B>SNOBOL4 FCOUNTS.SNO /I=TEXT.IN
  2022.  
  2023.  
  2024.           5.3.2 Formatting Text - TRIPLET.SNO
  2025.  
  2026.             This program reformats a file by centering the lines and ar-
  2027.           ranging them in groups of three.  Note that statements containing
  2028.           an asterisk in column one are considered comments by SNOBOL4.
  2029.  
  2030.                * Trim input, count input lines:
  2031.                        &TRIM = 1
  2032.                        N = 0
  2033.                
  2034.                * Read next input line, all done if End-of-File.
  2035.                LOOP    S = INPUT                       :F(END)
  2036.                
  2037.                * Precede with blanks to center within 80 character line:
  2038.                        OUTPUT = DUPL(' ', (80 - SIZE(S)) / 2) S
  2039.                
  2040.                * Increment count, but reset to 0 every third line.
  2041.                * Also, output a blank line when count resets:
  2042.                        N = REMDR(N + 1, 3)
  2043.                        OUTPUT = EQ(N, 0)               :(LOOP)
  2044.                END
  2045.  
  2046.             This program uses the DUPL function to produce the leading
  2047.           blanks required to center a line.  A simple calculation based on
  2048.           each line's width determines the number of blanks needed.
  2049.  
  2050.             The last two statements break the file lines into triplets.
  2051.           The REMDR function returns the integer remainder (modulus) when
  2052.           the first argument is divided by the second.  In this case,
  2053.           assigning the result to variable N causes N to continually cycle
  2054.           through the values 0, 1, 2, 0, 1, ....  When N is 0, the last
  2055.           statement assigns the null string to OUTPUT, producing a blank
  2056.           line.  If N is 1 or 2, EQ fails, and the assignment fails.
  2057.  
  2058.             Try running the program with the sample text file:
  2059.  
  2060.                B>SNOBOL4 TRIPLET /I=TEXT
  2061.  
  2062.  
  2063.  
  2064.  
  2065.  
  2066.        Tutorial                        - 29 -       Input/Output and Keywords
  2067.  
  2068.  
  2069.  
  2070.  
  2071.  
  2072.                                                                   Chapter 6
  2073.  
  2074.  
  2075.                                                            PATTERN MATCHING
  2076.           -----------------------------------------------------------------
  2077.  
  2078.  
  2079.                                   6.1 INTRODUCTION
  2080.  
  2081.             Pattern matching examines a "subject" string for some combina-
  2082.           tion of characters, called a "pattern."  The matching process may
  2083.           be very simple, or extremely complex.  For example:
  2084.  
  2085.             1. The subject contains several color names.  The pattern is
  2086.                the string "BLUE".  Does the subject string contain the word
  2087.                "BLUE"?
  2088.  
  2089.             2. The subject contains a nucleic acid (DNA) sequence.  The
  2090.                pattern searches for a subsequence that is replicated in two
  2091.                other places in the string.
  2092.  
  2093.             3. The subject contains a paragraph of English text.  The
  2094.                pattern describes the spacing rules to be applied after
  2095.                punctuation.  Does the subject string conform to the
  2096.                punctuation rules?
  2097.  
  2098.             4. The subject string represents the current board position in
  2099.                a game of Tick-Tack-Toe.  The pattern examines this string
  2100.                and determines the next move.
  2101.  
  2102.             5. The subject contains a program statement from a prototype
  2103.                computer language.  The pattern contains the grammar of that
  2104.                language.  Is the statement properly formed according to the
  2105.                grammar?
  2106.  
  2107.             Most programming languages provide rudimentary facilities to
  2108.           examine a string for a specific character sequence.  SNOBOL4 pat-
  2109.           terns are far more powerful, because they can specify complex
  2110.           (and convoluted) interrelationships.  The colors of a painting,
  2111.           the words of a sentence, the notes of a musical score have lim-
  2112.           ited significance in isolation.  It is their "relationship" with
  2113.           one another which provides meaning to the whole.  Likewise,
  2114.           SNOBOL4 patterns can specify "context;" they may be qualified by
  2115.           what precedes or follows them, or by their position in the
  2116.           subject.
  2117.  
  2118.  
  2119.           6.1.1 Knowns and Unknowns
  2120.  
  2121.             Patterns are composed of "known" and "unknown" components.
  2122.  
  2123.             "Knowns" are specific character strings, such as the string
  2124.           "BLUE" in the first example above.  We are looking for a yes/no
  2125.           answer to the question: "Does this known item appear in the sub-
  2126.  
  2127.  
  2128.  
  2129.        Tutorial                        - 30 -                Pattern Matching
  2130.  
  2131.  
  2132.  
  2133.  
  2134.  
  2135.           ject string?"
  2136.  
  2137.             "Unknowns" specify the "kind" of subject characters we are
  2138.           looking for; the specific characters are not identifiable in
  2139.           advance.  We might want to match only characters from a
  2140.           restricted alphabet, or any substring of a certain length, or
  2141.           some arbitrary number of repetitions of a string.  If the pattern
  2142.           matches, we can then "capture" the particular subject substring
  2143.           matched.
  2144.  
  2145.  
  2146.                            6.2 SPECIFYING PATTERN MATCHING
  2147.  
  2148.             A pattern match requires a subject string and a pattern.  The
  2149.           subject is the first statement element after the label field (if
  2150.           any).  The pattern appears next, separated from the subject by
  2151.           white space (blank or tab).  If SUBJECT is the subject string,
  2152.           and PATTERN is the pattern, it looks like this:
  2153.  
  2154.                label   SUBJECT PATTERN
  2155.  
  2156.             The pattern match "succeeds" if the pattern is found in the
  2157.           subject string; otherwise it fails.  This success or failure may
  2158.           be tested in the GOTO field:
  2159.  
  2160.                label   SUBJECT PATTERN            :S(label1) F(label2)
  2161.  
  2162.             A real point of confusion is the distinction between pattern
  2163.           matching and concatenation.  How do you tell the difference?
  2164.           Where does the subject end and the pattern begin?  In this case,
  2165.           parentheses should be placed around the subject, since SNOBOL4
  2166.           always uses the first "complete" statement element as the
  2167.           subject.  In the statement
  2168.  
  2169.                        X Y Z
  2170.  
  2171.           X is the subject, and Y concatenated with Z is the pattern.
  2172.           Whereas
  2173.  
  2174.                        (X Y) Z
  2175.  
  2176.           indicates the subject is string X concatenated with string Y, and
  2177.           the pattern is Z.
  2178.  
  2179.  
  2180.                                  6.3 SUBJECT STRING
  2181.  
  2182.             The subject string may be a literal string, a variable, or an
  2183.           expression.  If it is not a string, its string equivalent will be
  2184.           produced before pattern matching begins.  For example, if the
  2185.           subject is the integer 48, integer to string conversion produces
  2186.           the character string "48".  Remember, if the subject includes
  2187.           concatenated elements, they should be enclosed in parentheses.
  2188.  
  2189.  
  2190.  
  2191.  
  2192.        Tutorial                        - 31 -                Pattern Matching
  2193.  
  2194.  
  2195.  
  2196.  
  2197.  
  2198.                        6.4 PATTERN SUBSEQUENTS AND ALTERNATES
  2199.  
  2200.             Arithmetic expressions are composed of elements and simpler
  2201.           subexpressions.  Similarly, patterns are composed of simpler sub-
  2202.           patterns which are joined together as "subsequents" and "alter-
  2203.           nates."  If P1 and P2 are two subpatterns, the expression
  2204.  
  2205.                        P1 P2
  2206.  
  2207.           is also a pattern.  The subject must contain whatever P1 matches,
  2208.           immediately followed by whatever P2 matches.  P2 is the "subse-
  2209.           quent" of P1.  The white space (blank or tab) between P1 and P2
  2210.           is the same binary concatenation operator previously used to join
  2211.           strings; its use with patterns is completely analogous.  The pre-
  2212.           ceding pattern matches pattern P1 "followed by pattern" P2.
  2213.  
  2214.             The binary "alternation" operator is the vertical bar (|).  As
  2215.           it is a binary operator, it must have white space on each side.
  2216.           The pattern
  2217.  
  2218.                        P1 | P2
  2219.  
  2220.           matches whatever P1 matches, "or" whatever P2 matches.  SNOBOL4
  2221.           tries the various alternatives from left to right.
  2222.  
  2223.             Normally, concatenation is performed before alternation, so the
  2224.           pattern
  2225.  
  2226.                        P1 | P2 P3
  2227.  
  2228.           matches P1 alone, or P2 "followed by" P3.  Parentheses can be
  2229.           used to alter the grouping of subpatterns.  For example:
  2230.  
  2231.                        (P1 | P2) P3
  2232.  
  2233.           matches P1 "or" P2, followed by P3.
  2234.  
  2235.             When a pattern successfully matches a portion of the subject,
  2236.           the matching subject characters are "bound" to it.  The next pat-
  2237.           tern in the statement must match beginning with the very next
  2238.           subject character.  If a subsequent fails to match, SNOBOL4 back-
  2239.           tracks, unbinding patterns until another alternative can be
  2240.           tried.  A pattern match fails when SNOBOL4 cannot find an alter-
  2241.           native that matches.
  2242.  
  2243.             The null string may appear in a pattern.  It always matches,
  2244.           but does not bind any subject characters.  We can think of it as
  2245.           matching the invisible space "between" two subject characters.
  2246.           One possible use is as the last of a series of alternatives.  For
  2247.           example, the pattern
  2248.  
  2249.                        ROOT ('S' | 'ES' | '')
  2250.  
  2251.           matches the pattern in ROOT, with an optional suffix of 'S' or
  2252.  
  2253.  
  2254.  
  2255.        Tutorial                        - 32 -                Pattern Matching
  2256.  
  2257.  
  2258.  
  2259.  
  2260.  
  2261.           'ES'.  If ROOT matches, but is not followed by 'S' or 'ES', the
  2262.           null string matches and successfully completes the clause.  Its
  2263.           presence gives the pattern match a successful escape.
  2264.  
  2265.             The conditional functions of the previous chapter may appear in
  2266.           patterns.  If they fail when evaluated, the current alternative
  2267.           fails.  If they succeed, they match the null string, and so do
  2268.           not consume any subject characters.  They behave like a gate,
  2269.           allowing the match to proceed beyond them only if they are true.
  2270.           This pattern will match 'FOX' if N is 1, or 'WOLF' if N is 2:
  2271.  
  2272.                        EQ(N,1) 'FOX' | EQ(N,2) 'WOLF'
  2273.  
  2274.             Parentheses may be used to factor a pattern.  The strings
  2275.           'COMPATIBLE', 'COMPREHENSIBLE', and 'COMPRESSIBLE' are matched by
  2276.           the pattern:
  2277.  
  2278.                        'COMP' ('AT' | 'RE' ('HEN' | 'S') 'S') 'IBLE'
  2279.  
  2280.  
  2281.                              6.5 SIMPLE PATTERN MATCHES
  2282.  
  2283.             Here are examples of pattern matches using a string literal or
  2284.           variable for the subject.  The patterns consist entirely of known
  2285.           elements.  Use the CODE.SNO program to experiment with them:
  2286.  
  2287.                ?       'BLUEBIRD' 'BIRD'
  2288.                Success
  2289.                ?       'BLUEBIRD' 'bird'
  2290.                Failure
  2291.                ?       B = 'THE BLUEBIRD'
  2292.                ?       B 'FISH'
  2293.                Failure
  2294.                ?       B 'FISH' | 'BIRD'
  2295.                Success
  2296.                ?       B ('GOLD' | 'BLUE') ('FISH' | 'BIRD')
  2297.                Success
  2298.  
  2299.             The first statement shows that the matching substring ('BIRD')
  2300.           need not begin at the start of the subject string.  This is
  2301.           called "unanchored" matching.  The second statement fails because
  2302.           strings are case sensitive, unlike names and labels.  The third
  2303.           statement creates a variable to be used as the subject.  The
  2304.           fifth statement employs an alternate: we are matching for 'FISH'
  2305.           or 'BIRD'.
  2306.  
  2307.             The last statement uses subsequents and alternates.  We are
  2308.           looking for a substring in B that contains 'GOLD' or 'BLUE', fol-
  2309.           lowed by 'FISH' or 'BIRD'.  It will match 'GOLDFISH', 'GOLDBIRD',
  2310.           'BLUEFISH' or 'BLUEBIRD'.  If the parentheses were omitted, con-
  2311.           catenation of 'BLUE' and 'FISH' would be performed before alter-
  2312.           nation, and the pattern would match 'GOLD', 'BLUEFISH', or
  2313.           'BIRD'.
  2314.  
  2315.  
  2316.  
  2317.  
  2318.        Tutorial                        - 33 -                Pattern Matching
  2319.  
  2320.  
  2321.  
  2322.  
  2323.  
  2324.                               6.6 THE PATTERN DATA TYPE
  2325.  
  2326.             If we execute the statement
  2327.  
  2328.                ?       COLOR = 'BLUE'
  2329.  
  2330.           the variable COLOR contains the string 'BLUE', and could appear
  2331.           in the pattern portion of a statement:
  2332.  
  2333.                ?       B COLOR
  2334.                Success
  2335.  
  2336.             Even though it is used as a pattern, COLOR has the "string"
  2337.           data type.  However, complicated patterns may be stored in a
  2338.           variable just like a string or numeric value.  The statement
  2339.  
  2340.                ?       COLOR = 'GOLD' | 'BLUE'
  2341.  
  2342.           will create a "structure" describing the pattern, and store it in
  2343.           the variable COLOR.  COLOR now has the "pattern" data type.  The
  2344.           preceding example can now be written as:
  2345.  
  2346.                ?       CRITTER = 'FISH' | 'BIRD'
  2347.                ?       BOTH = COLOR CRITTER
  2348.                ?       B BOTH
  2349.                Success
  2350.  
  2351.  
  2352.                              6.7 CAPTURING MATCH RESULTS
  2353.  
  2354.             If the pattern match
  2355.  
  2356.                        B BOTH
  2357.  
  2358.           succeeds, we may want to know which of the many pattern alterna-
  2359.           tives were used in the match.  The binary operator "conditional
  2360.           assignment" assigns the matching subject substring to a variable.
  2361.           The operator is called conditional, because assignment occurs
  2362.           ONLY if the entire pattern match is successful.  Its graphic
  2363.           symbol is a period (.).  It assigns the matching substring on its
  2364.           left to the variable on its right.  Note that the direction of
  2365.           assignment is just the opposite of the statement assignment oper-
  2366.           ator (=).  Continuing with the previous example, we'll redefine
  2367.           COLOR and CRITTER to use conditional assignment:
  2368.  
  2369.                ?       COLOR = ('GOLD' | 'BLUE') . SHADE
  2370.                ?       CRITTER = ('FISH' | 'BIRD') . ANIMAL
  2371.                ?       BOTH = COLOR CRITTER
  2372.                ?       B BOTH
  2373.                Success
  2374.                ?       OUTPUT = SHADE
  2375.                BLUE
  2376.                ?       OUTPUT = ANIMAL
  2377.                BIRD
  2378.  
  2379.  
  2380.  
  2381.        Tutorial                        - 34 -                Pattern Matching
  2382.  
  2383.  
  2384.  
  2385.  
  2386.  
  2387.             The substrings that match the subpatterns COLOR and CRITTER are
  2388.           assigned to SHADE and ANIMAL respectively.  The statement
  2389.  
  2390.                        BOTH = COLOR CRITTER
  2391.  
  2392.           had to be reexecuted because its previous execution captured the
  2393.           old values of COLOR and CRITTER, without the conditional assign-
  2394.           ment operators.  The redefinition of COLOR and CRITTER was not
  2395.           reflected in BOTH until the statement was reexecuted.
  2396.  
  2397.             Conditional assignment may appear at any level of pattern nest-
  2398.           ing, and may include other conditional assignments within its
  2399.           embrace.  The pattern
  2400.  
  2401.                (('B' | 'F' | 'N') . FIRST 'EA' ('R' | 'T') . LAST) . WORD
  2402.  
  2403.           matches 'BEAR', 'FEAR', 'NEAR', 'BEAT', 'FEAT', or 'NEAT',
  2404.           assigning the first letter matched to FIRST, the last letter to
  2405.           LAST, and the entire result to WORD.
  2406.  
  2407.             The variable OUTPUT may be used as the target of conditional
  2408.           assignment.  Try:
  2409.  
  2410.                ?       'B2' ('A' | 'B') . OUTPUT (1 | 2 | 3) . OUTPUT
  2411.                B
  2412.                2
  2413.                Success
  2414.  
  2415.  
  2416.                                     6.8 UNKNOWNS
  2417.  
  2418.             All of the previous examples used patterns created from literal
  2419.           strings.  We may also want to specify the "qualities" of a match
  2420.           component, rather than its specific characters.  Using unknowns
  2421.           greatly increases the power of pattern matching.  There are two
  2422.           types, primitive patterns and pattern functions.
  2423.  
  2424.  
  2425.           6.8.1 Primitive Patterns
  2426.  
  2427.             There are seven primitive patterns built into the SNOBOL4
  2428.           system.  The two used most frequently will be discussed here.
  2429.           Chapter 9, "Advanced Topics," introduces the remaining five.
  2430.  
  2431.           -----------------------------------------------------------------
  2432.  
  2433.           REM                              Match remainder of subject
  2434.  
  2435.             REM is short for the REMainder pattern.  It will match zero or
  2436.           more characters at the end of the subject string.  Try the
  2437.           following:
  2438.  
  2439.  
  2440.  
  2441.  
  2442.  
  2443.  
  2444.        Tutorial                        - 35 -                Pattern Matching
  2445.  
  2446.  
  2447.  
  2448.  
  2449.  
  2450.                ?       'THE WINTER WINDS' 'WIN' REM . OUTPUT
  2451.                TER WINDS
  2452.                Success
  2453.  
  2454.             The subpattern 'WIN' matched its first occurrence in the sub-
  2455.           ject, at the beginning of the word 'WINTER'.  REM matched from
  2456.           there to the end of the subject string---the characters 'TER
  2457.           WINDS'---and assigned them to the variable OUTPUT.  If we change
  2458.           the pattern slightly, to:
  2459.  
  2460.                ?       'THE WINTER WINDS' 'WINDS' REM . OUTPUT
  2461.                
  2462.                Success
  2463.  
  2464.           then 'WINDS' matches at the end of the subject string, leaving a
  2465.           null remainder for REM.  REM matches this null string, assigns it
  2466.           to OUTPUT, and a blank line is displayed.
  2467.  
  2468.             The pattern components to the left of REM must successfully
  2469.           match some portion of the subject string.  REM begins where they
  2470.           left off, matching all subject characters through the end of
  2471.           string.  There are no restrictions on the particular characters
  2472.           matched.
  2473.  
  2474.           -----------------------------------------------------------------
  2475.  
  2476.           ARB                              Match arbitrary characters
  2477.  
  2478.             ARB matches an ARBitrary number of characters from the subject
  2479.           string.  It matches the shortest possible substring, including
  2480.           the null string.  The pattern components on either side of ARB
  2481.           determine what is matched.  Try the statements
  2482.  
  2483.                ?       'MOUNTAIN' 'O' ARB . OUTPUT 'A'
  2484.                UNT
  2485.                Success
  2486.                ?       'MOUNTAIN' 'O' ARB . OUTPUT 'U'
  2487.                
  2488.                Success
  2489.  
  2490.             In the first statement, the ARB pattern is constrained on
  2491.           either side by the known patterns 'O' and 'A'.  ARB expands to
  2492.           match the subject characters between, 'UNT'.  In the second
  2493.           statement, there is nothing between 'O' and 'U', so ARB matches
  2494.           the null string.  ARB behaves like a spring, expanding as needed
  2495.           to fill the gap defined by neighboring patterns.
  2496.  
  2497.  
  2498.           6.8.2 Cursor Position
  2499.  
  2500.             During a pattern match, the "cursor" is SNOBOL4's pointer into
  2501.           the subject string.  It is integer valued, and points "between"
  2502.           two subject characters.  The cursor is set to zero when a pattern
  2503.           match begins, corresponding to a position immediately to the left
  2504.  
  2505.  
  2506.  
  2507.        Tutorial                        - 36 -                Pattern Matching
  2508.  
  2509.  
  2510.  
  2511.  
  2512.  
  2513.           of the first subject character.  As the pattern match proceeds,
  2514.           the cursor moves right and left across the subject to indicate
  2515.           where SNOBOL4 is attempting a match.  The value of the cursor
  2516.           will be used by some of the pattern functions that follow.
  2517.  
  2518.             The "cursor position" operator assigns the current cursor value
  2519.           to a variable.  It is a unary operator whose graphic symbol is
  2520.           the "at sign" (@).  It appears within a pattern, preceding the
  2521.           name of a variable.  By using OUTPUT as the variable, we can
  2522.           display the cursor position on the screen.  For instance:
  2523.  
  2524.                ?       'VALLEY' 'A' @OUTPUT ARB 'E' @OUTPUT
  2525.                2
  2526.                5
  2527.                Success
  2528.                ?       'DOUBT' @OUTPUT 'B'
  2529.                0
  2530.                1
  2531.                2
  2532.                3
  2533.                Success
  2534.                ?       'FIX' @OUTPUT 'B'
  2535.                0
  2536.                1
  2537.                2
  2538.                Failure
  2539.  
  2540.             Cursor assignment is performed whenever the pattern match
  2541.           encounters the operator, including retries.  It occurs even if
  2542.           the pattern ultimately fails.  The element @OUTPUT behaves like
  2543.           the null string---it doesn't consume subject characters or inter-
  2544.           fere with the match in any way.
  2545.  
  2546.  
  2547.           6.8.3 Integer Pattern Functions
  2548.  
  2549.             These functions return a pattern based on their integer argu-
  2550.           ment.  The pattern produced can be used directly in a pattern
  2551.           match statement, or stored in a variable for later retrieval.
  2552.  
  2553.           -----------------------------------------------------------------
  2554.  
  2555.           LEN(integer)                     Match fixed-length string
  2556.  
  2557.             LEN(I) produces a pattern which matches a string exactly I
  2558.           characters long.  I must be an integer greater than or equal to
  2559.           zero.  Any characters may appear in the matched string.  For
  2560.           example, LEN(5) matches any 5-character string, and LEN(0)
  2561.           matches the null string.  LEN may be constrained to certain por-
  2562.           tions of the subject by other adjacent patterns:
  2563.  
  2564.  
  2565.  
  2566.  
  2567.  
  2568.  
  2569.  
  2570.        Tutorial                        - 37 -                Pattern Matching
  2571.  
  2572.  
  2573.  
  2574.  
  2575.  
  2576.                ?       S = 'ABCDA'
  2577.                ?       S LEN(3) . OUTPUT
  2578.                ABC
  2579.                ?       S LEN(2) . OUTPUT 'A'
  2580.                CD
  2581.  
  2582.             The first pattern match had only one constraint---the subject
  2583.           had to be at least three characters long---so LEN(3) matched its
  2584.           first three characters.  The second case imposes the additional
  2585.           restriction that LEN(2)'s match be followed immediately by the
  2586.           letter 'A'.  This disqualifies the intermediate match attempts
  2587.           'AB' and 'BC'.
  2588.  
  2589.             Using keyword &ALPHABET as the subject provides a simple way to
  2590.           convert a decimal character code between 0 and 255 to its one
  2591.           character equivalent.  For example, by consulting an ASCII char-
  2592.           acter code chart we find that the BEL character is decimal 7.  We
  2593.           can load that character into variable BEEP with one statement:
  2594.  
  2595.                ?       &ALPHABET LEN(7) LEN(1) . BEEP
  2596.  
  2597.           and produce five beeps on the speaker with:
  2598.  
  2599.                ?       OUTPUT = DUPL(BEEP,5)
  2600.  
  2601.             &ALPHABET contains all 256 members of the computer's character
  2602.           set, in ascending order.  LEN(7) matches the first seven charac-
  2603.           ters (codes 0 - 6), leaving BEL as the next match position for
  2604.           LEN(1).  This operation is analogous to the CHR$ function in
  2605.           BASIC.
  2606.  
  2607.             The inverse operation, obtaining the numerical value of a char-
  2608.           acter code, is also possible.  If variable CHAR contains a one
  2609.           character string, variable N will be set to its decimal equiva-
  2610.           lent with the second statement below:
  2611.  
  2612.                ?       CHAR = 'A'
  2613.                ?       &ALPHABET @N CHAR
  2614.                ?       OUTPUT = N
  2615.                65
  2616.  
  2617.             In Chapter 8, "Program Defined Objects," I'll demonstrate how
  2618.           you can define your own functions to encapsulate each of these
  2619.           operations.
  2620.  
  2621.           -----------------------------------------------------------------
  2622.  
  2623.           POS(integer), RPOS(integer)      Verify cursor position
  2624.  
  2625.             The POS(I) and RPOS(I) patterns do not match subject charac-
  2626.           ters.  Instead, they succeed only if the "current" cursor posi-
  2627.           tion is a specified value.  They often are used to tie points of
  2628.           the pattern to specific character positions in the subject.
  2629.  
  2630.  
  2631.  
  2632.  
  2633.        Tutorial                        - 38 -                Pattern Matching
  2634.  
  2635.  
  2636.  
  2637.  
  2638.  
  2639.             POS(I) counts from the left end of the subject string, succeed-
  2640.           ing if the current cursor position is equal to I.  RPOS(I) is
  2641.           similar, but counts from the right end of the subject.  If the
  2642.           subject length is N characters, RPOS(I) requires the cursor be
  2643.           (N - I).  If the cursor is not the correct value, these functions
  2644.           fail, and SNOBOL4 tries other pattern alternatives, perhaps
  2645.           extending a previous substring matched by ARB, or beginning the
  2646.           match further along in the subject.
  2647.  
  2648.             Continuing with CODE.SNO:
  2649.  
  2650.                ?       S = 'ABCDA'
  2651.                ?       S POS(0) 'B'
  2652.                Failure
  2653.                ?       S LEN(3) . OUTPUT RPOS(0)
  2654.                CDA
  2655.                ?       S POS(3) LEN(1) . OUTPUT
  2656.                D
  2657.                ?       S POS(0) 'ABCD' RPOS(0)
  2658.                Failure
  2659.  
  2660.             The first example requires a 'B' at cursor position 0, and
  2661.           fails for this subject.  POS(0) "anchors" the match, forcing it
  2662.           to begin with the first subject character.  Similarly, RPOS(0)
  2663.           anchors the end of the pattern to the tail of the subject.  The
  2664.           next example matches at a specific mid-string character position,
  2665.           POS(3).  Finally, enclosing a pattern between POS(0) and RPOS(0)
  2666.           forces the match to use the ENTIRE subject string.
  2667.  
  2668.             At first glance these functions appear to be "setting" the
  2669.           cursor to a specified value.  Actually, they never alter the
  2670.           cursor, but instead wait for the cursor to "come to them" as
  2671.           various match alternatives are attempted.  This, in turn, allows
  2672.           other patterns in the statement to be processed in an orderly
  2673.           fashion.  You can demonstrate this "waiting for the cursor"
  2674.           behavior like this:
  2675.  
  2676.                ?       S @OUTPUT POS(3)
  2677.                0
  2678.                1
  2679.                2
  2680.                3
  2681.                Success
  2682.  
  2683.           -----------------------------------------------------------------
  2684.  
  2685.           TAB(integer), RTAB(integer)      Match to fixed position
  2686.  
  2687.             These patterns are hybrids of ARB, POS(), and RPOS().  They use
  2688.           specific cursor positions, like POS and RPOS, but bind (match)
  2689.           subject characters, like ARB.  TAB(I) matches any characters from
  2690.           the current cursor position up to the specified position I.
  2691.           RTAB(I) does the same, except, as in RPOS(), the target position
  2692.           is measured from the end of the subject.
  2693.  
  2694.  
  2695.  
  2696.        Tutorial                        - 39 -                Pattern Matching
  2697.  
  2698.  
  2699.  
  2700.  
  2701.  
  2702.             TAB and RTAB will match the null string, but will fail if the
  2703.           current cursor is to the right of the target.  They also fail if
  2704.           the target position is past the end of the subject string.
  2705.  
  2706.             These patterns are useful when working with tabular data.  For
  2707.           example, if a data file contains name, street address, city and
  2708.           state in columns 1, 30, 60, and 75, this pattern will break out
  2709.           those elements from a line:
  2710.  
  2711.             P = TAB(29) . NAME TAB(59) . STREET TAB(74) . CITY REM . STATE
  2712.  
  2713.             The pattern RTAB(0) is equivalent to primitive pattern REM.
  2714.           One potential source of confusion is just what it is that RTAB
  2715.           matches.  It counts from the right end of the subject, but
  2716.           matches to the left of its target cursor.  Try:
  2717.  
  2718.                ?       'ABCDE' TAB(2) . OUTPUT RTAB(1) . OUTPUT
  2719.                AB
  2720.                CD
  2721.                Success
  2722.  
  2723.             TAB(2) matches 'AB', leaving the cursor at 2, between 'B' and
  2724.           'C'.  The subject is 5 characters long, so RTAB(1) specifies a
  2725.           target cursor of 5 - 1, or 4, which is between the 'D' and 'E'.
  2726.           RTAB matches everything from the current cursor, 2, to the
  2727.           target, 4.
  2728.  
  2729.  
  2730.           6.8.4 Character Pattern Functions
  2731.  
  2732.             These functions produce a pattern based on a string-valued
  2733.           argument.  Once again, the pattern may be used directly or stored
  2734.           in a variable.
  2735.  
  2736.           -----------------------------------------------------------------
  2737.  
  2738.           ANY(string), NOTANY(string)      Match one character
  2739.  
  2740.             Each function produces a pattern which matches one character
  2741.           based upon the subject string.  ANY(S) matches the next subject
  2742.           character IF it appears in the string S, and fails otherwise.
  2743.           NOTANY(S) matches a subject character only if it does NOT appear
  2744.           in S.  Here are some sample uses of each:
  2745.  
  2746.                ?       VOWEL = ANY('AEIOU')
  2747.                ?       DVOWEL = VOWEL VOWEL
  2748.                ?       NOTVOWEL = NOTANY('AEIOU')
  2749.                ?       'VACUUM' VOWEL . OUTPUT
  2750.                A
  2751.                ?       'VACUUM' DVOWEL . OUTPUT
  2752.                UU
  2753.                ?       'VACUUM' (VOWEL NOTVOWEL) . OUTPUT
  2754.                AC
  2755.  
  2756.  
  2757.  
  2758.  
  2759.        Tutorial                        - 40 -                Pattern Matching
  2760.  
  2761.  
  2762.  
  2763.  
  2764.  
  2765.             The argument string specifies a set of characters to be used in
  2766.           creating the ANY or NOTANY pattern.  It may contain duplicate
  2767.           characters, and the order of characters in S is immaterial.
  2768.  
  2769.           -----------------------------------------------------------------
  2770.  
  2771.           SPAN(string), BREAK(string)      Match a run of characters
  2772.  
  2773.             These are multicharacter versions of ANY and NOTANY.  Each
  2774.           requires a nonnull argument to specify a set of characters.
  2775.  
  2776.             SPAN(S) matches one or more subject characters from the set in
  2777.           S.  SPAN must match at least one subject character, and will
  2778.           match the LONGEST subject string possible.
  2779.  
  2780.             BREAK(S) matches "up to but not including" any character in S.
  2781.           The string matched must always be followed in the subject by a
  2782.           character in S.  Unlike SPAN and NOTANY, BREAK will match the
  2783.           null string.
  2784.  
  2785.             These two functions are called "stream" functions because each
  2786.           streams by a series of subject characters.  SPAN is most useful
  2787.           for matching a group of characters with a common trait.  For
  2788.           example, we can say an English word is composed of one or more
  2789.           alphabetic characters, apostrophe, and hyphen.  The statements
  2790.  
  2791.                ?       LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ'-"
  2792.                ?       WORD = SPAN(LETTERS)
  2793.  
  2794.           produce a suitable pattern in WORD.  To match the material
  2795.           between words (white space, punctuation, etc.), use the pattern:
  2796.  
  2797.                ?       GAP = BREAK(LETTERS)
  2798.  
  2799.             SPAN and BREAK are two of the most useful SNOBOL4 functions.
  2800.           Try some examples using CODE.SNO:
  2801.  
  2802.  
  2803.  
  2804.  
  2805.  
  2806.  
  2807.  
  2808.  
  2809.  
  2810.  
  2811.  
  2812.  
  2813.  
  2814.  
  2815.  
  2816.  
  2817.  
  2818.  
  2819.  
  2820.  
  2821.  
  2822.        Tutorial                        - 41 -                Pattern Matching
  2823.  
  2824.  
  2825.  
  2826.  
  2827.  
  2828.                ?       'SAMPLE LINE' WORD . OUTPUT
  2829.                SAMPLE
  2830.                ?       'PLUS TEN DEGREES' ' ' WORD . OUTPUT
  2831.                TEN
  2832.                ?       GAPO = GAP . OUTPUT
  2833.                ?       WORDO = WORD . OUTPUT
  2834.                ?       ': ONE, TWO, THREE' GAPO WORDO GAPO WORDO
  2835.                :
  2836.                ONE
  2837.                ,
  2838.                TWO
  2839.                        DIGITS = '0123456789'
  2840.                ?       INTEGER = (ANY('+-') | '') SPAN(DIGITS)
  2841.                ?       'SET -43 VOLTS' INTEGER . OUTPUT
  2842.                -43
  2843.                ?       REAL = INTEGER '.' (SPAN(DIGITS) | '')
  2844.                ?       'SET -43.625 VOLTS' REAL . OUTPUT
  2845.                -43.625
  2846.                ?       S = '0ZERO,1ONE,2TWO,3THREE,4FOUR,5FIVE,'
  2847.                ?       S 4 BREAK(',') . OUTPUT
  2848.                FOUR
  2849.  
  2850.             If you require a version of SPAN which WILL match the null
  2851.           string, or a BREAK which will NOT match the null string, you can
  2852.           use the following constructions:
  2853.  
  2854.                        (SPAN(S) | '')
  2855.                        (NOTANY(S) BREAK(S))
  2856.  
  2857.             We need to introduce one more fundamental concept---replace-
  2858.           ment---before we can write some meaningful programs.
  2859.  
  2860.  
  2861.                         6.9 PATTERN MATCHING WITH REPLACEMENT
  2862.  
  2863.             Pattern matching identifies a subject substring with a particu-
  2864.           lar trait, specified by the pattern.  We used conditional assign-
  2865.           ment to copy that substring to a variable.  Replacement moves in
  2866.           the other direction, letting you alter the substring in the sub-
  2867.           ject.  The space occupied by the matching substring may be en-
  2868.           larged or contracted (or removed entirely), leaving adjacent sub-
  2869.           ject characters undisturbed.  If the pattern matched the entire
  2870.           subject, replacement behaves like a simple assignment statement.
  2871.  
  2872.             Replacement appears in a form similar to assignment:
  2873.  
  2874.                        SUBJECT PATTERN = REPLACEMENT
  2875.  
  2876.             First, the pattern match is attempted on the subject.  If it
  2877.           fails, execution of the statement ends immediately, and replace-
  2878.           ment does not occur.  If the match succeeds, any conditional
  2879.           assignments within the pattern are performed.  The replacement
  2880.           field is then evaluated, converted to a string, and inserted in
  2881.           the subject in place of the matching substring.  If the replace-
  2882.  
  2883.  
  2884.  
  2885.        Tutorial                        - 42 -                Pattern Matching
  2886.  
  2887.  
  2888.  
  2889.  
  2890.  
  2891.           ment field is empty, the null string replaces the matched sub-
  2892.           string, effectively deleting it.  Try a few examples with
  2893.           CODE.SNO:
  2894.  
  2895.                ?       T = 'MUCH ADO ABOUT NOTHING'
  2896.                ?       T 'ADO' = 'FUSS'
  2897.                Success
  2898.                ?       OUTPUT = T
  2899.                MUCH FUSS ABOUT NOTHING
  2900.                ?       T 'NOTHING' =
  2901.                Success
  2902.                ?       OUTPUT = T
  2903.                MUCH FUSS ABOUT
  2904.                ?       'MASH' 'M' = 'B'
  2905.                Execution error #8, Variable not present where required
  2906.                Failure
  2907.  
  2908.             The first replacement searches for 'ADO' in the subject string,
  2909.           replacing it with 'FUSS'.  The second replacement has a null
  2910.           string replacement value, and deletes the matching substring.
  2911.           The last example demonstrates that a variable must be the subject
  2912.           of replacement.  Variables can be changed; string literals---like
  2913.           'MASH'---cannot.
  2914.  
  2915.             The following will replace the 'M' in 'MASH' with a 'B':
  2916.  
  2917.                ?       VERB = 'MASH'
  2918.                ?       VERB 'M' = 'B'
  2919.                ?       OUTPUT = VERB
  2920.                BASH
  2921.  
  2922.             If the matched substring appears more than once in the subject,
  2923.           only the first occurrence is changed.  The remaining substrings
  2924.           must be found with a program loop.  For example, a statement to
  2925.           eliminate all occurrences of the letter 'A' from the subject
  2926.           looks like this:
  2927.  
  2928.                ALOOP   SUBJECT 'A' =                   :S(ALOOP)
  2929.  
  2930.             Here ALOOP is the statement label, SUBJECT is some variable
  2931.           containing the subject string, 'A' is the pattern, and the
  2932.           replacement field is empty.  If an 'A' is found, it is deleted by
  2933.           replacing it with the null string, and the statement succeeds.
  2934.           The success GOTO branches back to ALOOP, and another search for
  2935.           'A' is performed.  The loop continues until no 'A's remain in the
  2936.           subject, and the pattern match fails.  Of course, the pattern and
  2937.           replacement can be as complex as desired.
  2938.  
  2939.             Simple loops like this can be tried in CODE.SNO by appending a
  2940.           semicolon after the GOTO field.  (Semicolon is used with GOTO in
  2941.           CODE.SNO only; you would not use it in normal programs.)  Contin-
  2942.           uing with the previous example:
  2943.  
  2944.  
  2945.  
  2946.  
  2947.  
  2948.        Tutorial                        - 43 -                Pattern Matching
  2949.  
  2950.  
  2951.  
  2952.  
  2953.  
  2954.                ?       VOWEL = ANY('AEIOU')
  2955.                ?VL     T VOWEL = '*'                   :S(VL);
  2956.                ?       OUTPUT = T
  2957.                M*CH F*SS *B**T
  2958.  
  2959.             Since conditional assignment is performed before replacement,
  2960.           its results are available for use in the replacement field of the
  2961.           same statement.  Here's an example of removing the first item
  2962.           from a list, and placing it on the end:
  2963.  
  2964.                ?       RB = 'RED,ORANGE,YELLOW,GREEN,BLUE,INDIGO,VIOLET,'
  2965.                ?       CYCLE = BREAK(',') . ITEM LEN(1) REM . REST
  2966.                ?       RB CYCLE = REST ITEM ','
  2967.                Success
  2968.                ?       OUTPUT = ITEM
  2969.                RED
  2970.                ?       OUTPUT = RB
  2971.                ORANGE,YELLOW,GREEN,BLUE,INDIGO,VIOLET,RED,
  2972.  
  2973.             Pattern CYCLE matches the entire subject, placing the first
  2974.           color into ITEM, bypassing the comma with LEN(1), and placing the
  2975.           remainder of the subject into REST.  REST and ITEM are then
  2976.           transposed in the replacement field, and stored back into RB.
  2977.  
  2978.  
  2979.                                 6.10 SAMPLE PROGRAMS
  2980.  
  2981.             I've introduced a lot of concepts in this chapter; it's time to
  2982.           see how they fit together into programs.  They're supplied on the
  2983.           Vanilla SNOBOL4 diskette.
  2984.  
  2985.  
  2986.           6.10.1 Word Counting
  2987.  
  2988.             The first program counts the number of words in the input file.
  2989.           Lines with an asterisk in the first column are comment lines---
  2990.           their contents are ignored by SNOBOL4.
  2991.  
  2992.  
  2993.  
  2994.  
  2995.  
  2996.  
  2997.  
  2998.  
  2999.  
  3000.  
  3001.  
  3002.  
  3003.  
  3004.  
  3005.  
  3006.  
  3007.  
  3008.  
  3009.  
  3010.  
  3011.        Tutorial                        - 44 -                Pattern Matching
  3012.  
  3013.  
  3014.  
  3015.  
  3016.  
  3017.                *   Simple word counting program, WORDS.SNO.
  3018.                *
  3019.                *   A word is defined to be a contiguous run of letters,
  3020.                *   digits, apostrophe and hyphen.  This definition of
  3021.                *   legal letters in a word can be altered for specialized
  3022.                *   text.
  3023.                *
  3024.                *   If the file to be counted is TEXT.IN, run this program
  3025.                *   by typing:
  3026.                *       B>SNOBOL4 WORDS /I=TEXT
  3027.                *
  3028.                        &TRIM  =  1
  3029.                        WORD   =  "'-"  '0123456789' &UCASE &LCASE
  3030.                        WPAT   =  BREAK(WORD) SPAN(WORD)
  3031.                
  3032.                NEXTL   LINE   =  INPUT                      :F(DONE)
  3033.                NEXTW   LINE WPAT =                          :F(NEXTL)
  3034.                        N      =  N + 1                      :(NEXTW)
  3035.                
  3036.                DONE    OUTPUT =  +N ' words'
  3037.                END
  3038.  
  3039.             After defining the acceptable characters in a word, the real
  3040.           work of the program is performed in the three lines beginning
  3041.           with label NEXTL.  A line is read from the input file, and stored
  3042.           in variable LINE.  The next statement attempts to find the next
  3043.           word with pattern WPAT.  BREAK streams by any blanks and punctua-
  3044.           tion, stopping just short of the word, which SPAN then matches.
  3045.           Both the word and any preceding punctuation are removed from LINE
  3046.           by replacement with the null string.
  3047.  
  3048.             When no more words remain in LINE, the failure transfer to
  3049.           NEXTL reads the next line.  If the match succeeds, N is incre-
  3050.           mented, and the program goes back to NEXTW to search for another
  3051.           word.  When the End-of-File is encountered, control transfers to
  3052.           DONE and the number of words is displayed.
  3053.  
  3054.             It's simple to alter pattern WPAT to search for other things.
  3055.           For instance, if we wanted to count occurrences of double vowels,
  3056.           we could use:
  3057.  
  3058.                        WPAT = ANY('AEIOUaeiou') ANY('AEIOUaeiou')
  3059.  
  3060.             To count the occurrences of integers with an optional sign
  3061.           character, use:
  3062.  
  3063.                        WPAT = (ANY('+-') | '') SPAN('0123456789')
  3064.  
  3065.             Perhaps we want to count violations of simple punctuation
  3066.           rules: period with only one blank, or comma and semicolon fol-
  3067.           lowed by more than one blank:
  3068.  
  3069.                        WPAT = '. ' NOTANY(' ') | ANY(',;') ' ' SPAN(' ')
  3070.  
  3071.  
  3072.  
  3073.  
  3074.        Tutorial                        - 45 -                Pattern Matching
  3075.  
  3076.  
  3077.  
  3078.  
  3079.  
  3080.             Notice how closely WPAT parallels the English language descrip-
  3081.           tion of the problem.
  3082.  
  3083.  
  3084.           6.10.2 Word Crossing
  3085.  
  3086.             This program asks for two words, and displays all intersecting
  3087.           letters between them.  For example, given the words LOOM and
  3088.           HOME, the program output is:
  3089.  
  3090.                        H
  3091.                       LOOM
  3092.                        M
  3093.                        E
  3094.                
  3095.                         H
  3096.                       LOOM
  3097.                         M
  3098.                         E
  3099.                
  3100.                          H
  3101.                          O
  3102.                       LOOM
  3103.                          E
  3104.  
  3105.             A pattern match like this would find the first intersecting
  3106.           character:
  3107.  
  3108.                        HORIZONTAL ANY(VERTICAL) . CHAR
  3109.  
  3110.             However, we want to find all intersections, so will have to
  3111.           iterate our search.  In conventional programming languages, we
  3112.           might use numerical indices to remember which combinations were
  3113.           tried.  Here, we'll use place-holding characters like '*' and '#'
  3114.           to remove solutions from future consideration.  As seems to be
  3115.           the case with SNOBOL4, there are more comments than program
  3116.           statements:
  3117.  
  3118.  
  3119.  
  3120.  
  3121.  
  3122.  
  3123.  
  3124.  
  3125.  
  3126.  
  3127.  
  3128.  
  3129.  
  3130.  
  3131.  
  3132.  
  3133.  
  3134.  
  3135.  
  3136.  
  3137.        Tutorial                        - 46 -                Pattern Matching
  3138.  
  3139.  
  3140.  
  3141.  
  3142.  
  3143.                * CROSS.SNO - Print all intersections between two words
  3144.                
  3145.                        &TRIM = 1
  3146.                
  3147.                *  Get words from user
  3148.                *
  3149.                AGAIN   OUTPUT = 'ENTER HORIZONTAL WORD:'
  3150.                        H      = INPUT                       :F(END)
  3151.                
  3152.                        OUTPUT = 'ENTER VERTICAL WORD:'
  3153.                        V      = INPUT                       :F(END)
  3154.                
  3155.                *       Make copy of horizontal word to track position.
  3156.                        HC     = H
  3157.                
  3158.                *  Find next intersection in horizontal word.  Save
  3159.                *  the number of preceding horizontal characters in NH.
  3160.                *  Save the intersecting character in CROSS.
  3161.                *  Replace with '*' to remove from further consideration.
  3162.                *  Go to AGAIN to get new words if horizontal exhausted.
  3163.                *
  3164.                NEXTH   HC @NH ANY(V) . CROSS = '*'          :F(AGAIN)
  3165.                
  3166.                *  For each horizontal hit, iterate over possible
  3167.                *  vertical ones.  Make copy of vertical word to track
  3168.                *  vertical position.
  3169.                *
  3170.                        VC     = V
  3171.                
  3172.                *  Find where the intersection was in the vertical word.
  3173.                *  Save the number of preceding vertical characters in NV.
  3174.                *  Replace with '#' to prevent finding it again in that
  3175.                *  position.  When vertical exhausted, try horizontal again.
  3176.                *
  3177.                NEXTV   VC @NV CROSS = '#'                   :F(NEXTH)
  3178.                
  3179.                *  Now display this particular intersection.
  3180.                *  We make a copy of the original vertical word,
  3181.                *  and mark the intersecting position with '#'.
  3182.                *
  3183.                        OUTPUT =
  3184.                        PRINTV = V
  3185.                        PRINTV POS(NV) LEN(1) = '#'
  3186.                
  3187.                *  Peel off the vertical characters one-by-one.  Each will
  3188.                *  be displayed with NH leading blanks to get it in the
  3189.                *  correct column.  When the '#' is found, display the full
  3190.                *  horizontal word instead.
  3191.                *  When done, go to NEXTV to try another vertical position.
  3192.                *
  3193.                PRINT   PRINTV LEN(1) . C =                   :F(NEXTV)
  3194.                        OUTPUT = DIFFER(C,'#') DUPL(' ',NH) C :S(PRINT)
  3195.                        OUTPUT = H                            :(PRINT)
  3196.                END
  3197.  
  3198.  
  3199.  
  3200.        Tutorial                        - 47 -                Pattern Matching
  3201.  
  3202.  
  3203.  
  3204.  
  3205.  
  3206.                         6.11 ANCHORED AND UNANCHORED MATCHING
  3207.  
  3208.             Most of the examples above match substrings which do not begin
  3209.           at the first subject character.  This is the "unanchored" mode of
  3210.           pattern matching.  Alternately, we can "anchor" the pattern match
  3211.           by requiring it to include the first subject character.  Setting
  3212.           keyword &ANCHOR to a nonzero value produces anchored matching.
  3213.           Anchored matching is usually faster than unanchored, because many
  3214.           futile attempts to match are eliminated.
  3215.  
  3216.             Even when the desired item is not at the beginning of the sub-
  3217.           ject, it is often possible to simulate anchored matching by pre-
  3218.           fixing the pattern with a subpattern which will stream out to the
  3219.           desired object.  The stream function spans the gap from the first
  3220.           subject character to the desired item.  Use CODE.SNO to experi-
  3221.           ment with &ANCHOR:
  3222.  
  3223.                ?       DIGITS = '0123456789'
  3224.                ?       &ANCHOR = 1
  3225.                ?       'THE NEXT 43 DAYS' BREAK(DIGITS) SPAN(DIGITS) . N
  3226.  
  3227.             This will assign substring '43' to N, even in anchored mode.
  3228.           In unanchored mode, the test lines:
  3229.  
  3230.                ?       &ANCHOR = 0
  3231.                ?       'THE NEXT 43 DAYS' SPAN(DIGITS) . N
  3232.  
  3233.           would ultimately succeed, but only after SPAN failed on each of
  3234.           the characters preceding the '4'.  The efficiency difference is
  3235.           more pronounced if the subject does not contain any digits.  In
  3236.           the first formulation, BREAK(DIGITS) fails and the anchored match
  3237.           then fails immediately.  The second construction fails only after
  3238.           SPAN is tried at each subject character position.
  3239.  
  3240.             When your program first begins execution, SNOBOL4 sets keyword
  3241.           &ANCHOR to zero, the unanchored mode.  If you can construct all
  3242.           your patterns as anchored patterns, you should set &ANCHOR
  3243.           nonzero for anchored matching.  Setting and resetting &ANCHOR
  3244.           throughout your program is error prone and not advised.  Another
  3245.           alternative is to leave &ANCHOR set to 0, but to 'pseudo-anchor'
  3246.           patterns by using POS(0) as the first pattern element.
  3247.  
  3248.             It always takes less time for a pattern to succeed than to
  3249.           fail.  Failure implies an exhaustive search of all combinations,
  3250.           whereas success stops the pattern match early.  You should try to
  3251.           construct patterns with direct routes to success, such as the use
  3252.           of BREAK above.  Wherever possible, impose restrictions on the
  3253.           number of alternatives to be tried.  Combinatorial explosion is
  3254.           the price of loose pattern programming.
  3255.  
  3256.  
  3257.  
  3258.  
  3259.  
  3260.  
  3261.  
  3262.  
  3263.        Tutorial                        - 48 -                Pattern Matching
  3264.  
  3265.  
  3266.  
  3267.  
  3268.  
  3269.                                                                   Chapter 7
  3270.  
  3271.  
  3272.                                         ADDITIONAL OPERATORS AND DATA TYPES
  3273.           -----------------------------------------------------------------
  3274.  
  3275.             In this chapter we will explore some additional SNOBOL4 opera-
  3276.           tors and data types.  Many of these concepts are entirely absent
  3277.           from other programming languages.  Far from being esoteric, they
  3278.           fit quite naturally into SNOBOL4, and add to its conciseness and
  3279.           power of expression.  In the following examples, we will continue
  3280.           to use the CODE.SNO program to illustrate each new idea.
  3281.  
  3282.  
  3283.                                7.1 INDIRECT REFERENCE
  3284.  
  3285.             In conventional programming languages, a variable's name may be
  3286.           specified only at the time the program is written.  In fact, once
  3287.           the run-time storage has been allocated, the textual form of the
  3288.           name can be discarded.  This is not the case in SNOBOL4; you can
  3289.           create new variables during execution, and reference existing
  3290.           ones from names specified in character strings.
  3291.  
  3292.             The unary operator dollar sign ($) is the "indirect reference
  3293.           operator."  By applying it to a variable you instruct SNOBOL4 to
  3294.           use its contents as the name of another variable, and to continue
  3295.           on to reference that variable.  SNOBOL4 "goes through" the oper-
  3296.           and to reach the variable.  Try the following simple example:
  3297.  
  3298.                ?       DOG = 'BARK'
  3299.                ?       CAT = 'MEOW'
  3300.                ?       ANIMAL = 'CAT'
  3301.                ?       OUTPUT = $ANIMAL
  3302.                MEOW
  3303.                ?       ANIMAL = 'DOG'
  3304.                ?       OUTPUT = $ANIMAL
  3305.                BARK
  3306.  
  3307.             These statements make their indirect reference through the
  3308.           string contained in variable ANIMAL.  ANIMAL's contents are
  3309.           treated as a "pointer" to the final destination.  That is, using
  3310.           ANIMAL by itself retrieves the string 'DOG', while $ANIMAL refers
  3311.           to the variable DOG.
  3312.  
  3313.             New variables may also be created by using an indirect refer-
  3314.           ence as the object of an assignment.  Here, $DOG causes variable
  3315.           BARK to be created, and assigned the string 'RUFF':
  3316.  
  3317.                ?       $DOG = 'RUFF'
  3318.                ?       OUTPUT = BARK
  3319.                RUFF
  3320.  
  3321.             Indirect referencing may proceed to any depth, provided the
  3322.           null string is never encountered as a variable name:
  3323.  
  3324.  
  3325.  
  3326.        Tutorial                        - 49 -        Operators and Data Types
  3327.  
  3328.  
  3329.  
  3330.  
  3331.  
  3332.                ?       OUTPUT = $ANIMAL '-' $$ANIMAL
  3333.                BARK-RUFF
  3334.                ?       OUTPUT = $RUFF
  3335.                Execution error #4, Null string in illegal context
  3336.  
  3337.             In the first example, $ANIMAL produces the contents of variable
  3338.           DOG, while $$ANIMAL refers to the variable BARK.  The second ex-
  3339.           ample attempts to go through RUFF---which was not previously de-
  3340.           fined---and obtains the null string.  Of course, the null string
  3341.           is not a valid variable name.
  3342.  
  3343.  
  3344.           7.1.1 Associative Programming
  3345.  
  3346.             Indirect referencing provides a means of "programming by asso-
  3347.           ciation."  Suppose we want to write a program that allows the
  3348.           user to enter a state name and receive the state's capital in
  3349.           response.  We've provided a data file called CAPITAL.DAT, in
  3350.           which each line contains a state name, comma, and the capital.
  3351.           The first part of the program will read the file and set up an
  3352.           associative data base:
  3353.  
  3354.                *  Trim input, attach data file to variable INFILE
  3355.                        &TRIM = 1
  3356.                        INPUT('INFILE', 1, , 'CAPITAL.DAT')       :F(ERR)
  3357.                
  3358.                *  Read a line from file.  Start querying upon EOF
  3359.                READF   LINE = INFILE                             :F(QUERY)
  3360.                
  3361.                *  Break out state and capital from line
  3362.                        LINE BREAK(',') . STATE LEN(1) REM . CAPITAL :F(ERR)
  3363.                
  3364.                *  Convert state name into a variable, and assign the
  3365.                *  capital city string to it.  Then read next line.
  3366.                        $STATE = CAPITAL                          :(READF)
  3367.                
  3368.                ERR     OUTPUT = 'Illegal data file'              :(END)
  3369.                QUERY    . . .
  3370.  
  3371.             We attach the file, and associate variable INFILE with it.
  3372.           Successive file lines are read into variable LINE.  Pattern
  3373.           matching assigns the state name and capital city to variables
  3374.           STATE and CAPITAL respectively.  We use an indirect reference
  3375.           through $STATE to create a new variable with the state's name,
  3376.           and assign the capital city to it.  For example, the file line
  3377.           'COLORADO,DENVER' creates variable COLORADO, containing 'DENVER'.
  3378.  
  3379.             Having established a data base, completing the program to ac-
  3380.           cess it is trivial:
  3381.  
  3382.                *  Read state name, access it as a variable
  3383.                QUERY   OUTPUT = $INPUT                           :S(QUERY)
  3384.                END
  3385.  
  3386.  
  3387.  
  3388.  
  3389.        Tutorial                        - 50 -        Operators and Data Types
  3390.  
  3391.  
  3392.  
  3393.  
  3394.  
  3395.             An input line is read from the user, and used for an indirect
  3396.           reference.  If the user types a state name, treating it as a
  3397.           variable name obtains the state capital.  An invalid state name
  3398.           would reference a new variable, whose value is the null string,
  3399.           and a blank line would be output.  A more complete program might
  3400.           test for this null string and produce an error message.
  3401.  
  3402.             The addition of one statement to the program loop creating the
  3403.           data base allows us to enter either the state name or capital
  3404.           city, and obtain the other:
  3405.  
  3406.                        $STATE = CAPITAL
  3407.                        $CAPITAL = STATE                          :(READF)
  3408.  
  3409.             How would we solve this problem in a language like BASIC?
  3410.           States and capitals could be stored in an array.  We would then
  3411.           use a loop to sequentially compare the user's input string with
  3412.           the array elements.  If a match were found, the result would be
  3413.           displayed from another array element.  In SNOBOL4, we did it all
  3414.           with one statement: OUTPUT = $INPUT.  Associative programming can
  3415.           often replace a conventional linear search.
  3416.  
  3417.  
  3418.           7.1.2 Variable Names
  3419.  
  3420.             Earlier I said that variable names were composed of letters,
  3421.           digits, and the characters period and underscore.  These restric-
  3422.           tions apply only to variables which appear in program text.  Var-
  3423.           iable names created or referenced with the indirect reference
  3424.           operator may be composed of ANY nonnull string of characters, and
  3425.           may be as long as any other string.  If we set keyword &DUMP
  3426.           nonzero, we would see a list of states and capitals when the
  3427.           program terminated.  The variable names created by $STATE are in
  3428.           the left column, and their string contents in the right column:
  3429.  
  3430.                ALABAMA = 'MONTGOMERY'
  3431.                ALASKA = 'JUNEAU'
  3432.                      . . .
  3433.                NEW HAMPSHIRE = 'CONCORD'
  3434.                      . . .
  3435.  
  3436.             The dump reveals a variable named NEW HAMPSHIRE, which contains
  3437.           a "blank" within its name.  Clearly, you cannot directly say:
  3438.  
  3439.                        NEW HAMPSHIRE = 'CONCORD'
  3440.  
  3441.           since SNOBOL4 sees this as a pattern match statement: variable
  3442.           NEW is the subject, and variable HAMPSHIRE contains the pattern.
  3443.           To reference this variable, we must use:
  3444.  
  3445.                        $'NEW HAMPSHIRE' = 'CONCORD'
  3446.  
  3447.             Try CODE.SNO with some unconventional variable names:
  3448.  
  3449.  
  3450.  
  3451.  
  3452.        Tutorial                        - 51 -        Operators and Data Types
  3453.  
  3454.  
  3455.  
  3456.  
  3457.  
  3458.                ?       $'"' = 'DOUBLE QUOTE'
  3459.                ?       $'$#@!*' = 53
  3460.                ?       OUTPUT = $'$#@!*' $'"'
  3461.                53DOUBLEQUOTE
  3462.  
  3463.  
  3464.           7.1.3 Indirect GOTOs
  3465.  
  3466.             Indirect referencing is not restricted to the main body of a
  3467.           statement.  It may be used in the GOTO field to transfer control
  3468.           to a label specified by a variable.  Suppose variable OP held the
  3469.           one-character string '+', '-', '*', or '/'.  This GOTO would
  3470.           transfer to one of four statements, labeled L+, L-, L*, or L/:
  3471.  
  3472.                        statement                            :($('L' OP))
  3473.                L+      statement
  3474.                L-      statement
  3475.                         . . .
  3476.  
  3477.             The string in OP is appended to string 'L', and the result is
  3478.           used with an indirect reference to obtain the final label name.
  3479.  
  3480.             Indirect referencing in the GOTO field is a more powerful ver-
  3481.           sion of the computed GOTO which appears in some languages.  It
  3482.           allows a program to quickly perform a multiway control branch
  3483.           based on an item of data.  Of course, the computed label name
  3484.           must be defined in the program.  SNOBOL4 provides an error mes-
  3485.           sage if your program transfers to an undefined label.
  3486.  
  3487.             Indirect referencing may not be used in a statement's label
  3488.           field.  Dynamically changing the name of a statement during exe-
  3489.           cution is excessive even by SNOBOL4 standards.
  3490.  
  3491.  
  3492.                              7.2 UNEVALUATED EXPRESSIONS
  3493.  
  3494.             The pattern data type appears when a pattern structure is
  3495.           stored in a variable for subsequent use in a pattern match.  For
  3496.           example, a pattern to capture the next N characters after a
  3497.           colon, and store them in variable ITEM could be written as:
  3498.  
  3499.                        NPAT = ':' LEN(N) . ITEM
  3500.  
  3501.             Notice that a definition such as this is static.  NPAT captures
  3502.           the value of variable N at the time of pattern construction.  If
  3503.           we subsequently alter N in the program, NPAT retains N's original
  3504.           value.  One way to use the current value of N is to explicitly
  3505.           specify the pattern each time it is needed:
  3506.  
  3507.                        SUBJECT ':' LEN(N) . ITEM
  3508.  
  3509.             Now the pattern is being constructed anew whenever the state-
  3510.           ment is executed.  But reconstructing a pattern whenever it is
  3511.           used is inefficient, so a one-time definition is preferable.
  3512.  
  3513.  
  3514.  
  3515.        Tutorial                        - 52 -        Operators and Data Types
  3516.  
  3517.  
  3518.  
  3519.  
  3520.  
  3521.             The "unevaluated expression" operator allows us to obtain the
  3522.           efficiency of the NPAT formulation, yet use the current value of
  3523.           N when NPAT is referenced.  It is a unary operator, whose graphic
  3524.           symbol is the asterisk (*).  Now we would specify NPAT like this:
  3525.  
  3526.                        NPAT = ':' LEN(*N) . ITEM
  3527.  
  3528.             The pattern is only constructed once, and assigned to NPAT.
  3529.           The current value of N is ignored at this time.  Later, when NPAT
  3530.           is used in a pattern match, the unevaluated expression operator
  3531.           tells SNOBOL4 to fetch the current value of N.
  3532.  
  3533.             The unevaluated expression operator may be used with the argu-
  3534.           ment of the pattern functions ANY, BREAK, LEN, NOTANY, POS, RPOS,
  3535.           RTAB, SPAN, or TAB.  It may also be applied to an alternate or
  3536.           subsequent clause or to an entire pattern.  Here's an example:
  3537.  
  3538.                ?       PAT = TAB(*I) . OUTPUT SPAN(*S) . OUTPUT
  3539.                ?       SUB = '123AABBCC'
  3540.                ?       I = 4
  3541.                ?       S = 'AB'
  3542.                ?       SUB PAT
  3543.                123A
  3544.                ABB
  3545.                ?       I = 3
  3546.                ?       SUB PAT
  3547.                123
  3548.                AABB
  3549.  
  3550.             It's worth noting that I and S were undefined when PAT was
  3551.           first constructed.  Later, we will apply this technique to con-
  3552.           struct recursive patterns.
  3553.  
  3554.  
  3555.                               7.3 IMMEDIATE ASSIGNMENT
  3556.  
  3557.             Our examples have made extensive use of the conditional assign-
  3558.           ment operator to capture matched substrings after a successful
  3559.           pattern match.  The "immediate assignment" operator allows us to
  3560.           capture intermediate results during the pattern match.
  3561.  
  3562.             Immediate assignment occurs whenever a subpattern matches, even
  3563.           if the entire pattern match ultimately fails.  Immediate assign-
  3564.           ment is a binary operator whose graphic symbol is the dollar sign
  3565.           ($).  Like conditional assignment, the matching substring on its
  3566.           left is assigned to the variable on its right.  Here are examples
  3567.           with CODE.SNO where we use variable OUTPUT to reveal the work of
  3568.           the pattern matcher:
  3569.  
  3570.  
  3571.  
  3572.  
  3573.  
  3574.  
  3575.  
  3576.  
  3577.  
  3578.        Tutorial                        - 53 -        Operators and Data Types
  3579.  
  3580.  
  3581.  
  3582.  
  3583.  
  3584.                ?       S = 'ABCDEFG'
  3585.                ?       S 'A' ARB $ OUTPUT 'E'
  3586.                
  3587.                B
  3588.                BC
  3589.                BCD
  3590.                Success
  3591.                ?       S ('B' LEN(2) | 'C' LEN(3)) $ OUTPUT 'G'
  3592.                BCD
  3593.                CDEF
  3594.                Success
  3595.                ?
  3596.  
  3597.  
  3598.           7.3.1 Immediate Assignment and Unevaluated Expressions
  3599.  
  3600.             As useful as immediate assignment is for revealing the inner
  3601.           workings of a pattern match, a more powerful use is possible.  It
  3602.           can be used with the unevaluated expression operator to develop a
  3603.           new class of patterns.  An interesting substring at the beginning
  3604.           of the subject is immediately assigned to a variable, and the
  3605.           variable is then subsequently used in the very same pattern.
  3606.  
  3607.             Suppose a number at the beginning of the subject specifies the
  3608.           length of a variable width field that follows.  We would like to
  3609.           capture the number into variable N, then use it with the LEN
  3610.           function to transfer the data into variable FIELD.  When used
  3611.           with LEN, N must be preceded by the unevaluated expression opera-
  3612.           tor, so that its new value is retrieved.  For instance:
  3613.  
  3614.                ?       FPAT = SPAN('0123456789') $ N LEN(*N) . FIELD
  3615.                ?       '12ABCDEFGHIJKLMNOPQ' FPAT
  3616.                Success
  3617.                ?       OUTPUT = FIELD
  3618.                ABCDEFGHIJKL
  3619.  
  3620.             SPAN matched the field length, 12, and immediately assigned it
  3621.           to N.  LEN(*N) then matched the next 12 characters.  Another sub-
  3622.           ject, with a different field length, would update N appropri-
  3623.           ately.  Type conversion was working quietly behind the scenes
  3624.           here:  N was assigned the string '12', yet it appeared as integer
  3625.           12 to the LEN function.
  3626.  
  3627.             Now here is an example which provides a glimpse of just how
  3628.           powerful SNOBOL4's pattern matching can be.  Problem:  Examine a
  3629.           subject for an arbitrary three-character substring which appears
  3630.           twice in a row, or bracketed in parentheses.  Solution:
  3631.  
  3632.  
  3633.  
  3634.  
  3635.  
  3636.  
  3637.  
  3638.  
  3639.  
  3640.  
  3641.        Tutorial                        - 54 -        Operators and Data Types
  3642.  
  3643.  
  3644.  
  3645.  
  3646.  
  3647.                ?       TWOPAT = LEN(3) $ X . OUTPUT *(X | "(" X ")")
  3648.                ?       'ABCDECDEFGH' TWOPAT
  3649.                CDE
  3650.                Success
  3651.                ?       'ABCDE(CDE)BA' TWOPAT
  3652.                CDE
  3653.                Success
  3654.  
  3655.             As you experiment with these types of patterns, you may dis-
  3656.           cover some which fail when they should succeed.  The problem is
  3657.           that SNOBOL4 stops matching when it believes further match at-
  3658.           tempts would be futile.  These "heuristics" are normally invisi-
  3659.           ble, and speed program execution.  At this time, we'll defer dis-
  3660.           cussing heuristics, and simply mention that they can be disabled
  3661.           with the statement:
  3662.  
  3663.                        &FULLSCAN = 1
  3664.  
  3665.             Let's take a break from pattern matching, and examine some
  3666.           other SNOBOL4 data types.
  3667.  
  3668.  
  3669.                                      7.4 ARRAYS
  3670.  
  3671.  
  3672.           7.4.1 Array Concepts
  3673.  
  3674.             Arrays in SNOBOL4 are similar to arrays in other programming
  3675.           languages.  They allow a single variable name to specify more
  3676.           than one data element; integer subscripts distinguish the indi-
  3677.           vidual members of an array.  Each array element may contain any
  3678.           data type, independent of the types in other array elements.
  3679.  
  3680.             A one-dimensional array is a "vector;" it is simply a list of I
  3681.           items.  A two-dimensional array is a "grid" composed of several
  3682.           adjacent vectors---an I by J array has I rows and J columns.  A
  3683.           three-dimensional array, I by J by K in size, is a rectangular
  3684.           solid consisting of K adjacent grids.  There's no limit to the
  3685.           number of dimensions allowed, but such arrays become increasingly
  3686.           difficult to visualize.
  3687.  
  3688.             In keeping with SNOBOL4's pliability, an array is defined dur-
  3689.           ing program execution, rather than at compilation time.  Its size
  3690.           and shape is specified by a string.  The definition of an array
  3691.           may be changed at any time, or the array may be deleted and its
  3692.           memory reused when it is no longer needed.
  3693.  
  3694.  
  3695.           7.4.2 Array Creation
  3696.  
  3697.             Arrays are created by the SNOBOL4 function ARRAY.  A program
  3698.           calls this function with a "prototype string" which specifies the
  3699.           number of dimensions and their sizes.  The function returns an
  3700.           "array pointer," which is stored in a variable; the array ele-
  3701.  
  3702.  
  3703.  
  3704.        Tutorial                        - 55 -        Operators and Data Types
  3705.  
  3706.  
  3707.  
  3708.  
  3709.  
  3710.           ments are referenced by applying subscripts to this variable.
  3711.           Here are two statements for use with CODE.SNO.  They create one-
  3712.           and two-dimensional arrays named LIST and BOX respectively:
  3713.  
  3714.                ?       LIST = ARRAY('25')
  3715.                ?       BOX = ARRAY('12,3')
  3716.  
  3717.             LIST points to a vector of 25 elements.  BOX points to a grid,
  3718.           12 rows high and 3 columns wide, containing 36 elements.  The
  3719.           ARRAY function initializes all array elements to the null string.
  3720.  
  3721.  
  3722.           7.4.3 Array Referencing
  3723.  
  3724.             Array subscripts are integer valued, and are specified by angu-
  3725.           lar or square brackets (<> or []).  Subscript values range from 1
  3726.           to the size of each dimension.  If you attempt to use a subscript
  3727.           outside this range, the array reference will fail, and the fail-
  3728.           ure may be detected in the GOTO portion of the statement.  Try
  3729.           some array references with CODE.SNO:
  3730.  
  3731.                ?       LIST<3> = 'MAPLE'
  3732.                ?       BOX[10,2] = 3
  3733.                ?       LIST[33] = 4
  3734.                Failure
  3735.                ?       OUTPUT = LIST[3] LIST[4] BOX<10,2>
  3736.                MAPLE3
  3737.  
  3738.             Angular and square brackets are interchangeable.  The reference
  3739.           to LIST[33] failed because the largest subscript allowed for that
  3740.           array is 25.  LIST[4] produced its initialized value, the null
  3741.           string, and had no effect on the concatenation.  The array
  3742.           pointer in LIST can be assigned to another variable:
  3743.  
  3744.                ?       B = LIST
  3745.                ?       OUTPUT = B[3]
  3746.                MAPLE
  3747.                ?       B<3> = 'WILLOW'
  3748.                ?       OUTPUT = LIST<3>
  3749.                WILLOW
  3750.  
  3751.             Assigning the pointer in LIST to B made both variables point to
  3752.           the same array.  Since there's but one actual array, array refer-
  3753.           ences made using LIST or B are equivalent.  The COPY function
  3754.           (Chapter 19) creates a duplicate copy of an entire array.
  3755.  
  3756.             Array elements may be used anywhere a variable name is
  3757.           allowed---expressions, patterns, function arguments, etc.  The
  3758.           fact that an array reference fails if a subscript is out-of-
  3759.           bounds can be used in a simple and natural way when scanning an
  3760.           array.  Rather than having to know an array's size, we simply
  3761.           loop until an array reference fails.  A program segment to dis-
  3762.           play the members of an array SCORE might look like this:
  3763.  
  3764.  
  3765.  
  3766.  
  3767.        Tutorial                        - 56 -        Operators and Data Types
  3768.  
  3769.  
  3770.  
  3771.  
  3772.  
  3773.                        I = 0
  3774.                PRINT   I = I + 1
  3775.                        OUTPUT = SCORE[I]                    :S(PRINT)
  3776.                         . . .
  3777.  
  3778.  
  3779.           7.4.4 Array Initialization
  3780.  
  3781.             Arrays may be created with an initial value other than the null
  3782.           string.  ARRAY accepts a second argument which specifies this
  3783.           initial value.  We can create a three-dimensional array with all
  3784.           elements initialized to the string 'PA-18' as follows:
  3785.  
  3786.                ?       A = ARRAY('2,3,4','PA-18')
  3787.                ?       OUTPUT = A[1,2,3]
  3788.                PA-18
  3789.  
  3790.  
  3791.           7.4.5 Other Array Bounds
  3792.  
  3793.             Ordinarily, subscripts range from 1 to the size of each dimen-
  3794.           sion.  However, if you find it more convenient, other subscript
  3795.           ranges may be used.  The prototype string for ARRAY's first
  3796.           argument has the general form:
  3797.  
  3798.                        'L1:H1,L2:H2,...,Ln:Hn'
  3799.  
  3800.             The L's and H's are integers specifying the lower and upper
  3801.           bounds of each dimension.  If the lower bound and colon are
  3802.           omitted from any dimension, the integer 1 is assumed.  Here is a
  3803.           five element vector, with allowed subscripts -2, -1, 0, 1 and 2:
  3804.  
  3805.                ?       A = ARRAY('-2:2','PIPER')
  3806.                ?       OUTPUT = A[-1]
  3807.                PIPER
  3808.                ?       OUTPUT = A[3]
  3809.                Failure
  3810.  
  3811.             Arrays are a traditional computer programming concept.  Now
  3812.           we'll see how SNOBOL4 takes the idea one important step further,
  3813.           with the concept of tables.
  3814.  
  3815.  
  3816.                                      7.5 TABLES
  3817.  
  3818.  
  3819.           7.5.1 Table Creation and Referencing
  3820.  
  3821.             A "table" is similar to a one-dimensional array, with two
  3822.           important differences.  First, a table's size is not fixed; it
  3823.           extends itself automatically whenever a new element is added to
  3824.           it.  Second, table subscripts are not limited to integers, but
  3825.           may be any SNOBOL4 data type.  Strings and patterns may be used
  3826.           as subscripts.  Tables combine the idea of associative program-
  3827.  
  3828.  
  3829.  
  3830.        Tutorial                        - 57 -        Operators and Data Types
  3831.  
  3832.  
  3833.  
  3834.  
  3835.  
  3836.           ming with the data grouping of arrays.
  3837.  
  3838.             Tables are created by the SNOBOL4 function TABLE.  No arguments
  3839.           are required, since a table's size is not fixed.  The function
  3840.           returns a table pointer, which you store in a variable.  Like
  3841.           arrays, table elements are referenced by applying subscripts to
  3842.           the variable.  Try this example with CODE.SNO:
  3843.  
  3844.                ?       T = TABLE()
  3845.                ?       T['ROSE'] = 'RED'
  3846.                ?       T['N'] = 6
  3847.                ?       OUTPUT = T['N'] T['THE'] T['ROSE']
  3848.                6RED
  3849.                ?       FLOWER = 'ROSE'
  3850.                ?       T[FLOWER] = T[FLOWER] ',THORNS'
  3851.                ?       OUTPUT = T[FLOWER]
  3852.                RED,THORNS
  3853.  
  3854.             Here, strings have been used as table subscripts.  The concept
  3855.           of an "out-of-bounds" subscript does not exist with tables.  The
  3856.           reference to T['THE'] created a new entry, and assigned it the
  3857.           null string.  Unlike arrays, no initial value for new entries may
  3858.           be specified in the call to TABLE; new table entries are always
  3859.           initialized to the null string.
  3860.  
  3861.  
  3862.           7.5.2 Conversion between Tables and Arrays
  3863.  
  3864.             In the above example, we know what values were used as table
  3865.           subscripts.  But if the table were constructed from data in a
  3866.           file, how can we determine what items were placed in the table?
  3867.           We need to know the subscripts to view the table, but the sub-
  3868.           scripts themselves are part of the table.  If this were an array,
  3869.           we could run an integer subscript over the array to see the data.
  3870.           Applying integer subscripts to a table only creates more entries.
  3871.  
  3872.             SNOBOL4 provides a simple solution to this dilemma---a method
  3873.           to convert a table to an array.  An N row by 2 column array can
  3874.           be created from a table.  The first array column contains the
  3875.           subscripts that were used to create the table.  The second column
  3876.           contains the data items stored with the corresponding table sub-
  3877.           script.  N is the number of table entries with nonnull values.
  3878.  
  3879.             Once the table is in array form, integer subscripts can be
  3880.           applied to the array to display the subscripts and their values.
  3881.           A table is converted to an array with the CONVERT function, which
  3882.           accepts a table argument and the word 'ARRAY', and returns a
  3883.           pointer to the new array.  Continuing with the previous example:
  3884.  
  3885.  
  3886.  
  3887.  
  3888.  
  3889.  
  3890.  
  3891.  
  3892.  
  3893.        Tutorial                        - 58 -        Operators and Data Types
  3894.  
  3895.  
  3896.  
  3897.  
  3898.  
  3899.                ?       A = CONVERT(T, 'ARRAY')
  3900.                Success
  3901.                ?       OUTPUT = A[1,1] '-' A[1,2]
  3902.                ROSE-RED,THORNS
  3903.                ?       OUTPUT = A[2,1] '-' A[2,2]
  3904.                N-6
  3905.  
  3906.             As you would expect with SNOBOL4, the inverse operation---con-
  3907.           version of an array to a table---is also possible.  The array
  3908.           must be rectangular, N rows by 2 columns.  The array entries in
  3909.           the first column become the table subscripts.  The array's second
  3910.           column becomes the table entry values:
  3911.  
  3912.                ?       W = CONVERT(A, 'TABLE')
  3913.                Success
  3914.                ?       OUTPUT = W['ROSE']
  3915.                RED,THORNS
  3916.  
  3917.  
  3918.           7.5.3 Counting Word Usage with a Table
  3919.  
  3920.             Tables are useful when we want to record a number of pair asso-
  3921.           ciations, where each half of the pair might have any data type.
  3922.           A classic example of a table's utility is a word usage program.
  3923.           Earlier, we developed a program to count the total number of
  3924.           words in a file.  We will modify that program to count the number
  3925.           of times each unique word appears.  The program begins like this:
  3926.  
  3927.  
  3928.  
  3929.  
  3930.  
  3931.  
  3932.  
  3933.  
  3934.  
  3935.  
  3936.  
  3937.  
  3938.  
  3939.  
  3940.  
  3941.  
  3942.  
  3943.  
  3944.  
  3945.  
  3946.  
  3947.  
  3948.  
  3949.  
  3950.  
  3951.  
  3952.  
  3953.  
  3954.  
  3955.  
  3956.        Tutorial                        - 59 -        Operators and Data Types
  3957.  
  3958.  
  3959.  
  3960.  
  3961.  
  3962.                *       Simple word usage program, WORDU.SNO.
  3963.                *
  3964.                *  A word is defined to be a contiguous run of letters,
  3965.                *  digits, apostrophe and hyphen.  This definition of legal
  3966.                *  letters in a word can be altered for specialized text.
  3967.                *
  3968.                *  If the file to be counted is TEXT.IN, run as follows:
  3969.                *       B>SNOBOL4 WORDU /I=TEXT
  3970.                *
  3971.                        &TRIM  = 1
  3972.                
  3973.                *  Define the characters which comprise a 'word'
  3974.                        WORD   = "'-"  '0123456789' &LCASE
  3975.                
  3976.                *  Pattern to isolate each word as assign it to ITEM:
  3977.                        WPAT   = BREAK(WORD) SPAN(WORD) . ITEM
  3978.                
  3979.                *  Create a table to maintain the word counts
  3980.                        WCOUNT = TABLE()
  3981.                
  3982.                *  Read a line of input and obtain the next word
  3983.                NEXTL   LINE   = REPLACE(INPUT, &UCASE, &LCASE)   :F(DONE)
  3984.                NEXTW   LINE WPAT =                               :F(NEXTL)
  3985.                
  3986.                *  Use word as subscript, update its usage count
  3987.                        WCOUNT<ITEM> = WCOUNT<ITEM> + 1           :(NEXTW)
  3988.                DONE     . . .
  3989.  
  3990.             We'll convert the input to lower case, so words like 'The' and
  3991.           'the' are counted together.  WPAT has been changed to store each
  3992.           word in variable ITEM.  When a word is identified, it is used as
  3993.           a subscript for table WCOUNT.  When ITEM contains a new word, the
  3994.           first reference to WCOUNT<ITEM> creates a new table entry and
  3995.           returns the null string.  Integer 1 is added to the null string,
  3996.           and the result, 1, is stored back into WCOUNT<ITEM>.  If the same
  3997.           word is encountered again, WCOUNT<ITEM> for that word will be
  3998.           incremented to 2.
  3999.  
  4000.             The program reads the input file, building a table with entries
  4001.           for each unique word.  When End-of-File is read, control trans-
  4002.           fers to label DONE, where we display the words and their respec-
  4003.           tive counts.  We convert WCOUNT to an array, and use integer
  4004.           subscripts to retrieve the words and their counts.  Conversion
  4005.           fails if the table is empty.  Continuing with this program:
  4006.  
  4007.  
  4008.  
  4009.  
  4010.  
  4011.  
  4012.  
  4013.  
  4014.  
  4015.  
  4016.  
  4017.  
  4018.  
  4019.        Tutorial                        - 60 -        Operators and Data Types
  4020.  
  4021.  
  4022.  
  4023.  
  4024.  
  4025.                *  Convert table to array.  Fail if table is empty
  4026.                DONE    A = CONVERT(WCOUNT, 'ARRAY')              :F(EMPTY)
  4027.                
  4028.                *  Scan array, printing words and counts
  4029.                        I = 0
  4030.                PRINT   I = I + 1
  4031.                        OUTPUT = A<I,1> '--' A<I,2>     :S(PRINT) F(END)
  4032.                
  4033.                EMPTY   OUTPUT = 'No words'
  4034.                END
  4035.  
  4036.             The table subscripts were the file's words, and have been
  4037.           placed in the first column of the array, A<I,1>.  The count for
  4038.           each word was the table entry, now in the second column, A<I,2>.
  4039.           Tables are very convenient for recording information about data
  4040.           items, while conversion to an array makes it easy to systemati-
  4041.           cally examine the recorded information.
  4042.  
  4043.  
  4044.                                 7.6 THE NAME OPERATOR
  4045.  
  4046.             The unary name operator provides the address or location in
  4047.           memory where a variable is stored.  Its graphic symbol is the
  4048.           period (.).  We'll introduce it here through an example.
  4049.  
  4050.             Consider the indirect reference operator mentioned earlier.
  4051.           Suppose we want to use a variable to point to different elements
  4052.           of an array or table.  If we try the following, we immediately
  4053.           discover a problem:
  4054.  
  4055.                ?       A = ARRAY('10,10')
  4056.                ?       A[4,2] = 'DOG'
  4057.                ?       V = 'A[4,2]'
  4058.                ?       OUTPUT = $V
  4059.                
  4060.                Success
  4061.  
  4062.             The indirect reference operator treats the string 'A[4,2]' as a
  4063.           variable name, rather than an array element.  Remember, any char-
  4064.           acter sequence can be used indirectly to create a variable.
  4065.           SNOBOL4 creates a variable called A[4,2] that has absolutely no
  4066.           connection with array A.  The fact that this character sequence
  4067.           happens to look like an array reference to us is purely coinci-
  4068.           dental from SNOBOL4's point of view.
  4069.  
  4070.             To make this work, the name operator is applied to A[4,2] to
  4071.           obtain the address of that array element.  The address can be
  4072.           stored in variable V, and referenced with the indirect operator:
  4073.  
  4074.                ?       V = .A[4,2]
  4075.                ?       OUTPUT = $V
  4076.                DOG
  4077.  
  4078.             The name operator provides a general method for specifying the
  4079.  
  4080.  
  4081.  
  4082.        Tutorial                        - 61 -        Operators and Data Types
  4083.  
  4084.  
  4085.  
  4086.  
  4087.  
  4088.           name of an object.  Both of these statements are correct for
  4089.           specifying the first argument to the INPUT function:
  4090.  
  4091.                        INPUT('INFILE', 1, , 'CAPITAL.DAT')
  4092.                        INPUT(.INFILE,  1, , 'CAPITAL.DAT')
  4093.  
  4094.             Either form, 'INFILE' or .INFILE, tells the INPUT function the
  4095.           name of the variable to be input associated.  However, using the
  4096.           name operator allows us to associate a file with an array or
  4097.           table element:
  4098.  
  4099.                        INPUT('A[4,2]', 1, , 'CAPITAL.DAT')  (incorrect)
  4100.                        INPUT(.A[4,2],  1, , 'CAPITAL.DAT')
  4101.  
  4102.             Note that alternate use of the indirect reference and name
  4103.           operators "cancel" one another, so
  4104.  
  4105.                ?       OUTPUT = $(.($(.A[4,2])))
  4106.                DOG
  4107.  
  4108.           is simply a reference to A[4,2].
  4109.  
  4110.  
  4111.  
  4112.  
  4113.  
  4114.  
  4115.  
  4116.  
  4117.  
  4118.  
  4119.  
  4120.  
  4121.  
  4122.  
  4123.  
  4124.  
  4125.  
  4126.  
  4127.  
  4128.  
  4129.  
  4130.  
  4131.  
  4132.  
  4133.  
  4134.  
  4135.  
  4136.  
  4137.  
  4138.  
  4139.  
  4140.  
  4141.  
  4142.  
  4143.  
  4144.  
  4145.        Tutorial                        - 62 -        Operators and Data Types
  4146.  
  4147.  
  4148.  
  4149.  
  4150.  
  4151.                                                                   Chapter 8
  4152.  
  4153.  
  4154.                                                     PROGRAM-DEFINED OBJECTS
  4155.           -----------------------------------------------------------------
  4156.  
  4157.             SNOBOL4 is a very large and rich language, providing a diverse
  4158.           assortment of built-in features.  It is also an extensible lan-
  4159.           guage; it allows you to define new data types, functions, and
  4160.           operators.  You can, by creating your own entities, obtain
  4161.           another level of conciseness and power of expression.
  4162.  
  4163.             We will begin with program-defined functions because they allow
  4164.           a program to be partitioned into smaller, more manageable seg-
  4165.           ments.  As functions tend to be just a few lines long, transfers
  4166.           of control within them are usually obvious and manageable.  If
  4167.           your main program has complex, intertwined GOTOs, consider how
  4168.           the use of functions would clarify things.
  4169.  
  4170.             Functions also allow us to postpone the complete development of
  4171.           an algorithm.  We can design the overall program structure, using
  4172.           function names for components which will be developed later.
  4173.           Furthermore, if a particular function proves inefficient, it can
  4174.           be replaced later with an improved version.
  4175.  
  4176.  
  4177.                             8.1 PROGRAM-DEFINED FUNCTIONS
  4178.  
  4179.             The concept of a function should be clear from all the examples
  4180.           of SNOBOL4's built-in functions.  A function accepts some number
  4181.           of arguments, performs a computation based on their values, and
  4182.           returns a result and a success signal.  A function can also sig-
  4183.           nal failure, and not return any value.
  4184.  
  4185.  
  4186.           8.1.1 Function Definition
  4187.  
  4188.             We can define a new function by specifying its name and argu-
  4189.           ments.  The definition will be composed of "dummy arguments"---
  4190.           place holders that show how the arguments are to be used in the
  4191.           function.  Later, when the function is called, the actual argu-
  4192.           ments will replace the dummy arguments in the computation.
  4193.  
  4194.             We define a new function in SNOBOL4 by using the built-in func-
  4195.           tion DEFINE.  We call it with a "prototype string" containing the
  4196.           new function's name and arguments.  DEFINE makes the new func-
  4197.           tion's name known to SNOBOL4, so it can be used subsequently.
  4198.  
  4199.             Suppose we want to create a new function called SHIFT, which
  4200.           would circularly rotate a string through a specified number of
  4201.           character positions.  We'll define all rotations as being to the
  4202.           left---characters removed from the front of the string are placed
  4203.           back on the end.  For example, SHIFT('ENGRAVING',3) would return
  4204.           the string 'RAVINGENG'.
  4205.  
  4206.  
  4207.  
  4208.        Tutorial                        - 63 -         Program-Defined Objects
  4209.  
  4210.  
  4211.  
  4212.  
  4213.  
  4214.             We will begin by defining the function name and its dummy argu-
  4215.           ments, S and N.  Any names of your choosing can by used for dummy
  4216.           arguments.  In a program, it would look like this:
  4217.  
  4218.                        DEFINE('SHIFT(S,N)')
  4219.  
  4220.             It is important to realize that the DEFINE function must be
  4221.           executed for the definition to occur.  Most other programming
  4222.           languages process function definitions when a program is com-
  4223.           piled.  SNOBOL4's system is more flexible; the prototype string
  4224.           can itself be the result of other run-time computations.  In an
  4225.           extreme case, data input to a program could determine the names
  4226.           and kinds of functions to be defined.
  4227.  
  4228.  
  4229.           8.1.2 The Function Body
  4230.  
  4231.             Having declared the function name and dummy arguments, we need
  4232.           to provide the statements which will implement the function.  A
  4233.           very simple convention applies:
  4234.  
  4235.                When the function is used, SNOBOL4 transfers control to
  4236.                a statement label with the same name as the function.
  4237.  
  4238.             In this case, the first statement of the function would be
  4239.           labeled SHIFT.  There is no limit to the number of statements
  4240.           comprising the function body.
  4241.  
  4242.  
  4243.           8.1.3 Returning Function Results
  4244.  
  4245.             First, a function may return a value by assigning it to a vari-
  4246.           able with the same name as the function.  If no assignment
  4247.           occurs, the result is the null string.
  4248.  
  4249.             Second, the function must tell SNOBOL4 that it is finished, and
  4250.           that control should return back to the caller.  It does this by
  4251.           transferring to the special label RETURN.
  4252.  
  4253.             The label RETURN should not appear anywhere in your program.
  4254.           It is a special name, reserved by SNOBOL4 for just this purpose.
  4255.  
  4256.             With this information, we can now write our SHIFT function.  We
  4257.           will remove the first N characters from the beginning of the ar-
  4258.           gument string, and place them on the end.  The function body
  4259.           looks like this:
  4260.  
  4261.                SHIFT   S LEN(N) . FRONT REM . REST
  4262.                        SHIFT = REST FRONT                   :(RETURN)
  4263.  
  4264.             Each time SHIFT is called, the particular arguments used are
  4265.           placed in S and N.  The first statement splits S into two parts,
  4266.           assigning them to variables FRONT and REST.  The second statement
  4267.           reassembles them in the shifted order, and assigns them to vari-
  4268.  
  4269.  
  4270.  
  4271.        Tutorial                        - 64 -         Program-Defined Objects
  4272.  
  4273.  
  4274.  
  4275.  
  4276.  
  4277.           able SHIFT, to be returned as the function result.  The GOTO then
  4278.           transfers to label RETURN to return back to the caller.
  4279.  
  4280.  
  4281.           8.1.4 Function Failure
  4282.  
  4283.             What happens if we try the function call SHIFT('PEAR',7)?  As
  4284.           the function is defined above, the pattern match would fail,
  4285.           since LEN(7) is longer than the subject string.  The assignment
  4286.           to FRONT and REST would not take place, and the function would
  4287.           return an erroneous result.
  4288.  
  4289.             Now we could extend the definition of SHIFT to cycle the
  4290.           argument string multiple times.  In general, though, we want to
  4291.           develop a convenient method that allows a function to signal an
  4292.           exceptional condition back to the caller.  Function failure
  4293.           allows us to do just that.  Another convention is provided:
  4294.  
  4295.                Transferring to the special label FRETURN returns from
  4296.                a function signaling failure to the caller.  No value
  4297.                is returned as the function result.
  4298.  
  4299.             We can now rework the function body to signal failure when N is
  4300.           too large.  In this case, the pattern match fails, and we detect
  4301.           the failure in the GOTO field:
  4302.  
  4303.                SHIFT   S LEN(N) . FRONT REM . REST          :F(FRETURN)
  4304.                        SHIFT = REST FRONT                   :(RETURN)
  4305.  
  4306.             In general, the transfer to FRETURN does not need to be the
  4307.           result of the failure of a particular statement.  Any success or
  4308.           failure could be tested to produce a transfer to FRETURN.  For
  4309.           example, if we decided to explicitly test the length of S, the
  4310.           function could begin with:
  4311.  
  4312.                SHIFT   GT(N, SIZE(S))                       :S(FRETURN)
  4313.                         . . .
  4314.  
  4315.  
  4316.           8.1.5 Local Variables
  4317.  
  4318.             FRONT and REST were used in this function as temporary vari-
  4319.           ables to rearrange the argument string.  If they had appeared
  4320.           elsewhere in your program, their old values would be destroyed.
  4321.           Such inadvertent conflicts become harder to avoid as your func-
  4322.           tion library grows.  The prototype string used with DEFINE can
  4323.           specify "local variables" to be protected when the function is
  4324.           called.  For our SHIFT function, the call would look like this:
  4325.  
  4326.                        DEFINE('SHIFT(S,N)FRONT,REST')
  4327.  
  4328.             The local variables appear after the argument list.  When SHIFT
  4329.           is called, any existing values for FRONT and REST will be saved
  4330.           on a pushdown stack.  FRONT and REST are set to the null string,
  4331.  
  4332.  
  4333.  
  4334.        Tutorial                        - 65 -         Program-Defined Objects
  4335.  
  4336.  
  4337.  
  4338.  
  4339.  
  4340.           and control is transferred to the first statement of the function
  4341.           body.  When the function returns, FRONT and REST are restored to
  4342.           their previous values.
  4343.  
  4344.             Since the same potential problem exists for dummy arguments S
  4345.           and N, SNOBOL4 automatically saves their values before assigning
  4346.           the actual arguments to them.  And just like local variables,
  4347.           when the function returns, the dummy arguments are restored to
  4348.           their original values.
  4349.  
  4350.  
  4351.           8.1.6 Using Functions
  4352.  
  4353.             Once a function has been defined, it may be used in exactly the
  4354.           same manner as a built-in function.  It may appear in a statement
  4355.           anywhere its value is needed---in the subject, pattern, or
  4356.           replacement fields.  If used with the indirect reference opera-
  4357.           tion, functions may even be used in the GOTO field.  Of course, a
  4358.           function may be used as the argument of another function.
  4359.  
  4360.             The value returned by a function is not restricted to strings.
  4361.           Any SNOBOL4 data type, including patterns, may be returned.  Ear-
  4362.           lier, in the pattern match chapter, we showed how simple patterns
  4363.           could be tailored to our needs by using them in more complicated
  4364.           clauses.  The specific example was a variation of the BREAK pat-
  4365.           tern which would not match the null string.  Let's use a program-
  4366.           defined function to create a new function, BREAK1, with this
  4367.           property.  The definition statement might look like this:
  4368.  
  4369.                        DEFINE('BREAK1(S)')
  4370.  
  4371.           and the function body, like this:
  4372.  
  4373.                BREAK1  BREAK1 = NOTANY(S) BREAK(S)          :(RETURN)
  4374.  
  4375.             This function can now be used directly in a pattern match.  For
  4376.           example, BREAK1('abc') constructs a pattern which matches a non-
  4377.           null string, up to the occurrence of the letters 'a', 'b', or
  4378.           'c'.  Of course, the pattern returned by a function can be as
  4379.           complex as desired, giving us an elegant method to define our own
  4380.           pattern matching primitives.
  4381.  
  4382.  
  4383.           8.1.7 Organizing Functions
  4384.  
  4385.             SNOBOL4 does not know or care which statements belong to a
  4386.           particular function.  There is no explicit END statement for
  4387.           individual functions.  To keep programs readable, we'll have to
  4388.           impose some discipline of our own.  Also, having to execute the
  4389.           DEFINE function is a mixed blessing.  It offers tremendous flexi-
  4390.           bility, but requires us to place all our DEFINE's at the begin-
  4391.           ning of a program.  Here is the system proposed by Gimpel, which
  4392.           I like to use to manage functions and their definitions:
  4393.  
  4394.  
  4395.  
  4396.  
  4397.        Tutorial                        - 66 -         Program-Defined Objects
  4398.  
  4399.  
  4400.  
  4401.  
  4402.  
  4403.             We keep the function definition, any one-time initialization,
  4404.           and the function body together as a unit.  A GOTO transfers con-
  4405.           trol around the function body after the definition and initial-
  4406.           ization statements are executed.  Also present are comments de-
  4407.           scribing its use and any exceptional conditions.  Rewriting the
  4408.           SHIFT function in this form, and taking this opportunity to avoid
  4409.           rebuilding the pattern each time the function is called, it looks
  4410.           like this:
  4411.  
  4412.                * SHIFT(S,N)  -  Shift string S left N character positions.
  4413.                *  As characters are removed from the left side of the
  4414.                *  string, they are placed on the end.
  4415.                *
  4416.                *  The function fails if N is larger than the size of S.
  4417.                
  4418.                        DEFINE('SHIFT(S,N)FRONT,REST')
  4419.                        SHIFT_PAT = LEN(*N) . FRONT REM . REST :(SHIFT_END)
  4420.                
  4421.                SHIFT   S SHIFT_PAT                          :F(FRETURN)
  4422.                        SHIFT = REST FRONT                   :(RETURN)
  4423.                SHIFT_END
  4424.  
  4425.             Now this group of lines can be incorporated as a unit into the
  4426.           beginning of any program that wants to use it.  When execution
  4427.           begins, the first statement defines the SHIFT function.  Next we
  4428.           define a pattern, called SHIFT_PAT, for use when the function is
  4429.           called.  The pattern definition is only executed once, so we use
  4430.           the unevaluated expression operator (*N) to obtain the current
  4431.           value of N on each function call.  After defining the pattern, we
  4432.           "jump around" the function body, to label SHIFT_END.  (Remember,
  4433.           we are defining the function now, not executing it; falling into
  4434.           the function body would be an error.)  The function is now de-
  4435.           fined, and ready to be used.
  4436.  
  4437.             In general, functions should be prepared in this form:
  4438.  
  4439.                * Fname  - Description of use
  4440.                
  4441.                        DEFINE('Fname(arg1,...,argn)local1,...,localn')
  4442.                         . . .
  4443.                *       Any one-time initialization for Fname
  4444.                         . . .                               :(Fname_END)
  4445.                
  4446.                Fname   Function body
  4447.                         . . .
  4448.                Fname_END
  4449.  
  4450.             If you place your functions in individual disk files, they can
  4451.           be included in new programs as necessary.  By preparing functions
  4452.           in this form, they will all be defined and initialized when exe-
  4453.           cution begins.
  4454.  
  4455.             When discussing pattern matching, we used a pattern to convert
  4456.           a character to its ASCII decimal value.  In BASIC, two functions
  4457.  
  4458.  
  4459.  
  4460.        Tutorial                        - 67 -         Program-Defined Objects
  4461.  
  4462.  
  4463.  
  4464.  
  4465.  
  4466.           are provided for similar operations: ASC and CHR$.  We can create
  4467.           SNOBOL4 equivalents like this:
  4468.  
  4469.                * ASC(S) - Return the ASCII code for the first character of
  4470.                *          string S.
  4471.                *
  4472.                *       The value returned is an integer between 0 and 255.
  4473.                *       The function fails if S is null.
  4474.                
  4475.                        DEFINE('ASC(S)C')
  4476.                        ASC_ONE = LEN(1) . C
  4477.                        ASC_PAT = BREAK(*C) @ASC             :(ASC_END)
  4478.                
  4479.                ASC     S ASC_ONE                            :F(FRETURN)
  4480.                        &ALPHABET ASC_PAT                    :(RETURN)
  4481.                ASC_END
  4482.  
  4483.                * CHR(N) - Converts an integer ASCII code to a one character
  4484.                *          string.
  4485.                *
  4486.                *       The argument N is an integer between 0 and 255.
  4487.                *       The function fails if N is greater than 255.
  4488.                
  4489.                        DEFINE('CHR(N)')
  4490.                        CHR_PAT = TAB(*N) LEN(1) . CHR       :(CHR_END)
  4491.                
  4492.                CHR     &ALPHABET CHR_PAT              :S(RETURN) F(FRETURN)
  4493.                CHR_END
  4494.  
  4495.             Note that both functions were written to work correctly regard-
  4496.           less of the anchoring mode in use by the calling program.
  4497.  
  4498.             (The CHR function is shown here as an example only.  Vanilla
  4499.           SNOBOL4 provides a built-in function, CHAR(N), for this purpose.
  4500.           See Chapter 19, "Built-in Functions.")
  4501.  
  4502.  
  4503.           8.1.8 Call by Value and Call by Name
  4504.  
  4505.             Function calls in SNOBOL4 transmit the "value" of the argument
  4506.           to the function.  Variables used in the function call cannot be
  4507.           harmed by the function.  This type of function usage is referred
  4508.           to as "call by value."  Occasionally, we might want the function
  4509.           to access the argument variables themselves.  The name operator
  4510.           introduced in the previous chapter provides this ability.  The
  4511.           function call still transmits a value, but the value used is the
  4512.           "name" of a variable.
  4513.  
  4514.             Consider a function called SWAP, which will exchange the con-
  4515.           tents of two variables.  If we wanted to exchange the contents of
  4516.           variables COUNT and OLDCOUNT, we would say SWAP(.COUNT,
  4517.           .OLDCOUNT).  The function looks like this:
  4518.  
  4519.  
  4520.  
  4521.  
  4522.  
  4523.        Tutorial                        - 68 -         Program-Defined Objects
  4524.  
  4525.  
  4526.  
  4527.  
  4528.  
  4529.                * SWAP(.V1, .V2) - Exchange the contents of two variables.
  4530.                *  The variables must be prefixed with the name operator
  4531.                *  when the function is called.
  4532.                
  4533.                        DEFINE('SWAP(X,Y)TEMP')              :(SWAP_END)
  4534.                
  4535.                SWAP    TEMP = $X
  4536.                        $X = $Y
  4537.                        $Y = TEMP                            :(RETURN)
  4538.                SWAP_END
  4539.  
  4540.             The name operator allows us to access the argument variables.
  4541.           If we had not used it, the function would be called with the
  4542.           variables' values, with no indication of where they came from.
  4543.           Calls to SWAP are not limited to simple variable arguments.  Any-
  4544.           thing capable of receiving the name operator, such as array and
  4545.           table elements, could be used:  SWAP(.A<4,3>, .T<'YOU'>).
  4546.  
  4547.             There are certain situations where call by name occurs implic-
  4548.           itly.  If the argument is an array or table name, or a program-
  4549.           defined data type (discussed below), it points to the actual data
  4550.           object, which can then be modified by the function.  For example,
  4551.           if FILL were a function which loads an array with values read
  4552.           from a file, the statements
  4553.  
  4554.                        A = ARRAY(25)
  4555.                        FILL(A)
  4556.  
  4557.           would cause array A to be altered.
  4558.  
  4559.  
  4560.           8.1.9 Functions and CODE.SNO
  4561.  
  4562.             The CODE.SNO program was provided to allow interactive experi-
  4563.           ments with SNOBOL4 statements.  If you create functions using the
  4564.           preceding format, they also can be tested using CODE.SNO.
  4565.  
  4566.             Use your text editor to create a disk file containing the SHIFT
  4567.           function.  (Be certain to include the GOTO that transfers around
  4568.           the function body.)  Call the file SHIFT.SNO.  Now, start the
  4569.           CODE.SNO program, and type the following:
  4570.  
  4571.                ?       SLOAD('SHIFT.SNO')
  4572.                Success
  4573.                ?       OUTPUT = SHIFT('COTTON',4)
  4574.                ONCOTT
  4575.                ?       OUTPUT = SHIFT('OAK',4)
  4576.                Failure
  4577.  
  4578.  
  4579.  
  4580.  
  4581.  
  4582.  
  4583.  
  4584.  
  4585.  
  4586.        Tutorial                        - 69 -         Program-Defined Objects
  4587.  
  4588.  
  4589.  
  4590.  
  4591.  
  4592.           8.1.10 Recursive Functions
  4593.  
  4594.             The statements that comprise a function are free to call any
  4595.           functions they choose, including the function they are defining.
  4596.           Of course, for this to make sense, they must call themselves with
  4597.           a simplified version of the original problem, or an endless loop
  4598.           would result.  Eventually, the function calls itself with an arg-
  4599.           ument so simple that it can return an answer without any further
  4600.           recursive calls.  It's like winding a clock spring up.  The
  4601.           central, non-recursive answer to the innermost call provides an
  4602.           answer to the next turn out, with the recursive calls unwinding
  4603.           until the original problem can be solved.
  4604.  
  4605.             There is no explicit declaration for recursion; any function
  4606.           can be used recursively if it is designed properly.  However, all
  4607.           local variables should be declared in the DEFINE function so they
  4608.           will be saved and restored during recursive calls.
  4609.  
  4610.             Sometimes, recursion can produce dramatically smaller programs.
  4611.           "Algorithms in SNOBOL4" provides a example with the recursive
  4612.           function, ROMAN.  It convert's an integer in the range 0 to 3999
  4613.           to its Roman numeral equivalent.  Two premises are required:
  4614.  
  4615.             1. We know the Roman numerals for the numbers 0 to 9 (null, I,
  4616.                II, ..., IX), and can perform this conversion with a simple
  4617.                pattern match.
  4618.  
  4619.             2. We can use the REPLACE function to "multiply" a number in
  4620.                Roman form by 10 by replacing I by X, V by L, X by C, etc.
  4621.  
  4622.             The function uses these two rules to produce a recursive solu-
  4623.           tion for some integer N.  The algorithm looks like this:
  4624.  
  4625.                The rightmost digit is removed from the argument and
  4626.                converted by premise 1.  Removing the digit effectively
  4627.                divides the argument by 10, simplifying the problem.
  4628.  
  4629.                The reduced argument is then converted by calling ROMAN
  4630.                recursively and "multiplying" the result by 10 accord-
  4631.                ing to premise 2.
  4632.  
  4633.                The previously converted unit's digit is appended to
  4634.                the result.
  4635.  
  4636.           Here's the function (note that a "plus sign" in column one allows
  4637.           a statement to be continued over several lines):
  4638.  
  4639.  
  4640.  
  4641.  
  4642.  
  4643.  
  4644.  
  4645.  
  4646.  
  4647.  
  4648.  
  4649.        Tutorial                        - 70 -         Program-Defined Objects
  4650.  
  4651.  
  4652.  
  4653.  
  4654.  
  4655.                * ROMAN(N) - Convert integer N to Roman numeral form.
  4656.                *
  4657.                *  N must be positive and less than 4000.
  4658.                *
  4659.                *  An asterisk appears in the result if N >= 4000.
  4660.                *
  4661.                *  The function fails if N is not an integer.
  4662.                
  4663.                        DEFINE('ROMAN(N)UNITS')              :(ROMAN_END)
  4664.                
  4665.                *  Get rightmost digit to UNITS and remove it from N.
  4666.                *  Return null result if argument is null.
  4667.                ROMAN   N RPOS(1) LEN(1) . UNITS =           :F(RETURN)
  4668.                
  4669.                *  Search for digit, replace with its Roman form.
  4670.                *  Return failing if not a digit.
  4671.                        '0,1I,2II,3III,4IV,5V,6VI,7VII,8VIII,9IX,'  UNITS
  4672.                +         BREAK(',') . UNITS                 :F(FRETURN)
  4673.                
  4674.                *  Convert rest of N and multiply by 10.  Propagate a
  4675.                *  failure return from recursive call back to caller.
  4676.                        ROMAN = REPLACE(ROMAN(N), 'IVXLCDM', 'XLCDM**')
  4677.                +               UNITS            :S(RETURN) F(FRETURN)
  4678.                ROMAN_END
  4679.  
  4680.             The first call to ROMAN may have an integer argument.  The
  4681.           statement labeled ROMAN causes N to be converted to a string, and
  4682.           subsequent recursive calls use a string argument.  The recursive
  4683.           calls cease when reducing N finally produces a null string
  4684.           argument---the match at statement ROMAN fails, and the function
  4685.           returns immediately with a null result.
  4686.  
  4687.  
  4688.                            8.2 PROGRAM-DEFINED DATA TYPES
  4689.  
  4690.             With the exception of arrays and tables, a variable may have
  4691.           only one item of data in it at a time.  In many applications, it
  4692.           is convenient if several data items can be associated with a
  4693.           variable.  For example, if we wanted to work with complex num-
  4694.           bers, a variable should contain two numbers---the real and imagi-
  4695.           nary parts.  In an inventory system, an individual product might
  4696.           require values such as name, price, quantity, and manufacturer.
  4697.  
  4698.             Program-defined data types enlarge SNOBOL4's repertoire to
  4699.           include new objects such as COMPLEX or PRODUCT.  SNOBOL4 only
  4700.           provides a system for managing these new types; defining a data
  4701.           type does not magically invest SNOBOL4 with a knowledge of com-
  4702.           plex arithmetic or inventory accounting.  It is still up to you
  4703.           to provide the computational support for each new type.
  4704.  
  4705.  
  4706.           8.2.1 Data Type Definition
  4707.  
  4708.             A program-defined data type will consist of a number of fields,
  4709.  
  4710.  
  4711.  
  4712.        Tutorial                        - 71 -         Program-Defined Objects
  4713.  
  4714.  
  4715.  
  4716.  
  4717.  
  4718.           each containing an individual data element.  We begin by select-
  4719.           ing names for the data type and fields.  An inventory system
  4720.           might use the data type name PRODUCT, and field names NAME,
  4721.           PRICE, QUANTITY, and MFG.
  4722.  
  4723.             A data type is defined by providing a prototype string to the
  4724.           built-in DATA function.  The prototype assumes a form similar to
  4725.           a function call, with the data type taking the place of the func-
  4726.           tion name, and the field names replacing the arguments.  The form
  4727.           of the prototype string is:
  4728.  
  4729.                        'TYPENAME(FIELD1,FIELD2,...,FIELDn)'
  4730.  
  4731.             Blanks are not permitted within a prototype.  Try creating a
  4732.           new data type using the CODE.SNO program:
  4733.  
  4734.                ?       DATA('PRODUCT(NAME,PRICE,QUANTITY,MFG)')
  4735.                Success
  4736.  
  4737.             The DATA function tells SNOBOL4 to define an object creation
  4738.           function with the new data type's name:
  4739.  
  4740.                        PRODUCT(arg1, arg2, arg3, arg4)
  4741.  
  4742.             This new function can be called whenever we wish to create a
  4743.           new object with the PRODUCT data type.  Its arguments are the
  4744.           initial values to be given to the four fields which comprise a
  4745.           PRODUCT.  The function returns a pointer to the new object, which
  4746.           can be stored in a variable, array, or table.  Try creating two
  4747.           new objects as follows:
  4748.  
  4749.                ?      ITEM1 = PRODUCT('CAPERS', 2, 48, 'BRINE BROTHERS')
  4750.                ?      ITEM2 = PRODUCT('PICKLES', 1, 72, 'PETER PIPER INC.')
  4751.  
  4752.  
  4753.           8.2.2 Data Type Use
  4754.  
  4755.             The defining call to the DATA function also created several
  4756.           field reference functions.  In this case, their names would be:
  4757.  
  4758.                NAME(arg)    PRICE(arg)    QUANTITY(arg)    MFG(arg)
  4759.  
  4760.             The argument used with each function is an object created by
  4761.           the PRODUCT function.  Try accessing ITEM1's fields:
  4762.  
  4763.                ?       OUTPUT = MFG(ITEM1)
  4764.                BRINE BROTHERS
  4765.                ?       OUTPUT = PRICE(ITEM1) * QUANTITY(ITEM1)
  4766.                96
  4767.  
  4768.             We can alter the value of a field after an object is created.
  4769.           Field reference functions can also be used as the object of an
  4770.           assignment, so:
  4771.  
  4772.  
  4773.  
  4774.  
  4775.        Tutorial                        - 72 -         Program-Defined Objects
  4776.  
  4777.  
  4778.  
  4779.  
  4780.  
  4781.                ?       QUANTITY(ITEM2) = QUANTITY(ITEM2) - 12
  4782.  
  4783.           changes the QUANTITY field of ITEM2 from 72 to 60.
  4784.  
  4785.  
  4786.           8.2.3 Copying Data Items
  4787.  
  4788.             It is important to recognize that variables like ITEM1 and
  4789.           ITEM2 contain "pointers" to the data.  Assigning ITEM1 to another
  4790.           variable, say LASTITEM, merely copies the pointer; both variables
  4791.           still point to the same physical packet of data in memory.
  4792.           Altering the QUANTITY field of ITEM1 would alter the QUANTITY
  4793.           field of LASTITEM.  This is the same behavior observed earlier
  4794.           for array and table names.
  4795.  
  4796.             The built-in COPY function creates a unique copy of an object--
  4797.           one which is independent of the original.  Try using it with
  4798.           CODE.SNO:
  4799.  
  4800.                ?       LASTITEM = COPY(ITEM1)
  4801.                ?       QUANTITY(ITEM1) = 24
  4802.                ?       OUTPUT = QUANTITY(LASTITEM)
  4803.                48
  4804.  
  4805.  
  4806.           8.2.4 Creating Structures
  4807.  
  4808.             Our inventory example used string and integer values as the
  4809.           field contents.  In fact, any SNOBOL4 data type may be stored in
  4810.           a field, including pointers to other program-defined types.  Com-
  4811.           plex structures, such as queues, stacks, trees, and arbitrary
  4812.           graphs may be created.
  4813.  
  4814.             For example, if we wanted to link together all products made by
  4815.           the same manufacturer, PRODUCT could be defined with an addi-
  4816.           tional field.  We won't go through the exercise with CODE.SNO,
  4817.           but will sketch out the changes:
  4818.  
  4819.                DATA('PRODUCT(NAME,PRICE,QUANTITY,MFG,MFGLINK')
  4820.  
  4821.             As each product is defined, we will determine if we have
  4822.           another product from the same manufacturer.  If so, MFGLINK is
  4823.           set to point to that other product.  If not, it is set to the
  4824.           null string.  A table M provides a convenient way to keep track
  4825.           of manufacturers.  Assume variable COMPANY contains the manufac-
  4826.           turer's name as each product is defined.  Then all of the requi-
  4827.           site searching and linking can be accomplished in one statement:
  4828.  
  4829.                M<COMPANY> = PRODUCT(..., ..., ..., COMPANY, M<COMPANY>)
  4830.  
  4831.             If this is the company's first appearance, it is not in the
  4832.           table, and the last argument to the PRODUCT function sets MFGLINK
  4833.           to the null string.  The assignment statement uses the company as
  4834.           the table subscript, and the entry points to the current product.
  4835.  
  4836.  
  4837.  
  4838.        Tutorial                        - 73 -         Program-Defined Objects
  4839.  
  4840.  
  4841.  
  4842.  
  4843.  
  4844.           If another product definition uses the same company, MFGLINK will
  4845.           point to the previous product, and the table will be updated to
  4846.           point to the current product.  In this manner, all products from
  4847.           a manufacturer will be threaded together.  Each thread starts
  4848.           with a table entry, and goes through each product's MFGLINK
  4849.           field, ending with a null string in the last product's MFGLINK.
  4850.  
  4851.             Now if we wanted to display all products supplied by a particu-
  4852.           lar manufacturer, we select and follow the appropriate thread:
  4853.  
  4854.                        X      =  M<COMPANY>
  4855.                LOOP    OUTPUT =  DIFFER(X) NAME(X)          :F(DONE)
  4856.                        X      =  MFGLINK(X)                 :(LOOP)
  4857.                DONE
  4858.  
  4859.  
  4860.           8.2.5 The DATATYPE Function
  4861.  
  4862.             The DATATYPE function allows you to learn the type of data in a
  4863.           particular variable.  It is useful when the kind of processing to
  4864.           be performed depends on the data type.  The formal data type name
  4865.           is returned as an upper-case string:
  4866.  
  4867.                ?       OUTPUT = DATATYPE(54)
  4868.                INTEGER
  4869.                ?       OUTPUT = DATATYPE(ITEM1)
  4870.                PRODUCT
  4871.  
  4872.  
  4873.                             8.3 PROGRAM-DEFINED OPERATORS
  4874.  
  4875.             If you can define new functions and data types, why not new
  4876.           operators too?  Indeed, SNOBOL4 provides this feature, although
  4877.           most programs can be written without it.  For the sake of com-
  4878.           pleteness, we'll provide a brief discussion.
  4879.  
  4880.  
  4881.           8.3.1 Operators and Functions
  4882.  
  4883.             Unary or binary operators can be thought of as functions of one
  4884.           or two arguments.  For example, A + B can be written in func-
  4885.           tional form as PLUS(A,B), where PLUS is some function which im-
  4886.           plements addition.  Operators can be redefined by specifying a
  4887.           function to replace them.  We still write our program in terms of
  4888.           the operator's graphic symbol, but SNOBOL4 will use the specified
  4889.           function whenever the operator must be performed.
  4890.  
  4891.  
  4892.  
  4893.  
  4894.  
  4895.  
  4896.  
  4897.  
  4898.  
  4899.  
  4900.  
  4901.        Tutorial                        - 74 -         Program-Defined Objects
  4902.  
  4903.  
  4904.  
  4905.  
  4906.  
  4907.             The built-in function OPSYN creates synonyms and new defini-
  4908.           tions for operators.  Synonyms permit different names or symbols
  4909.           to be used in place of a function or operator.  The general form
  4910.           of OPSYN is:
  4911.  
  4912.                        OPSYN(new name, old name, i)
  4913.  
  4914.             The new name is defined as a synonym of the old name.  The
  4915.           third argument is 0, 1, or 2 if we are defining functions, unary
  4916.           operators, or binary operators respectively.
  4917.  
  4918.  
  4919.           8.3.2 Function Synonyms
  4920.  
  4921.             We can make the name LENGTH a synonym for the SIZE function:
  4922.  
  4923.                ?       OPSYN('LENGTH', 'SIZE', 0)
  4924.                ?       OUTPUT = LENGTH('RABBIT')
  4925.                6
  4926.  
  4927.             The word synonym is not quite an accurate description of OPSYN.
  4928.           The name LENGTH becomes associated with the "code" that imple-
  4929.           ments the SIZE function, not with the word SIZE per se.  If SIZE
  4930.           was subsequently redefined---perhaps as a program-defined
  4931.           function--LENGTH would continue to return the number of
  4932.           characters in a string.
  4933.  
  4934.  
  4935.           8.3.3 Operator Synonyms
  4936.  
  4937.             Take a moment to examine the tables in Chapter 15, "Operators,"
  4938.           in the reference section.  Note that in each table there are a
  4939.           number of operator symbols whose definition is <none>.
  4940.  
  4941.             If you use an undefined binary operator, you'll get an error:
  4942.  
  4943.                ?       OUTPUT = 1 # 1
  4944.                Execution error #5, Undefined function or operation
  4945.  
  4946.             However, we could make this operator synonymous with the DIFFER
  4947.           function (which also uses two arguments) and use it instead:
  4948.  
  4949.                ?       OPSYN('#', 'DIFFER', 2)
  4950.                ?       OUTPUT = 1 # 2
  4951.                Failure
  4952.  
  4953.             Conversely, we can define a function in place of an operator:
  4954.  
  4955.                ?       OPSYN('PLUS', '+', 2)
  4956.                ?       OUTPUT = PLUS(4, 5)
  4957.                9
  4958.  
  4959.  
  4960.  
  4961.  
  4962.  
  4963.  
  4964.        Tutorial                        - 75 -         Program-Defined Objects
  4965.  
  4966.  
  4967.  
  4968.  
  4969.  
  4970.             Unary operators can be similarly treated, using 1 as the third
  4971.           argument:
  4972.  
  4973.                ?       OPSYN('!', 'ANY', 1)
  4974.                ?       'ABC321' !'3C' . OUTPUT
  4975.                C
  4976.  
  4977.             Operators can be created to maintain a stack, or navigate
  4978.           around a tree.  The full generality of functions and program-
  4979.           defined data types are available to your operators.  Through this
  4980.           technique you can make SNOBOL4 speak the language of your
  4981.           particular problem.
  4982.  
  4983.  
  4984.  
  4985.  
  4986.  
  4987.  
  4988.  
  4989.  
  4990.  
  4991.  
  4992.  
  4993.  
  4994.  
  4995.  
  4996.  
  4997.  
  4998.  
  4999.  
  5000.  
  5001.  
  5002.  
  5003.  
  5004.  
  5005.  
  5006.  
  5007.  
  5008.  
  5009.  
  5010.  
  5011.  
  5012.  
  5013.  
  5014.  
  5015.  
  5016.  
  5017.  
  5018.  
  5019.  
  5020.  
  5021.  
  5022.  
  5023.  
  5024.  
  5025.  
  5026.  
  5027.        Tutorial                        - 76 -         Program-Defined Objects
  5028.  
  5029.  
  5030.  
  5031.  
  5032.  
  5033.                                                                   Chapter 9
  5034.  
  5035.  
  5036.                                                             ADVANCED TOPICS
  5037.           -----------------------------------------------------------------
  5038.  
  5039.             The material presented so far allows you to write powerful
  5040.           SNOBOL4 programs.  In this chapter, we will examine other inter-
  5041.           esting and useful features of the language.
  5042.  
  5043.  
  5044.                                9.1 THE ARBNO FUNCTION
  5045.  
  5046.             This function produces a pattern which will match zero or more
  5047.           consecutive occurrences of the pattern specified by its argument.
  5048.           As its name implies, ARBNO is useful when an arbitrary number of
  5049.           instances of a pattern may occur.  For example, ARBNO(LEN(3))
  5050.           matches strings of length 0, 3, 6, 9, ....  There is no restric-
  5051.           tion on the complexity of the pattern argument.
  5052.  
  5053.             Like the ARB pattern, ARBNO is shy, and tries to match the
  5054.           shortest possible string.  Initially, it simply matches the null
  5055.           string.  If a subsequent pattern component fails to match,
  5056.           SNOBOL4 backs up, and asks ARBNO to try again.  Each time ARBNO
  5057.           is retried, it supplies another instance of its argument pattern.
  5058.           In other words, ARBNO(PAT) behaves like
  5059.  
  5060.                        ( '' |  PAT | PAT PAT | PAT PAT PAT | ... )
  5061.  
  5062.             Also like ARB, ARBNO is usually used with adjacent patterns to
  5063.           "draw it out."  Let's consider a simple example.  We want to
  5064.           write a pattern to test for a list.  We'll define a list as being
  5065.           one or more numbers separated by comma, and enclosed by parenthe-
  5066.           ses.  Use CODE.SNO to try this definition:
  5067.  
  5068.                ?       ITEM = SPAN('0123456789')
  5069.                ?       LIST = POS(0) '(' ITEM  ARBNO(',' ITEM) ')' RPOS(0)
  5070.                ?       '(12,345,6)' LIST
  5071.                Success
  5072.                ?       '(12,,34)' LIST
  5073.                Failure
  5074.  
  5075.             ARBNO is retried and extended until its subsequent, ')', fi-
  5076.           nally matches.  POS(0) and RPOS(0) force the pattern to be ap-
  5077.           plied to the entire subject string.
  5078.  
  5079.             Alternation may be used within ARBNO's argument.  This pattern
  5080.           matches any number of pairs of certain letters:
  5081.  
  5082.                ?       PAIRS = POS(0) ARBNO('AA' | 'BB' | 'CC') RPOS(0)
  5083.                ?       'CCBBAAAACC' PAIRS
  5084.                Success
  5085.                ?       'AABBB' PAIRS
  5086.                Failure
  5087.  
  5088.  
  5089.  
  5090.        Tutorial                        - 77 -                 Advanced Topics
  5091.  
  5092.  
  5093.  
  5094.  
  5095.  
  5096.                                9.2 RECURSIVE PATTERNS
  5097.  
  5098.             This is the pattern analogue of a recursive function---a pat-
  5099.           tern is defined in terms of itself.  The unevaluated expression
  5100.           operator makes the definition possible.
  5101.  
  5102.             Suppose we wanted to expand the previous definition of a list
  5103.           to say that a list item may be a span of digits, or another list.
  5104.           The definition proceeds as before, except that the unevaluated
  5105.           expression operator is used in the first statement; the concept
  5106.           of a list has not yet been defined:
  5107.  
  5108.                ?       ITEM = SPAN('0123456789') | *LIST
  5109.                ?       LIST = '(' ITEM  ARBNO(',' ITEM) ')'
  5110.                ?       TEST = POS(0) LIST RPOS(0)
  5111.                ?       '(12,(3,45,(6)),78)' TEST
  5112.                Success
  5113.                ?       '(12,(34)' TEST
  5114.                Failure
  5115.  
  5116.             Recursion occurs because LIST is defined in terms of ITEM,
  5117.           which is defined in terms of LIST, and so on.  Note that func-
  5118.           tions POS(0) and RPOS(0) were "moved out one level," to TEST, be-
  5119.           cause LIST must now match substrings within the subject.
  5120.  
  5121.             In our previous discussion of recursive functions, we said they
  5122.           work because successive calls present the function with progres-
  5123.           sively simpler problems, until the problem can be solved without
  5124.           further recursion.  Similarly, patterns ITEM and LIST are applied
  5125.           to successively smaller substrings, until ITEM can use its SPAN()
  5126.           alternative instead of invoking LIST again.
  5127.  
  5128.             In general, you will need an alternative somewhere in the re-
  5129.           cursive loop to allow the pattern matcher "a way out."  Also, you
  5130.           should place recursive objects last in a series of alternatives,
  5131.           so that the simpler, nonrecursive patterns are attempted first
  5132.           and "recursive plunges" can be avoided.
  5133.  
  5134.             SNOBOL4 saves information on a "pattern stack" during the pat-
  5135.           tern match process.  Heavily recursive patterns and long subject
  5136.           strings can sometimes result in stack overflow.  If this occurs,
  5137.           you should break the problem apart into several smaller pattern
  5138.           matches.
  5139.  
  5140.             As recursive patterns use the unevaluated expression operator,
  5141.           it is sometimes necessary to disable SNOBOL4's heuristics by
  5142.           setting &FULLSCAN = 1.
  5143.  
  5144.  
  5145.                              9.3 QUICKSCAN AND FULLSCAN
  5146.  
  5147.             Pattern matching can be very time-consuming because of the num-
  5148.           ber of possibilities which must be attempted.  In the normal
  5149.           "quickscan" mode, SNOBOL4 stops searching for a match when it
  5150.  
  5151.  
  5152.  
  5153.        Tutorial                        - 78 -                 Advanced Topics
  5154.  
  5155.  
  5156.  
  5157.  
  5158.  
  5159.           thinks further efforts would be futile.  The heuristics are com-
  5160.           plex, but can be summarized as follows: pattern matching fails
  5161.           when there are insufficient subject characters to satisfy the re-
  5162.           maining pattern components.
  5163.  
  5164.             The cursor operator can be used to demonstrate at what point
  5165.           SNOBOL4 gives up.  For example, in the pattern match
  5166.  
  5167.                ?       'ABCD' @OUTPUT 'X' LEN(3)
  5168.                0
  5169.                Failure
  5170.  
  5171.             SNOBOL4 does not attempt to match 'X' against 'B' because fewer
  5172.           than 3 subject characters remain after it, and LEN(3) could never
  5173.           succeed.
  5174.  
  5175.             A second type of heuristic is the "one character assumption"
  5176.           for unevaluated expressions.  SNOBOL4 assumes that unevaluated
  5177.           expressions will match at least one character.  This heuristic
  5178.           was originally provided to break recursive loops, but can cause
  5179.           programming problems when an unevaluated expression must match
  5180.           the null string.  Consider a pattern which succeeds if 'B' is at
  5181.           least 4 character positions beyond an 'A' in the subject:
  5182.  
  5183.                ?       P = 'A' ARB $ X 'B' *GE(SIZE(X), 4)
  5184.                ?       'A12345BC' P
  5185.                Success
  5186.                ?       'A12345B' P
  5187.                Failure
  5188.  
  5189.             The characters between 'A' and 'B' are matched by ARB, and im-
  5190.           mediately assigned to X.  The size of X is then compared to 4 by
  5191.           the GE function, which succeeds and returns the null string.
  5192.           This null string result should not interfere with the pattern
  5193.           match, but we find the pattern misbehaves when 'B' is the last
  5194.           character of the subject.  The unevaluated expression operator
  5195.           made SNOBOL4 assume a one character length for the GE function,
  5196.           and matching 'B' against the last subject character was never at-
  5197.           tempted.
  5198.  
  5199.             For most pattern matching, heuristics are invisible.  However,
  5200.           there are circumstances when we would like SNOBOL4 to be exhaus-
  5201.           tive in its match attempts.  We can disable heuristics and enter
  5202.           "fullscan" mode by setting keyword &FULLSCAN nonzero:
  5203.  
  5204.  
  5205.  
  5206.  
  5207.  
  5208.  
  5209.  
  5210.  
  5211.  
  5212.  
  5213.  
  5214.  
  5215.  
  5216.        Tutorial                        - 79 -                 Advanced Topics
  5217.  
  5218.  
  5219.  
  5220.  
  5221.  
  5222.                ?       &FULLSCAN = 1
  5223.                ?       'A12345B' P
  5224.                Success
  5225.                ?       'ABCD' @OUTPUT 'X' LEN(3)
  5226.                0
  5227.                1
  5228.                2
  5229.                3
  5230.                4
  5231.                Failure
  5232.  
  5233.             The quickscan mode can be reinstated by setting &FULLSCAN = 0.
  5234.  
  5235.  
  5236.                             9.4 OTHER PRIMITIVE PATTERNS
  5237.  
  5238.             We can accomplish quite a lot with just the primitive patterns
  5239.           ARB and REM.  However, there are five additional patterns which
  5240.           you should be aware of:
  5241.  
  5242.           -----------------------------------------------------------------
  5243.  
  5244.           ABORT                            End pattern match
  5245.  
  5246.             The ABORT pattern causes immediate failure of the entire pat-
  5247.           tern match, without seeking other alternatives.  Usually a match
  5248.           succeeds when we find a subject sequence which satisfies the pat-
  5249.           tern.  The ABORT pattern does the opposite: if we find a certain
  5250.           pattern, we will abort the match and fail immediately.  For exam-
  5251.           ple, suppose we are looking for an 'A' or 'B', but want to fail
  5252.           if '1' is encountered first:
  5253.  
  5254.                ?       '--AB-1-' (ANY('AB') | '1' ABORT)
  5255.                Success
  5256.                ?       '--1B-A-' (ANY('AB') | '1' ABORT)
  5257.                Failure
  5258.  
  5259.             The last example may be confusing because the ANY function ap-
  5260.           pears as the first alternative, fostering the illusion that it
  5261.           will find the 'B' in the subject before the other pattern alter-
  5262.           native is tried.  However, that is not the order of pattern
  5263.           matching; ALL pattern alternatives are tried at cursor position
  5264.           zero in the subject.  If none succeed, the cursor is advanced by
  5265.           one, and all alternatives are tried again.  When the cursor is in
  5266.           front of subject character '1', ANY still does not match, but the
  5267.           second alternative now does.  As the '1's match, ABORT is
  5268.           reached, causing failure.
  5269.  
  5270.  
  5271.  
  5272.  
  5273.  
  5274.  
  5275.  
  5276.  
  5277.  
  5278.  
  5279.        Tutorial                        - 80 -                 Advanced Topics
  5280.  
  5281.  
  5282.  
  5283.  
  5284.  
  5285.           -----------------------------------------------------------------
  5286.  
  5287.           BAL                              Match balanced string
  5288.  
  5289.             The BAL pattern matches the shortest nonnull string in which
  5290.           parentheses are balanced.  (A string without parentheses is also
  5291.           considered to be balanced.)  These strings are balanced:
  5292.  
  5293.                (X)      Y      (A!(C:D))      (AB)+(CD)      9395
  5294.  
  5295.             These are not:
  5296.  
  5297.                )A+B     (A*(B+)      (X))
  5298.  
  5299.             BAL is concerned only with left and right parentheses.  The
  5300.           matching string does not have to be a well-formed expression in
  5301.           the algebraic sense; in fact, it needn't be an algebraic expres-
  5302.           sion at all.  Like ARB, BAL is most useful when constrained on
  5303.           both sides by other pattern components.
  5304.  
  5305.           -----------------------------------------------------------------
  5306.  
  5307.           FAIL                             Seek other alternatives
  5308.  
  5309.             The FAIL pattern signals failure of this portion of the pattern
  5310.           match, causing the pattern matcher to backtrack and seek other
  5311.           alternatives.  FAIL will also suppress a successful match, which
  5312.           can be very useful when the match is being performed for its side
  5313.           effects, such as immediate assignment.  For example, in unan-
  5314.           chored mode, this statement will display the subject characters,
  5315.           one per line:
  5316.  
  5317.                        SUBJECT LEN(1) $ OUTPUT FAIL
  5318.  
  5319.             LEN(1) matches the first subject character, and immediately as-
  5320.           signs it to OUTPUT.  FAIL tells the pattern matcher to try again,
  5321.           and since there are no other alternatives, the entire match is
  5322.           retried at the next subject character.  Forced failure and re-
  5323.           tries continue until the subject is exhausted.
  5324.  
  5325.           -----------------------------------------------------------------
  5326.  
  5327.           FENCE                            Prevent match retries
  5328.  
  5329.             Pattern FENCE matches the null string and has no effect when
  5330.           the pattern matcher is moving left to right in a pattern.  How-
  5331.           ever, if the pattern matcher is backing up to try other alterna-
  5332.           tives, and encounters FENCE, the match fails.
  5333.  
  5334.             FENCE can be used to "lock in" an earlier success.  Suppose we
  5335.           want to succeed if the first 'A' or 'B' in the subject is fol-
  5336.           lowed by a plus sign.  In the following example, the 'A's match,
  5337.           we go through the FENCE, and find '+' does not match the next
  5338.           subject character, 'B'.  SNOBOL4 tries to backtrack, but is
  5339.  
  5340.  
  5341.  
  5342.        Tutorial                        - 81 -                 Advanced Topics
  5343.  
  5344.  
  5345.  
  5346.  
  5347.  
  5348.           stopped by the FENCE and fails:
  5349.  
  5350.                ?       '1AB+' ANY('AB') FENCE '+'
  5351.                Failure
  5352.  
  5353.             If FENCE were omitted, backtracking would match ANY to 'B', and
  5354.           then proceed forward again to match '+'.
  5355.  
  5356.             If FENCE appears as the first component of a pattern, SNOBOL4
  5357.           cannot back up through it to try another subject starting posi-
  5358.           tion.  This results in an anchored pattern, even if the &ANCHOR
  5359.           keyword specifies unanchored mode:
  5360.  
  5361.                ?       'ABC' FENCE 'B'
  5362.                Failure
  5363.  
  5364.           -----------------------------------------------------------------
  5365.  
  5366.           SUCCEED                          Match always
  5367.  
  5368.             This pattern matches the null string and always succeeds.  If
  5369.           the scanner is backtracking when it encounters SUCCEED, it re-
  5370.           verses and starts forward again.  Placing a pattern between
  5371.           SUCCEED and FAIL causes the pattern matcher to oscillate.
  5372.  
  5373.  
  5374.                                  9.5 OTHER FUNCTIONS
  5375.  
  5376.             I'd like to briefly point out a few more built-in functions.
  5377.           See Chapter 19 for a complete description of their use.
  5378.  
  5379.              APPLY            Allows an indirect call to a function through
  5380.                               a variable.
  5381.  
  5382.              CONVERT          Provides explicit conversion from one data
  5383.                               type to another.  Chapter 17, "Data Types and
  5384.                               Conversion," describes the conversions
  5385.                               possible.
  5386.  
  5387.              ENDFILE          Closes a file and detaches all variables
  5388.                               associated with it.
  5389.  
  5390.              ITEM             Allows an indirect reference to an array or
  5391.                               table.
  5392.  
  5393.              LPAD & RPAD      These are padding functions, which will pad a
  5394.                               string on its left or right side with blanks
  5395.                               or a given character.  Padding is provided to
  5396.                               a specified width, and is useful when produc-
  5397.                               ing columnar output.
  5398.  
  5399.  
  5400.  
  5401.  
  5402.  
  5403.  
  5404.  
  5405.        Tutorial                        - 82 -                 Advanced Topics
  5406.  
  5407.  
  5408.  
  5409.  
  5410.  
  5411.                               9.6 OTHER UNARY OPERATORS
  5412.  
  5413.  
  5414.           Operation:     Negation
  5415.           Symbol:        ~ (tilde)
  5416.  
  5417.             The negation operator, or tilde (~), inverts the success or
  5418.           failure result of its operand.  If the expression X succeeds,
  5419.           then ~X fails.  Conversely, if X fails, ~X succeeds and returns
  5420.           the null string.
  5421.  
  5422.  
  5423.           Operation:     Interrogation
  5424.           Symbol         ? (question mark)
  5425.  
  5426.             Unary question mark is called the interrogation operator, al-
  5427.           though "value annihilation" might be more descriptive.  If X is
  5428.           an expression which fails, ?X also fails.  However, if X suc-
  5429.           ceeds, ?X also succeeds, and returns the null string.  In other
  5430.           words, any value component of X is replaced by the null string.
  5431.  
  5432.  
  5433.                               9.7 RUN-TIME COMPILATION
  5434.  
  5435.             The two functions described below are among the most esoteric
  5436.           features, not just of SNOBOL4, but of all programming languages
  5437.           in existence.  While your program is executing, the entire
  5438.           SNOBOL4 compiler is just a function call away.
  5439.  
  5440.             A SNOBOL4 program is nothing more than a string of characters.
  5441.           The functions EVAL and CODE let you supply the compiler with
  5442.           character strings from within the program itself.
  5443.  
  5444.  
  5445.           9.7.1 The EVAL Function
  5446.  
  5447.             This function is used to evaluate an expression.  Its argument
  5448.           may take a number of forms:
  5449.  
  5450.             1. If the argument is an integer, or a number in string form,
  5451.                the number is returned as the function result:
  5452.  
  5453.                ?       OUTPUT = EVAL(19)
  5454.                19
  5455.  
  5456.             2. If the argument is an unevaluated expression, it is evalu-
  5457.                ated using current values for any variables it might con-
  5458.                tain.  EVAL returns the expression's value as its result:
  5459.  
  5460.                ?       E = *('N SQUARED IS ' N ** 2)
  5461.                ?       N = 15
  5462.                ?       OUTPUT = EVAL(E)
  5463.                N SQUARED IS 225
  5464.  
  5465.  
  5466.  
  5467.  
  5468.        Tutorial                        - 83 -                 Advanced Topics
  5469.  
  5470.  
  5471.  
  5472.  
  5473.  
  5474.                This is similar to our earlier use of unevaluated expres-
  5475.                sions with patterns.  In this case, however, the unevaluated
  5476.                expression operator (*) must be applied to the entire ex-
  5477.                pression to create an object with the EXPRESSION data type.
  5478.  
  5479.             3. If the argument is a string (other than a simple number),
  5480.                EVAL tries to compile it as a SNOBOL4 expression.  Only an
  5481.                expression is permitted---not an entire SNOBOL4 statement:
  5482.  
  5483.                ?       OUTPUT = EVAL('3 * N + 2')
  5484.                47
  5485.  
  5486.                If the string compiles without error, EVAL then evaluates
  5487.                the expression and returns the result.
  5488.  
  5489.             It is this last use of EVAL---to compile a string---which is
  5490.           the most interesting.  Here is a trivial program which behaves
  5491.           like a simple desk calculator.
  5492.  
  5493.                LOOP    OUTPUT = EVAL(INPUT)                 :S(LOOP)
  5494.                END
  5495.  
  5496.             You can easily try it by placing a semicolon after the GOTO to
  5497.           protect it from CODE.SNO's own machinations:
  5498.  
  5499.                ?LOOP   OUTPUT = EVAL(INPUT)                 :S(LOOP);
  5500.                4 * (5 - 2) / 2
  5501.                6
  5502.                N + 1
  5503.                16
  5504.                ^Z
  5505.  
  5506.             The program reads a line of input, compiles and evaluates it,
  5507.           and displays the result.  Each expression you enter must be well-
  5508.           formed according to SNOBOL4's syntax rules.  In particular, this
  5509.           means there must be blanks around the binary operators.
  5510.  
  5511.             The BNF program included with Vanilla SNOBOL4 demonstrates that
  5512.           EVAL's power is useful even if the input data does not conform to
  5513.           SNOBOL4 syntax.  It reads a definition of a grammar from a file,
  5514.           and converts it to SNOBOL4 patterns.
  5515.  
  5516.             EVAL fails if evaluation of the argument fails, or if the argu-
  5517.           ment contains a syntax error.  The SNOBOL4 keyword &ERRTEXT will
  5518.           contain a string describing the error.
  5519.  
  5520.             The expressions used with EVAL may return any SNOBOL4 data
  5521.           type, not just numbers.  For instance, the expression might con-
  5522.           struct a new pattern, and return it as the result:
  5523.  
  5524.                        ITEM = EVAL('SPAN("0123456789") | *LIST')
  5525.  
  5526.             Note that EVAL can only call the compiler with a string argu-
  5527.           ment.  If we used a pattern as the argument, we would produce an
  5528.  
  5529.  
  5530.  
  5531.        Tutorial                        - 84 -                 Advanced Topics
  5532.  
  5533.  
  5534.  
  5535.  
  5536.  
  5537.           execution error:
  5538.  
  5539.                        ITEM = EVAL(SPAN("0123456789") | *LIST)  (incorrect)
  5540.  
  5541.  
  5542.           9.6.2 The CODE Function
  5543.  
  5544.             CODE accepts a string argument containing one or more state-
  5545.           ments to be compiled.  Multiple statements are separated by
  5546.           semicolons (;).  Statements may be labeled, and can include all
  5547.           the usual components---subject, pattern, replacement, and GOTO.
  5548.           However, comment and continuation statements are not permitted.
  5549.  
  5550.             The CODE function compiles the statements, and returns a poin-
  5551.           ter to the resulting object code.  It fails if any statement
  5552.           contains an error, and places an error message in &ERRTEXT.
  5553.  
  5554.             There are two ways to execute the new object code.
  5555.  
  5556.             1. Transfer to a label which is defined in the new code:
  5557.  
  5558.                *  Compile a sample piece of code:
  5559.                        S = 'L OUTPUT = N; N = LT(N,10) N + 1  :S(L)F(DONE)'
  5560.                        CODE(S)
  5561.                *  Transfer to a label in it:
  5562.                                                               :(L)
  5563.                *  Come here when the new code transfers back.
  5564.                DONE     . . .
  5565.  
  5566.                Notice how we placed a GOTO from the new code back to label
  5567.                DONE in the main program.  If we had not done this, SNOBOL4
  5568.                would terminate when execution "fell out of the bottom" of
  5569.                the new code block.
  5570.  
  5571.             2. The pointer returned by the CODE function can be used in a
  5572.                "direct GOTO" to transfer to the first statement in the code
  5573.                block.  A direct GOTO is performed by enclosing the pointer
  5574.                in angular brackets in the GOTO field:
  5575.  
  5576.                *  Compile a sample piece of code:
  5577.                        S = 'L OUTPUT = N; N = LT(N,10) N + 1  :S(L)F(DONE)'
  5578.                        C = CODE(S)
  5579.                *  Transfer to the first statement in the block:
  5580.                                                               :<C>
  5581.                DONE     . . .
  5582.  
  5583.             Labels contained in the new program fragment override any
  5584.           labels of the same name in your main program.  This provides the
  5585.           ability to write self-modifying SNOBOL4 programs, and makes the
  5586.           division between "code" and "data" far less distinct than in
  5587.           other high-level languages.
  5588.  
  5589.  
  5590.  
  5591.  
  5592.  
  5593.  
  5594.        Tutorial                        - 85 -                 Advanced Topics
  5595.  
  5596.  
  5597.  
  5598.  
  5599.  
  5600.                                                                  Chapter 10
  5601.  
  5602.  
  5603.                                            DEBUGGING AND PROGRAM EFFICIENCY
  5604.           -----------------------------------------------------------------
  5605.  
  5606.  
  5607.                              10.1 DEBUGGING AND TRACING
  5608.  
  5609.             You are probably well aware of the diversity of potential er-
  5610.           rors when writing computer programs.  They range from simple
  5611.           typographical errors made while entering a program, to subtle de-
  5612.           sign problems which may only be revealed by unexpected input
  5613.           data.
  5614.  
  5615.             Debugging a SNOBOL4 program is not fundamentally different than
  5616.           debugging programs written in other languages.  However,
  5617.           SNOBOL4's syntactic flexibility and lack of type declarations for
  5618.           variables produce some unexpected problems.  By way of compensa-
  5619.           tion, an unusually powerful trace capability is provided.
  5620.  
  5621.             Of course, there may come a time when you can't explain your
  5622.           program's behavior, and decide "the system" is at fault.  No
  5623.           guarantee can ever be made that SNOBOL4 is completely free of
  5624.           errors.  However, its internal algorithms have been in use in
  5625.           other SNOBOL4 systems since 1967, and all known errors have been
  5626.           removed.  Often the problem is a misunderstanding of how a func-
  5627.           tion works with exceptional data, and a close reading of the ref-
  5628.           erence section clears the problem up.  In short, suspect the
  5629.           system last.
  5630.  
  5631.  
  5632.           10.1.1 Compilation Errors
  5633.  
  5634.             Compilation errors are the simplest to find; SNOBOL4 displays
  5635.           the erroneous line on your screen with its statement number, and
  5636.           places a marker below the point where the error was encountered.
  5637.           The source file name, line number, and column number of the error
  5638.           are displayed for use by your text editor.  Only the first error
  5639.           in a statement is identified, so you should also carefully check
  5640.           the remainder of the statement.  A typical line looks like this:
  5641.  
  5642.                32              ,OUTPUT = CNT+ 1
  5643.                                 ^
  5644.                test.sno(57,10) : Compilation Error : Erroneous statement
  5645.  
  5646.             Here, the comma preceding the word OUTPUT is misplaced.  The
  5647.           message indicates that ",OUTPUT" is not a valid language element.
  5648.  
  5649.             Programs containing compilation errors can still be run, at
  5650.           least until a statement containing an error is encountered.  When
  5651.           that happens, SNOBOL4 will produce an execution error message,
  5652.           and stop.
  5653.  
  5654.  
  5655.  
  5656.  
  5657.        Tutorial                        - 86 -        Debugging and Efficiency
  5658.  
  5659.  
  5660.  
  5661.  
  5662.  
  5663.             A complete description of error messages is provided in Chapter
  5664.           20, "System Messages."
  5665.  
  5666.  
  5667.           10.1.2 Execution Errors
  5668.  
  5669.             Once a program compiles without error, testing can begin.  Two
  5670.           kinds of errors are possible: SNOBOL4 detectable errors, such an
  5671.           incorrect data type or calling an undefined function, and program
  5672.           logic errors that produce incorrect results.
  5673.  
  5674.             With the first type of error, you'll get a SNOBOL4 error mes-
  5675.           sage with statement and line numbers.  Inspecting the offending
  5676.           line will often reveal typing errors, such as a misspelled func-
  5677.           tion name, keyword, or label.  If the error is due to incorrect
  5678.           data in a variable---such as trying to perform arithmetic on a
  5679.           non-numeric string---you'll have to start debugging to discover
  5680.           how the incorrect data was created.  Placing output statements in
  5681.           your program, or using the trace techniques described below, will
  5682.           usually find such errors.
  5683.  
  5684.             Here are some common errors to look for first:
  5685.  
  5686.             1. Setting keywords &ANCHOR, &FULLSCAN, and &TRIM improperly.
  5687.                We may have written a program with anchored pattern matching
  5688.                in mind, but let an unanchored match slip in inadvertently.
  5689.                Forgetting to set &TRIM to 1 causes blanks to be appended to
  5690.                input lines, and they usually interfere with pattern match-
  5691.                ing and conversion of a string to an integer.
  5692.  
  5693.             2. Misspelled variable names.  Using PUTPUT instead of OUTPUT,
  5694.                as in:
  5695.  
  5696.                        PUTPUT = LINE1
  5697.  
  5698.                creates a new variable and assigns LINE1 to it.  Worse still
  5699.                is using a misspelled name as a value source, since it will
  5700.                return a null string value.
  5701.  
  5702.                The first type of error is relatively easy to find---produce
  5703.                an end-of-run dump by using the SNOBOL4 command line option
  5704.                /D.  You can study the list of variables for an unexpected
  5705.                name.  The second type of error is naturally much harder to
  5706.                find, because variables with null string values are omitted
  5707.                from the end-of-run dump.  In this case, you will have to
  5708.                study the source program closely for misspellings.
  5709.  
  5710.             3. Spurious spaces between a function name and its argument
  5711.                list.  A line like:
  5712.  
  5713.                        LINE = TRIM (INPUT)
  5714.  
  5715.                is not a call to the TRIM function.  The blank between TRIM
  5716.                and the left parenthesis is interpreted as concatenating
  5717.  
  5718.  
  5719.  
  5720.        Tutorial                        - 87 -        Debugging and Efficiency
  5721.  
  5722.  
  5723.  
  5724.  
  5725.  
  5726.                variable TRIM with the expression (INPUT).  TRIM used as a
  5727.                variable is likely to be the null string, so INPUT is
  5728.                returned unchanged.
  5729.  
  5730.             4. No blank space after a binary operator.   SNOBOL4 sees a
  5731.                unary operator instead, with completely unexpected results.
  5732.                For instance:
  5733.  
  5734.                        X = Y -Z
  5735.  
  5736.                concatenates Y with the expression -Z.
  5737.  
  5738.             5. Confusion occurring when a variable contains a number in
  5739.                string form.  When used as an argument to most functions,
  5740.                conversion from string to number is automatic, and proper
  5741.                execution results.  However, functions IDENT and DIFFER do
  5742.                not convert their arguments, and seemingly equal values are
  5743.                thought to be different.  For example, if we want to test an
  5744.                input line for the number 3, the statements:
  5745.  
  5746.                        N = INPUT
  5747.                        IDENT(N, 3)                               :S(OK)
  5748.  
  5749.                are not correct.  N contains a string, which is a different
  5750.                data type from the integer 3.  This could be corrected by
  5751.                using IDENT(+N, 3), or EQ(N, 3).  Once again, &TRIM should
  5752.                be 1, or the blanks appended to N will prevent its conver-
  5753.                sion to an integer.
  5754.  
  5755.             6. Omitting the assignment operator when we wish to remove the
  5756.                matching substring from a subject, resulting in a program
  5757.                which loops forever.  For example, our word-counting program
  5758.                replaced each word with the null string:
  5759.  
  5760.                NEXTWRD LINE WRDPAT =                        :F(READ)
  5761.  
  5762.                However, by omitting the equal sign we would repeatedly find
  5763.                the same first word in LINE:
  5764.  
  5765.                NEXTWRD LINE WRDPAT                          :F(READ)
  5766.  
  5767.             7. Unexpected statement failure, with no provision for detect-
  5768.                ing it in the GOTO field.  For example, the CONVERT function
  5769.                fails if the table being converted is empty:
  5770.  
  5771.                        RESULT = CONVERT(TALLY, "ARRAY")
  5772.  
  5773.                RESULT will not be set if CONVERT fails, and a subsequent
  5774.                array reference to RESULT would produce an execution error.
  5775.  
  5776.             8. Failure can be detected but misinterpreted when there are
  5777.                several causes for it in a statement.  This statement fails
  5778.                when an End-of-File is read, or if the input line does not
  5779.                contain any digits:
  5780.  
  5781.  
  5782.  
  5783.        Tutorial                        - 88 -        Debugging and Efficiency
  5784.  
  5785.  
  5786.  
  5787.  
  5788.  
  5789.                        INPUT SPAN('0123456789') . N         :F(EOF)
  5790.  
  5791.                In the latter case, if we want to generate an error message,
  5792.                the statement should be split in two:
  5793.  
  5794.                        N = INPUT                            :F(EOF)
  5795.                        N SPAN('0123456789') . N             :F(WARN)
  5796.  
  5797.             9. Using operators such as alternation (|) and conditional as-
  5798.                signment (.) for purposes other than pattern construction.
  5799.                Using them in the subject field will produce an 'Illegal
  5800.                data type' error message.  Using them in the replacement
  5801.                field produces a pattern, intended for subsequent use in a
  5802.                pattern match statement.  For example, this statement sets N
  5803.                to a pattern; it does not replace it with the words 'EVEN'
  5804.                or 'ODD', as was probably intended:
  5805.  
  5806.                        N = EQ(REMDR(N,2),0) 'EVEN' | 'ODD'
  5807.  
  5808.                We note in passing that SNOBOL4+, Catspaw's professional
  5809.                SNOBOL4 package, provides language extensions that allow
  5810.                just that:
  5811.  
  5812.                        N = (EQ(REMDR(N,2),0) 'EVEN', 'ODD')
  5813.  
  5814.             10 Forgetting that functions like TAB and BREAK bind subject
  5815.                characters.  This won't matter for simple pattern matching,
  5816.                but for matching with replacement, problems can appear.  For
  5817.                example, suppose we wanted to replace the 50th character in
  5818.                string S with '*'.  If we used:
  5819.  
  5820.                        S TAB(49) LEN(1) = '*'
  5821.  
  5822.                we would find the first 50 characters replaced by a single
  5823.                asterisk.  Instead, we should say:
  5824.  
  5825.                        S POS(49) LEN(1) = '*'
  5826.  
  5827.                or, even more efficiently:
  5828.  
  5829.                        S TAB(49) . FRONT LEN(1) = FRONT '*'
  5830.  
  5831.             11 Omitting the unevaluated expression operator when defining a
  5832.                pattern containing variable arguments.  For example, the
  5833.                pattern
  5834.  
  5835.                        NTH_CHAR = POS(*N - 1) LEN(1) . CHAR
  5836.  
  5837.                will copy the Nth subject character to variable CHAR.  The
  5838.                pattern adjusts automatically if N's value is subsequently
  5839.                changed.  Omitting the asterisk would capture the value of N
  5840.                at the time the pattern is defined (probably the null
  5841.                string).
  5842.  
  5843.  
  5844.  
  5845.  
  5846.        Tutorial                        - 89 -        Debugging and Efficiency
  5847.  
  5848.  
  5849.  
  5850.  
  5851.  
  5852.           10.1.3 Simple Debugging
  5853.  
  5854.             These simple methods should find a majority of your bugs:
  5855.  
  5856.             1. Set keyword &DUMP nonzero, or use command line option /D to
  5857.                get an end-of-run dump.  Examine it closely for reasonable
  5858.                values and variable names.  Dumps can also be produced at
  5859.                any time during execution by calling the built-in function
  5860.                DUMP.
  5861.  
  5862.             2. Use keyword &STLIMIT to end execution after a fixed number
  5863.                of statements.
  5864.  
  5865.             3. Use the keyboard Control-C key to interrupt a program which
  5866.                is looping endlessly, and record the statement number.
  5867.  
  5868.             4. Use the GOTO :F(ERROR) to detect unexpected failures and
  5869.                data errors.  Do not define the label ERROR---SNOBOL4 will
  5870.                display the statement number of the error if an attempt is
  5871.                made to transfer to label ERROR.
  5872.  
  5873.             5. Assign values to OUTPUT to monitor data values.  Use immedi-
  5874.                ate assignment and cursor assignment (to OUTPUT) to observe
  5875.                the operation of a pattern match.
  5876.  
  5877.             6. Produce end-of-run statistics with the command line option
  5878.                /S.  Are the number and kind of operations reasonable?
  5879.  
  5880.             7. Use the CODE.SNO program to setup simple test cases.  This
  5881.                is particularly useful when pattern-matching statements do
  5882.                not behave as expected.
  5883.  
  5884.             More subtle errors can be pinpointed using SNOBOL4's trace fa-
  5885.           cility, described below.
  5886.  
  5887.  
  5888.                                10.2 EXECUTION TRACING
  5889.  
  5890.             Tracing the flow of control and data in a program is usually
  5891.           the best way to find difficult problems.  SNOBOL4 allows tracing
  5892.           of data in variables and some keywords, transfers of control to
  5893.           specified labels, and function calls and returns.  Two keywords
  5894.           control tracing: &FTRACE and &TRACE.
  5895.  
  5896.  
  5897.           10.2.1 Function Tracing
  5898.  
  5899.             Keyword &FTRACE is set nonzero to produce a trace message each
  5900.           time a program-defined function is called or returns.  The trace
  5901.           message displays the statement number where the action occurred,
  5902.           the name of the function, and the values of its arguments.  Func-
  5903.           tion returns display the type of return and value, if any.  Each
  5904.           trace message decrements &FTRACE by one, and tracing ends when
  5905.           &FTRACE reaches zero.  A typical trace messages looks like this:
  5906.  
  5907.  
  5908.  
  5909.        Tutorial                        - 90 -        Debugging and Efficiency
  5910.  
  5911.  
  5912.  
  5913.  
  5914.  
  5915.                STATEMENT 39: LEVEL 0 CALL OF SHIFT('SKYBLUE',3),TIME = 140
  5916.                STATEMENT 12: LEVEL 1 RETURN OF SHIFT = 'BLUESKY',TIME = 141
  5917.  
  5918.             The level number is the overall function call depth.  The pro-
  5919.           gram execution time in tenths of a second is also provided.
  5920.  
  5921.  
  5922.           10.2.2 Selective Tracing
  5923.  
  5924.             Keyword &TRACE will also produce trace messages when it is set
  5925.           nonzero.  However, the TRACE function must be called to specify
  5926.           what is to be traced.  Tracing can be selectively ended by using
  5927.           the STOPTR function.  The TRACE function call takes the form:
  5928.  
  5929.                        TRACE(name, type, string, function)
  5930.  
  5931.             The name of the item being traced is specified using a string
  5932.           or the unary name operator.  Besides variables, it is also possi-
  5933.           ble to trace a particular element of an array or table:
  5934.  
  5935.                        TRACE('VAR1', ...
  5936.                        TRACE(.A<2,5>, ...
  5937.                        TRACE('SHIFT', ...
  5938.  
  5939.             "Type" is a string describing the kind of trace to be per-
  5940.           formed.  If omitted, a VALUE trace is assumed:
  5941.  
  5942.              'VALUE'          Trace whenever name has a value assigned to
  5943.                               it.  Assignment statements, as well as condi-
  5944.                               tional and immediate assignments within pat-
  5945.                               tern matching will all produce trace mes-
  5946.                               sages.
  5947.  
  5948.              'CALL'           Produce a trace whenever function name is
  5949.                               called.
  5950.  
  5951.              'RETURN'         Produce a trace whenever function name
  5952.                               returns.
  5953.  
  5954.              'FUNCTION'       Combine the previous two types: trace both
  5955.                               calls and returns of function name.
  5956.  
  5957.              'LABEL'          Produce a trace when a GOTO transfer to
  5958.                               statement name occurs.  Flowing sequentially
  5959.                               into the labeled statement does not produce a
  5960.                               trace.
  5961.  
  5962.              'KEYWORD'        Produce a trace when keyword name's value is
  5963.                               changed by the system.  The name is specified
  5964.                               without an ampersand.  Only keywords
  5965.                               &ERRTYPE, &FNCLEVEL, &STCOUNT, and &STFCOUNT
  5966.                               may be traced.
  5967.  
  5968.  
  5969.  
  5970.  
  5971.  
  5972.        Tutorial                        - 91 -        Debugging and Efficiency
  5973.  
  5974.  
  5975.  
  5976.  
  5977.  
  5978.             When the first argument is specified with the unary name opera-
  5979.           tor, the third argument, string, will be displayed to identify
  5980.           the item being traced:
  5981.  
  5982.                        TRACE(.T<"zip">, "VALUE", "Table entry 'zip'")
  5983.  
  5984.             The last argument, function, is usually omitted.  Its use is
  5985.           described in the next section.
  5986.  
  5987.             The form of trace message displayed for each type of trace is
  5988.           listed in Chapter 20, "System Messages."
  5989.  
  5990.             Each time a trace is performed, keyword &TRACE is decreased by
  5991.           one.  Tracing stops when it reaches zero.  Tracing of a particu-
  5992.           lar item can also be stopped by function STOPTR:
  5993.  
  5994.                        STOPTR(name, type)
  5995.  
  5996.  
  5997.           10.2.4 Program Trace Functions
  5998.  
  5999.             Normally, each trace action displays a descriptive message,
  6000.           such as:
  6001.  
  6002.                STATEMENT 371: SENTENCE = 'Ed ran to town',TIME = 810
  6003.  
  6004.             Instead, we can instruct SNOBOL4 to call our own program-
  6005.           defined function.  This allows us to perform whatever trace
  6006.           actions we wish.  We define the trace function in the normal way,
  6007.           using DEFINE, and then specify its name as the fourth argument of
  6008.           TRACE.  For example, if we want function TRFUN called whenever
  6009.           variable COUNT is altered, we would say:
  6010.  
  6011.                        &TRACE = 10000
  6012.                        TRACE('COUNT', 'VALUE', , 'TRFUN')
  6013.                        DEFINE('TRFUN(NAME,ID)')             :(TRFUN_END)
  6014.                         . . .
  6015.  
  6016.             TRFUN will be called with the name of the item being traced,
  6017.           'COUNT', as its first argument.  If a third argument was provided
  6018.           with TRACE, it too is passed to your trace function, as ID.
  6019.           (Here the argument was omitted.)  To use trace functions effec-
  6020.           tively, we must pause to describe a few more SNOBOL4 keywords:
  6021.  
  6022.              &LASTNO          The statement number of the previous SNOBOL4
  6023.                               statement executed.
  6024.  
  6025.              &STCOUNT         The total number of statements executed.
  6026.                               Incremented by one as each statement begins
  6027.                               execution.
  6028.  
  6029.              &ERRTYPE         Error message number of the last execution
  6030.                               error.
  6031.  
  6032.  
  6033.  
  6034.  
  6035.        Tutorial                        - 92 -        Debugging and Efficiency
  6036.  
  6037.  
  6038.  
  6039.  
  6040.  
  6041.              &ERRLIMIT        Number of nonfatal execution errors allowed
  6042.                               before SNOBOL4 will terminate.
  6043.  
  6044.             The first three keywords are continuously updated by SNOBOL4 as
  6045.           a program is executed.
  6046.  
  6047.             Now, let's consider debugging a program where variable COUNT is
  6048.           inexplicably being set to a negative number.  Continuing with the
  6049.           previous example, the function body would look like this:
  6050.  
  6051.                        &TRACE = 10000
  6052.                        TRACE('COUNT', 'VALUE', , 'TRFUN')
  6053.                        DEFINE('TRFUN(NAME,ID)TEMP')         :(TRFUN_END)
  6054.                
  6055.                TRFUN   TEMP = &LASTNO
  6056.                        GE($NAME, 0)                         :S(RETURN)
  6057.                        OUTPUT = 'COUNT negative in statement ' TEMP  :(END)
  6058.                TRFUN_END
  6059.  
  6060.             The first statement of the function captures the number of the
  6061.           last statement executed---the statement that triggered the trace.
  6062.           We then check COUNT, and return if it is satisfactory.  If it is
  6063.           negative, we print an error message and stop the program.
  6064.  
  6065.             When a trace function is invoked, keywords &TRACE and &FTRACE
  6066.           are temporarily set to zero.  Their values are restored when the
  6067.           trace function returns.  There is no limit to the number of func-
  6068.           tions or items which may be traced.
  6069.  
  6070.             Tracing keyword &STCOUNT will call your trace function before
  6071.           every program statement is executed.
  6072.  
  6073.             Program CODE.SNO traces keyword &ERRTYPE to trap nonfatal exe-
  6074.           cution errors from your sample statements, and produce an error
  6075.           message.  Keyword &ERRLIMIT must be set nonzero to prevent
  6076.           SNOBOL4 from terminating when an error occurs.
  6077.  
  6078.  
  6079.                                10.3 PROGRAM EFFICIENCY
  6080.  
  6081.             To a greater extent than other languages, SNOBOL4 programs are
  6082.           sensitive to programming methods.  Often, there are many differ-
  6083.           ent ways to formulate a pattern match, and some will require many
  6084.           more match attempts than others.
  6085.  
  6086.             As you work with SNOBOL4, you will develop an intuitive feel
  6087.           for the operation of the pattern matcher, and will write more
  6088.           efficient patterns.  I can, however, start you off with some gen-
  6089.           eral rules:
  6090.  
  6091.             1. Try to use anchored, quickscan, and trim modes when possi-
  6092.                ble.  If operating unanchored, artificially anchor whenever
  6093.                possible by using POS(0) or FENCE as the first subpattern.
  6094.  
  6095.  
  6096.  
  6097.  
  6098.        Tutorial                        - 93 -        Debugging and Efficiency
  6099.  
  6100.  
  6101.  
  6102.  
  6103.  
  6104.             2. Try to use BREAK and SPAN instead of ARB.
  6105.  
  6106.             3. Use ANY instead of an explicit list of one-character strings
  6107.                and the alternation operator.
  6108.  
  6109.             4. LEN, TAB and RTAB are faster than POS and RPOS.  The former
  6110.                "step over" subject characters in one operation; the latter
  6111.                continually fail until the subject cursor is positioned cor-
  6112.                rectly.  But be careful of misusing them with replacement
  6113.                and replacing more than you expected.
  6114.  
  6115.             5. Use conditional assignment instead of immediate assignment
  6116.                in pattern matching.
  6117.  
  6118.             6. Use IDENT and DIFFER to compare strings for equality,
  6119.                instead of pattern matching.  Since each unique string is
  6120.                stored only once in SNOBOL4, these functions merely compare
  6121.                one-word pointers, regardless of string length.  By con-
  6122.                trast, pattern matching and functions such as LGT must
  6123.                perform character by character comparisons.
  6124.  
  6125.             7. Avoid ARBNO and recursion if possible.
  6126.  
  6127.             8. Pattern construction is time-consuming.  Preconstruct pat-
  6128.                terns and store them in variables whenever possible.
  6129.  
  6130.             9. Keep strings modest in length.  Although SNOBOL4 allows
  6131.                strings to be thousands of characters long, operating upon
  6132.                them is very time-consuming.  They use large amounts of
  6133.                memory, and force SNOBOL4 to frequently rearrange storage.
  6134.  
  6135.             10 Use functions to modularize a program and make it easier to
  6136.                understand and maintain.
  6137.  
  6138.             11 Avoid algorithms that make a linear search of an array or
  6139.                list.  The algorithms can usually be rewritten using tables
  6140.                and indirect references for associative programming.
  6141.  
  6142.             Efficiency should not be measured purely in terms of program
  6143.           execution time.  With the relatively low cost of microcomputers,
  6144.           the larger picture of time spent designing, coding, and debugging
  6145.           a program also must be considered.  A direct approach, empha-
  6146.           sizing simplicity, robustness, and ease of understanding usually
  6147.           outweighs the advantages of tricky algorithms and shortcut tech-
  6148.           niques.  (But we admit that tricky pattern matching is fun!)
  6149.  
  6150.  
  6151.  
  6152.  
  6153.  
  6154.  
  6155.  
  6156.  
  6157.  
  6158.  
  6159.  
  6160.  
  6161.        Tutorial                        - 94 -        Debugging and Efficiency
  6162.  
  6163.  
  6164.  
  6165.  
  6166.  
  6167.                                                                  Chapter 11
  6168.  
  6169.  
  6170.                                                          CONCLUDING REMARKS
  6171.           -----------------------------------------------------------------
  6172.  
  6173.             For much of this tutorial we've been concerned with the de-
  6174.           tailed mechanics of pattern matching---the functions, primitive
  6175.           patterns, and heuristics of applying a pattern to a character
  6176.           string.  SNOBOL4 provides so many primitive functions and opera-
  6177.           tions that it's easy to get lost in the forest.  Let's step back
  6178.           and consider SNOBOL4's larger significance.
  6179.  
  6180.             It would be a mistake to think of SNOBOL4 only as a text pro-
  6181.           cessing language.  For example, programmers in the artificial
  6182.           intelligence field think in terms of lists, and have used the
  6183.           LISP language for some time.  As Shafto demonstrates, SNOBOL4 can
  6184.           be made to emulate LISP, and go well beyond it, using pattern
  6185.           matching, backtracking, and associative programming (see file
  6186.           SNOBOL4.DOC for information on Shafto's report on AI SNOBOL4
  6187.           programming.)
  6188.  
  6189.             SNOBOL4's pattern matching provides a very powerful and com-
  6190.           pletely general recognition system, in which character strings
  6191.           happen to be the medium of expression.  Other recognition pro-
  6192.           blems can be solved by mapping the object to be examined into a
  6193.           subject string, and the recognition criteria into SNOBOL4
  6194.           patterns.
  6195.  
  6196.             In the past, use of SNOBOL4 has been hindered by the high cost
  6197.           and inconvenience of running it on mainframe computers.  Now it's
  6198.           on your desk top, with computer time essentially free.
  6199.  
  6200.             What new insights can SNOBOL4 bring to your problems?  Can you
  6201.           find other general applications for SNOBOL4's unique abilities?
  6202.  
  6203.             The future of the language is in your hands.
  6204.  
  6205.  
  6206.  
  6207.  
  6208.  
  6209.  
  6210.  
  6211.  
  6212.  
  6213.  
  6214.  
  6215.  
  6216.  
  6217.  
  6218.  
  6219.  
  6220.  
  6221.  
  6222.  
  6223.  
  6224.        Tutorial                        - 95 -              Concluding Remarks
  6225.  
  6226.  
  6227.  
  6228.  
  6229.  
  6230.                                                                  Chapter 12
  6231.  
  6232.  
  6233.                                            REFERENCE MANUAL -- INTRODUCTION
  6234.           -----------------------------------------------------------------
  6235.  
  6236.             The reference section describes the SNOBOL4 system.  It will
  6237.           tell you how to create and run SNOBOL4 programs, and catalogs all
  6238.           the standard language features.  The tutorial section can be con-
  6239.           sulted for illustrative uses of various functions and operators.
  6240.  
  6241.             SNOBOL4 is a full implementation of the powerful development
  6242.           language SNOBOL4 for the IBM PC and the entire 8086/286/386 fam-
  6243.           ily of computers.  It has all the features of mainframe SNOBOL4,
  6244.           plus numerous useful extensions.  Compatibility with mainframe
  6245.           SNOBOL4 is achieved by basing this product on the Macro Implemen-
  6246.           tation used on such mainframes as the IBM 370 and the CDC 7600.
  6247.           Thus, it incorporates a thoroughly tested implementation in its
  6248.           entirety.  All SNOBOL4 string and pattern matching facilities
  6249.           available in the mainframe environment are now available to the
  6250.           personal computer user.
  6251.  
  6252.             The SNOBOL4 program contains both a compiler and interpreter.
  6253.           They are inseparable, and share many common routines.  Your
  6254.           source program is compiled into a compact internal notation,
  6255.           which is interpreted during execution.  More information on the
  6256.           internal code may be found in Griswold's "The Macro Implementa-
  6257.           tion of SNOBOL4;" see file SNOBOL4.DOC for ordering information.
  6258.  
  6259.  
  6260.                               12.1 LANGUAGE BACKGROUND
  6261.  
  6262.             In 1962, several researchers at Bell Telephone Laboratories
  6263.           (BTL) were applying computers to problems such as factoring mul-
  6264.           tivariate polynomials and symbolic integration.  Available tools
  6265.           were the Symbolic Communication Language (SCL), an internal BTL
  6266.           product for processing symbolic expressions, and COMIT, designed
  6267.           for natural-language analysis.  Both proved inadequate, and
  6268.           frustration with them led the researchers to attempt the design
  6269.           of a new language.
  6270.  
  6271.             The original SNOBOL was developed by David J. Farber, Ralph E.
  6272.           Griswold, and Ivan P. Polonsky, and was first implemented on an
  6273.           IBM 7090 computer in 1963.  The name, SNOBOL, came after the im-
  6274.           plementation, and ostensibly stands for StriNg Oriented symBOlic
  6275.           Language.
  6276.  
  6277.             It was soon discovered that SNOBOL was applicable to a much
  6278.           wider range of problems.  In fact, the language proved more in-
  6279.           teresting than the problems it was intended to solve.  As more
  6280.           people used it, new features such as recursive functions were
  6281.           added, and its generality grew.  By 1964, it had become SNOBOL3,
  6282.           and was available on such machines as the IBM 7094, CDC 3600, SDS
  6283.           930, Burroughs 5500, and the RCA 601.  Because these implementa-
  6284.  
  6285.  
  6286.  
  6287.        Reference                       - 96 -                    Introduction
  6288.  
  6289.  
  6290.  
  6291.  
  6292.  
  6293.           tions were all written from scratch, each machine introduced its
  6294.           own dialect of the language.
  6295.  
  6296.             SNOBOL3 had only one data type, the string.  The desire for ad-
  6297.           ditional data types, more complex pattern matching, and other
  6298.           features led to a major redesign of the language in 1966, by
  6299.           Ralph Griswold, Jim Poage, and Ivan Polonsky.  The new lan-
  6300.           guage---SNOBOL4---was also designed to be portable to other
  6301.           machines.  Most of SNOBOL4 was completed by 1967, although some
  6302.           features, such as operator redefinition, did not appear until
  6303.           1969.  Portability was achieved by writing the system in a macro
  6304.           assembly language for an abstract machine, hence the name "Macro
  6305.           Implementation of SNOBOL4."  By 1970 it was available on nine
  6306.           different types of mainframes.  Currently, it is available on
  6307.           most large- and medium-scale computers.
  6308.  
  6309.             The SNOBOL4 language evolved on computers whose primary input/
  6310.           output devices were the card reader, card punch, and line
  6311.           printer.  The current breed of microcomputers are interactive,
  6312.           rather than batch-oriented.  Thus, SNOBOL4 contains slight alter-
  6313.           ations of the language to conform to the personal computer envi-
  6314.           ronment.  For example, the preassigned output keyword PUNCH has
  6315.           been replaced by SCREEN.  Experienced SNOBOL4 programmers will
  6316.           find little incompatibility with familiar implementations.  Most
  6317.           existing SNOBOL4 programs should operate correctly using SNOBOL4
  6318.           with little or no change.
  6319.  
  6320.  
  6321.  
  6322.  
  6323.  
  6324.  
  6325.  
  6326.  
  6327.  
  6328.  
  6329.  
  6330.  
  6331.  
  6332.  
  6333.  
  6334.  
  6335.  
  6336.  
  6337.  
  6338.  
  6339.  
  6340.  
  6341.  
  6342.  
  6343.  
  6344.  
  6345.  
  6346.  
  6347.  
  6348.  
  6349.  
  6350.        Reference                       - 97 -                    Introduction
  6351.  
  6352.  
  6353.  
  6354.  
  6355.  
  6356.                                                                  Chapter 13
  6357.  
  6358.  
  6359.                                                   RUNNING A SNOBOL4 PROGRAM
  6360.           -----------------------------------------------------------------
  6361.  
  6362.  
  6363.                            13.1 BASIC COMMAND LINE FORMAT
  6364.  
  6365.             The format for the command line is:
  6366.  
  6367.                SNOBOL4 file options ;Comments
  6368.  
  6369.             Options are specified by a slash (/) or minus sign (-), and one
  6370.           or more option letters.  When the option requires a file name, an
  6371.           equal sign may be used between the option letter and file name
  6372.           for readability.
  6373.  
  6374.              File             The source file contains your SNOBOL4 pro-
  6375.                               gram.  If no file is specified, CON: is as-
  6376.                               sumed, and programs may be entered directly
  6377.                               from the keyboard.  Disk files will have ex-
  6378.                               tension .SNO supplied if none is specified.
  6379.  
  6380.             The source and input files may be assigned to any disk file or
  6381.           valid input device.  The listing, output, and error message files
  6382.           may be assigned to any disk file or valid output device.  If the
  6383.           output disk file does not exist, it will be created.
  6384.  
  6385.              /I=file          The input file is associated with the vari-
  6386.                               able INPUT when execution begins, as I/O unit
  6387.                               5.  The default is CON:, your keyboard.  Disk
  6388.                               files will have extension .IN supplied if
  6389.                               none is specified.
  6390.  
  6391.              /L=file          The listing file receives a listing of your
  6392.                               program, with assigned statement numbers.
  6393.                               Default is NUL:, that is, the listing is dis-
  6394.                               carded.  If /L appears without a file name,
  6395.                               the source program file name will be used,
  6396.                               with the extension changed to .LST.
  6397.  
  6398.              /O=file          The output file is associated with the vari-
  6399.                               able OUTPUT when execution begins.  This will
  6400.                               be I/O unit 6.  The default is CON:, which is
  6401.                               usually your computer's display screen.  Disk
  6402.                               files will have extension .OUT supplied if
  6403.                               none is specified.  Execution dumps and trac-
  6404.                               ings are sent to I/O unit 6.
  6405.  
  6406.  
  6407.  
  6408.  
  6409.  
  6410.  
  6411.  
  6412.  
  6413.        Reference                       - 98 -       Running a SNOBOL4 Program
  6414.  
  6415.  
  6416.  
  6417.  
  6418.  
  6419.              /E=file          A list of compilation and runtime error mes-
  6420.                               sages is written to this file.  Default is
  6421.                               CON:, that is, error messages are displayed
  6422.                               on the screen.  If /E appears without a file
  6423.                               name, the source program file name will be
  6424.                               used, with the extension changed to .ERR.
  6425.  
  6426.             In addition to the /I and /O options, the INPUT and OUTPUT
  6427.           variables may also be assigned to files by using the MS-DOS redi-
  6428.           rection operators < and > on the command line.
  6429.  
  6430.             Other I/O files may be specified explicitly within the INPUT
  6431.           and OUTPUT functions, or on the command line with a unit number:
  6432.  
  6433.              /n=file          The specified file becomes associated with
  6434.                               unit number n.  N must be in integer between
  6435.                               1 and 16.  If your program calls the INPUT or
  6436.                               OUTPUT function without a file name, the file
  6437.                               specified here will be used.  This command
  6438.                               line option merely makes an association; the
  6439.                               file is not opened or created until the INPUT
  6440.                               or OUTPUT function is called.
  6441.  
  6442.             File names may be a disk file, or any DOS device, such as NUL:,
  6443.           CON:, LPT2:, etc.
  6444.  
  6445.             The remaining option switches alter SNOBOL4's behavior:
  6446.  
  6447.              /B               Termination messages and statistics are nor-
  6448.                               mally displayed via I/O unit 7 (SCREEN).  The
  6449.                               /B (batch) option instead directs them to I/O
  6450.                               unit 6 (OUTPUT).
  6451.  
  6452.              /C               SNOBOL4 defaults to case-folding, making
  6453.                               lower and upper case alphabetics equivalent
  6454.                               for names and labels.  Specifying this option
  6455.                               inhibits case-folding:  upper and lower case
  6456.                               names are unique and distinct.
  6457.  
  6458.              /D               Sets the &DUMP keyword to 1.  This is useful
  6459.                               when you decide you want an end-of-run vari-
  6460.                               able dump, and don't want to edit the source
  6461.                               file.
  6462.  
  6463.              /H               Displays summary of options and Vanilla
  6464.                               SNOBOL4 license information.
  6465.  
  6466.              /NX              No execution after compilation.
  6467.  
  6468.              /NP              Suppress column position information in error
  6469.                               messages.
  6470.  
  6471.              /P               Displays additional product information.
  6472.  
  6473.  
  6474.  
  6475.  
  6476.        Reference                       - 99 -       Running a SNOBOL4 Program
  6477.  
  6478.  
  6479.  
  6480.  
  6481.  
  6482.              /S               Provide statistics upon termination.
  6483.  
  6484.             Vanilla SNOBOL4 works very nicely with text editors that allow
  6485.           a program to be compiled from within the editor.  If a compila-
  6486.           tion or runtime error occurs, you are returned to your editor
  6487.           with the cursor positioned on the troublesome statement.  To use
  6488.           with your editor, you will need to use the command line option
  6489.           "/BE-".  This writes errors messages to standard output, where
  6490.           they can be captured by your text editor.
  6491.  
  6492.  
  6493.                          13.2 PROVIDING YOUR OWN PARAMETERS
  6494.  
  6495.             The keyword &PARM contains the command line string.  It begins
  6496.           with the blank following the word SNOBOL4, and contains all char-
  6497.           acters up to the terminating carriage return.  Since SNOBOL4's
  6498.           command processor ignores all characters after a semicolon, com-
  6499.           ments placed there can easily communicate additional instructions
  6500.           to your program.  Break them out with the statement:
  6501.  
  6502.                        &PARM ';' REM . INSTRUCTIONS
  6503.  
  6504.  
  6505.                              13.3 COMMAND LINE EXAMPLES
  6506.  
  6507.             The command line:
  6508.  
  6509.                SNOBOL4 PROG
  6510.  
  6511.           will compile and run a source program from file PROG.SNO, discard
  6512.           the listing, and run it with keyboard input and screen output.
  6513.           The command line:
  6514.  
  6515.                SNOBOL4 CONVERT /I=DATA /O=RESULT /2=STYLE.DAT ;DRAFT
  6516.  
  6517.           will run a program that presumably transforms input file DATA.IN
  6518.           to output file RESULT.OUT according to program option 'DRAFT'.
  6519.           I/O unit number 2 is associated with the file STYLE.DAT.  The
  6520.           program can use the variable SCREEN to post error and status mes-
  6521.           sages to the user, regardless of the reassignment of the input
  6522.           and output files.
  6523.  
  6524.                SNOBOL4 SOURCE /I=SOURCE.SNO /L=OUTPUT /O=OUTPUT.LST /BCS
  6525.  
  6526.           sets up a "conventional" batch job, with source program and input
  6527.           data on file SOURCE.SNO (following the END statement), listing
  6528.           and program output to OUTPUT.LST, no case-folding, and end-of-run
  6529.           statistics.
  6530.  
  6531.  
  6532.  
  6533.  
  6534.  
  6535.  
  6536.  
  6537.  
  6538.  
  6539.        Reference                      - 100 -       Running a SNOBOL4 Program
  6540.  
  6541.  
  6542.  
  6543.  
  6544.  
  6545.                                                                  Chapter 14
  6546.  
  6547.  
  6548.                                                                  STATEMENTS
  6549.           -----------------------------------------------------------------
  6550.  
  6551.             Each line of input to SNOBOL4 consists of a sequence of ASCII
  6552.           characters, terminated by a carriage return.
  6553.  
  6554.             Comment and control statements are always one line long.  How-
  6555.           ever, a program statement may occupy several lines if necessary.
  6556.           A continuation mark (plus sign or period) is placed in the first
  6557.           column of the additional lines.
  6558.  
  6559.  
  6560.                                14.1 COMMENT STATEMENTS
  6561.  
  6562.             An asterisk (*) in character position one denotes a comment
  6563.           card.  All text through the end-of-line is copied to the listing
  6564.           file, but is otherwise ignored by SNOBOL4.
  6565.  
  6566.  
  6567.                                14.2 CONTROL STATEMENTS
  6568.  
  6569.             Control statements provide instructions to the SNOBOL4 com-
  6570.           piler.  They begin with a minus (-) in character position one.
  6571.           Controls may be specified in upper- or lower-case, regardless of
  6572.           the current state of case-folding.  Unrecognized controls are
  6573.           ignored.
  6574.  
  6575.              -CASE n          Fold lower-case names to upper-case if n is
  6576.                               nonzero.  Treat upper- and lower-case names
  6577.                               as distinct if n is zero or absent.
  6578.  
  6579.              -EJECT           Start a new page on the listing file.
  6580.  
  6581.              -LIST            Equivalent to -LIST LEFT.
  6582.  
  6583.              -LIST LEFT       Turn on list output, produce statement num-
  6584.                               bers at left end of line.
  6585.  
  6586.              -LIST RIGHT      Turn on list output, produce statement num-
  6587.                               bers at right end of line.
  6588.  
  6589.              -UNLIST          Turn off list output.  Errors are not shown
  6590.                               on the screen.
  6591.  
  6592.             SNOBOL4 defaults to -LIST LEFT and -CASE 1.
  6593.  
  6594.  
  6595.                                14.3 PROGRAM STATEMENTS
  6596.  
  6597.             If a line is not a control or comment statement, it is consid-
  6598.           ered SNOBOL4 program text.  A SNOBOL4 statement may have up to
  6599.  
  6600.  
  6601.  
  6602.        Reference                      - 101 -                      Statements
  6603.  
  6604.  
  6605.  
  6606.  
  6607.  
  6608.           five components.  The general form of a statement is:
  6609.  
  6610.                LABEL  SUBJECT PATTERN = REPLACEMENT              :GOTO
  6611.  
  6612.             Statement elements are separated by blank or tab.
  6613.  
  6614.             Ignoring the LABEL and GOTO fields for a moment, the remaining
  6615.           elements may appear in various combinations to create different
  6616.           types of statements:
  6617.  
  6618.  
  6619.           Evaluate expression: SUBJECT
  6620.  
  6621.             The expression comprising the subject is evaluated.  It may in-
  6622.           voke primitive and program-defined functions.
  6623.  
  6624.  
  6625.           Assignment statement: SUBJECT = REPLACEMENT
  6626.  
  6627.             The value on the right is assigned to the variable on the left.
  6628.           If failure occurs when evaluating the subject or replacement com-
  6629.           ponents, the assignment does not occur.
  6630.  
  6631.  
  6632.           Pattern match: SUBJECT PATTERN
  6633.  
  6634.             The subject and pattern expressions are evaluated, and the
  6635.           specified pattern is applied to the subject string, producing
  6636.           success or failure.
  6637.  
  6638.  
  6639.           Pattern match with replacement: SUBJECT PATTERN = REPLACEMENT
  6640.  
  6641.             If the pattern match succeeds, the replacement expression is
  6642.           evaluated and replaces the portion of the subject matched.  Only
  6643.           the matched portion is replaced; characters adjacent to the
  6644.           matching substring are not disturbed.
  6645.  
  6646.             If the equal sign (=) is present but the replacement field is
  6647.           absent, the null string is assumed as the value of the replace-
  6648.           ment field.
  6649.  
  6650.             The GOTO field provides two-way branching to test the success
  6651.           or failure of the preceding statement elements.
  6652.  
  6653.  
  6654.           14.3.1 Label Field
  6655.  
  6656.             If a label is present, it must begin with the first character
  6657.           of the line.  Labels provide a name for the statement, and serve
  6658.           as the target for transfer of control from the GOTO field of any
  6659.           statement.  Labels must begin with a letter or digit, optionally
  6660.           followed by an arbitrary string of characters.  The label field
  6661.           is terminated by the character blank, tab, or semicolon.  If the
  6662.  
  6663.  
  6664.  
  6665.        Reference                      - 102 -                      Statements
  6666.  
  6667.  
  6668.  
  6669.  
  6670.  
  6671.           first character of a line is blank or tab, the label field is
  6672.           absent.
  6673.  
  6674.             If case-folding is in effect, lower-case letters are converted
  6675.           to upper-case before defining the label.
  6676.  
  6677.  
  6678.           14.3.2 Subject Field
  6679.  
  6680.             The subject field specifies the string which will be the sub-
  6681.           ject of pattern matching.  It also specifies the left side of a
  6682.           simple assignment statement if pattern matching is absent.
  6683.  
  6684.             In an assignment statement, the subject must be a variable
  6685.           name, an unprotected keyword, or a field-reference function from
  6686.           a program-defined data type.  If a string is produced by evaluat-
  6687.           ing an expression, the indirect ($) operator must be used to
  6688.           reference the underlying variable.
  6689.  
  6690.             If the subject appears in pattern matching without replacement,
  6691.           the subject must evaluate to a string.  The string is scanned
  6692.           left to right during the pattern match.  If the subject evaluates
  6693.           to an integer, it is automatically converted to a string.  If re-
  6694.           placement is present, the same subject restrictions of assignment
  6695.           statements apply.  Thus, a literal string is a valid subject only
  6696.           if replacement is absent.
  6697.  
  6698.             If the expression comprising the subject contains the concate-
  6699.           nation operator, the subject must be surrounded by parenthesis.
  6700.           This allows SNOBOL4 to distinguish concatenation blanks within
  6701.           the subject from the blank between subject and pattern.
  6702.  
  6703.  
  6704.           14.3.3 Pattern Field
  6705.  
  6706.             The pattern may be a simple string, or a complex expression in-
  6707.           volving primitive pattern functions.  The pattern specifies one
  6708.           or more strings which are systematically searched for in the sub-
  6709.           ject.  The pattern match succeeds if a match is found, and fails
  6710.           otherwise.  The &FULLSCAN keyword determines whether the search
  6711.           is exhaustive, or if heuristics will be applied to prevent futile
  6712.           match attempts.
  6713.  
  6714.             The pattern may assign various matching components to variables
  6715.           with the binary assignment operators dot and dollar sign (., $).
  6716.  
  6717.  
  6718.           14.3.4 Replacement Field
  6719.  
  6720.             In an assignment statement, there are very few restrictions on
  6721.           the replacement field.  If the subject is an unprotected keyword,
  6722.           the replacement field must evaluate to an integer value.  If the
  6723.           subject is a variable, the replacement field is assigned directly
  6724.           to it, without type conversion.
  6725.  
  6726.  
  6727.  
  6728.        Reference                      - 103 -                      Statements
  6729.  
  6730.  
  6731.  
  6732.  
  6733.  
  6734.             If there is pattern matching on the left side of the statement,
  6735.           the replacement field must evaluate to a string, so that it may
  6736.           be inserted into the matched portion of the subject string.
  6737.  
  6738.             Replacement occurs only if evaluation of the subject, pattern,
  6739.           and replacement succeed.  Primitive functions which return suc-
  6740.           cess or failure may be used in the replacement field as predicate
  6741.           functions.  Since they return the null string, they do not alter
  6742.           the replacement value.  However, their failure can prevent re-
  6743.           placement from occurring, and can be tested in the GOTO field.
  6744.  
  6745.  
  6746.           14.3.5 GOTO Field
  6747.  
  6748.             Statement execution normally proceeds sequentially from one
  6749.           statement to the next.  The GOTO field allows this flow to be al-
  6750.           tered by directing the SNOBOL4 system to continue execution else-
  6751.           where.  The GOTO field is set off from the preceding statement
  6752.           elements by blank or tab, and colon (:).  It may assume three
  6753.           forms:  unconditional, conditional, and direct.
  6754.  
  6755.             The "unconditional GOTO" causes control to be transferred to
  6756.           the specified labeled statement.  The label is enclosed in paren-
  6757.           thesis, and may be a name, or the result of evaluating an expres-
  6758.           sion and applying the indirect operator ($).  Transfer is made to
  6759.           the labeled statement regardless of the success or failure out-
  6760.           come of the earlier parts of the statement.
  6761.  
  6762.             The "conditional GOTO" similarly specifies control transfer to
  6763.           a labeled statement, but it depends on the success or failure of
  6764.           the statement.  The letter S precedes the parenthesized label
  6765.           where control goes next if the statement succeeds.  The letter F
  6766.           specifies the branch to be taken if the statement fails.  For
  6767.           example:
  6768.  
  6769.              :S(LOOP)         Branches to label LOOP if the statement suc-
  6770.                               ceeds.
  6771.  
  6772.              :F(ERROR)        Branches to label ERROR if the statement
  6773.                               fails.
  6774.  
  6775.              :S(OK) F(NOGO)   Branches to label OK on success, to NOGO on
  6776.                               failure.
  6777.  
  6778.              :(AGAIN)         Unconditionally transfers control to label
  6779.                               AGAIN.
  6780.  
  6781.              :($('VAR' N))    Branches to the label obtained by concatenat-
  6782.                               ing the string 'VAR' with the value of vari-
  6783.                               able N.
  6784.  
  6785.             The "direct GOTO" is used to branch to a block of code compiled
  6786.           with the CODE function.  If the code contains labels, a regular
  6787.           GOTO could branch to the label and begin execution in the code
  6788.  
  6789.  
  6790.  
  6791.        Reference                      - 104 -                      Statements
  6792.  
  6793.  
  6794.  
  6795.  
  6796.  
  6797.           block.  The direct GOTO will branch to the start of the code
  6798.           block, labeled or not.  A direct GOTO is specified by placing in
  6799.           angle brackets the name of the variable which points to the code
  6800.           block.
  6801.  
  6802.             Direct GOTOs may be made conditional by preceding them with S
  6803.           or F.  They may also appear with regular GOTOs:
  6804.  
  6805.                        VAR = CODE(string)         :S<VAR> F(COMPILE_ERROR)
  6806.  
  6807.             The lower-case letters "s" and "f" may be used interchangeably
  6808.           with "S" and "F", regardless of case-folding.
  6809.  
  6810.             The GOTO field may appear on a line without any subject, pat-
  6811.           tern, and replacement.  The absent SNOBOL4 statement is assumed
  6812.           to have succeeded.
  6813.  
  6814.  
  6815.                             14.4 CONTINUATION STATEMENTS
  6816.  
  6817.             A SNOBOL4 statement may be divided across several lines by
  6818.           placing a plus (+) or period (.) in character position one of the
  6819.           successive lines.  There is no limit to the number of continua-
  6820.           tion statements allowed.  The statement must be divided at a
  6821.           point where a blank or tab could appear as an operator or separa-
  6822.           tor; it cannot be split in the middle of a name or quoted string.
  6823.  
  6824.             Very long strings may be entered on multiple lines, using the
  6825.           implicit blank between lines as a concatenation operator:
  6826.  
  6827.                        LONG_STRING = "This is an example of a very long "
  6828.                +   "string that wends its way across multiple continua"
  6829.                +   "tion statements.  There is an implicit blank at the "
  6830.                +   "beginning of each line that provides the concatenation"
  6831.                +   " operator between segments."
  6832.  
  6833.  
  6834.                               14.5 MULTIPLE STATEMENTS
  6835.  
  6836.             The semicolon character may be used to place several statements
  6837.           on one line.  Each semicolon terminates the current statement and
  6838.           behaves like a new "column one" for the statement which follows.
  6839.           Only program statements are permitted after the semicolon; con-
  6840.           trol and continuation statements are not allowed.  Here are some
  6841.           examples:
  6842.  
  6843.                        I = 1;     J = 2;      S PAT = 'HENRI'       :S(YES)
  6844.                        I = 1;OUT  OUTPUT = A<I>  :F(END);  I = I + 1 :(OUT)
  6845.  
  6846.             Because of its poor readability, placing labels in the middle
  6847.           of a statement is strongly discouraged.
  6848.  
  6849.             As a language extension, Vanilla SNOBOL4 permits a comment
  6850.           statement after the semicolon.  This provides a simple device for
  6851.  
  6852.  
  6853.  
  6854.        Reference                      - 105 -                      Statements
  6855.  
  6856.  
  6857.  
  6858.  
  6859.  
  6860.           end-of-line comments:
  6861.  
  6862.                PARA    NEXT = GETNEXT() :F(FRETURN) ;* Return if EOF
  6863.                        IDENT(NEXT)      :S(RETURN)  ;* Return on empty line
  6864.                        PARA = PARA NEXT :(PARA)     ;* Splice line
  6865.  
  6866.  
  6867.                                14.6 THE END STATEMENT
  6868.  
  6869.             The last statement in a program must be an END statement.  The
  6870.           word END appears in the label field, beginning in column one.
  6871.           Normally, it is the only word on the line:
  6872.  
  6873.                        . . .
  6874.                        OUTPUT = 'All done'
  6875.                END
  6876.  
  6877.             After reading the END statement, compilation ends, and execu-
  6878.           tion begins immediately with the very first program statement.
  6879.           When the program is done, it should flow into the END statement,
  6880.           or use a GOTO to transfer to it.
  6881.  
  6882.             Occasionally, we would like to begin execution at other than
  6883.           the first statement.  If we place a statement label in the sub-
  6884.           ject field of the END statement, execution will begin there.  For
  6885.           example, this statement will cause execution to begin at the
  6886.           statement labeled START:
  6887.  
  6888.                END     START
  6889.  
  6890.  
  6891.  
  6892.  
  6893.  
  6894.  
  6895.  
  6896.  
  6897.  
  6898.  
  6899.  
  6900.  
  6901.  
  6902.  
  6903.  
  6904.  
  6905.  
  6906.  
  6907.  
  6908.  
  6909.  
  6910.  
  6911.  
  6912.  
  6913.  
  6914.  
  6915.  
  6916.  
  6917.        Reference                      - 106 -                      Statements
  6918.  
  6919.  
  6920.  
  6921.  
  6922.  
  6923.                                                                  Chapter 15
  6924.  
  6925.  
  6926.                                                                   OPERATORS
  6927.           -----------------------------------------------------------------
  6928.  
  6929.             Following are lists of all the unary and binary operators in
  6930.           SNOBOL4.  Unused operators may be attached to program-defined
  6931.           functions using the OPSYN function.  Unary operators have equal
  6932.           precedence among themselves, and higher precedence than binary
  6933.           operators.  Operators of higher precedence are performed first,
  6934.           unless reordered by parentheses.  Where several instances of
  6935.           operators with the same priority appear, associativity specifies
  6936.           which one is performed first.
  6937.  
  6938.  
  6939.                                 15.1 UNARY OPERATORS
  6940.  
  6941.             All unary operators are left-associative: if several appear to-
  6942.           gether, they are performed left-to-right.
  6943.  
  6944.           Graphic        Name                  Definition
  6945.           =======  =================    ==============================
  6946.             +      plus                 arithmetic positive
  6947.             -      minus                arithmetic negative
  6948.             .      period               name of object (address)
  6949.             $      dollar sign          indirect reference through object
  6950.             *      asterisk             unevaluated expression
  6951.             &      ampersand            keyword
  6952.             ~      tilde                negation of success/failure
  6953.             ?      question mark        interrogation
  6954.             @      at sign              cursor position assignment
  6955.             /      slash                <none>
  6956.             ^, !   caret, exclamation   <none>
  6957.             %      percent              <none>
  6958.             #      pound sign           <none>
  6959.             |      vertical bar         <none>
  6960.  
  6961.  
  6962.  
  6963.           15.5.1 Indirect Reference and Case-Folding
  6964.  
  6965.             The indirect reference operator ($) converts a string to a
  6966.           variable name.  When case-folding is in effect, the string char-
  6967.           acters are treated as upper-case letters when producing the name.
  6968.           The string itself is not modified.  Thus,
  6969.  
  6970.                $('abc')
  6971.  
  6972.           references variable ABC when case-folding, and variable abc when
  6973.           not.
  6974.  
  6975.  
  6976.  
  6977.  
  6978.  
  6979.  
  6980.        Reference                      - 107 -                       Operators
  6981.  
  6982.  
  6983.  
  6984.  
  6985.  
  6986.                                 15.2 BINARY OPERATORS
  6987.  
  6988.           Graphic    Name            Definition       Precedence Associates
  6989.           ======= =================  ===============  ========== ==========
  6990.             ~     tilde              <none>                 12      right
  6991.             ?     question mark      <none>                 12      left
  6992.             .     period             conditional assignment 11      left
  6993.             $     dollar sign        immediate assignment   13      left
  6994.             ^, !  caret, exclamation exponentiation         12      right
  6995.             **    double asterisk    exponentiation         12      right
  6996.             %     percent            <none>                 11      left
  6997.             *     asterisk           multiplication         10      left
  6998.             /     slash              division                9      left
  6999.             #     pound sign         <none>                  8      left
  7000.             +     plus               addition                7      left
  7001.             -     minus              subtraction             7      left
  7002.             @     at sign            <none>                  6      left
  7003.             blank blank              concatenation           5      left
  7004.             tab   tab                concatenation           5      left
  7005.             |     vertical bar       alternation             4      left
  7006.             &     ampersand          <none>                  3      left
  7007.             =     equal sign         assignment              1      right
  7008.  
  7009.  
  7010.  
  7011.  
  7012.  
  7013.  
  7014.  
  7015.  
  7016.  
  7017.  
  7018.  
  7019.  
  7020.  
  7021.  
  7022.  
  7023.  
  7024.  
  7025.  
  7026.  
  7027.  
  7028.  
  7029.  
  7030.  
  7031.  
  7032.  
  7033.  
  7034.  
  7035.  
  7036.  
  7037.  
  7038.  
  7039.  
  7040.  
  7041.  
  7042.  
  7043.        Reference                      - 108 -                       Operators
  7044.  
  7045.  
  7046.  
  7047.  
  7048.  
  7049.                                                                  Chapter 16
  7050.  
  7051.  
  7052.                                                                    KEYWORDS
  7053.           -----------------------------------------------------------------
  7054.  
  7055.             Keywords allow a program to communicate with SNOBOL4.  Their
  7056.           names are set apart from other variables by the unary operator
  7057.           ampersand (&).  Protected keywords cannot be changed by a pro-
  7058.           gram, while unprotected keywords can.
  7059.  
  7060.             Several protected keywords can be traced using the TRACE func-
  7061.           tion: &ERRTYPE, &FNCLEVEL, &STCOUNT, and &STFCOUNT.  Tracing oc-
  7062.           curs each time SNOBOL4 alters their value.  For example, tracing
  7063.           keyword &STCOUNT produces a trace after every SNOBOL4 statement
  7064.           is executed.
  7065.  
  7066.  
  7067.                                16.1 PROTECTED KEYWORDS
  7068.  
  7069.             Among these keywords are several which serve as read-only
  7070.           repositories of fundamental system patterns and values, such as
  7071.           &ARB.  The nonkeyword form (ARB) may be changed by a program, and
  7072.           later restored to its original value by assigning it the corre-
  7073.           sponding keyword.
  7074.  
  7075.              &ABORT           The primitive pattern ABORT.
  7076.  
  7077.              &ALPHABET        String of 256 ASCII character values in as-
  7078.                               cending order.
  7079.  
  7080.              &ARB             The primitive pattern ARB.
  7081.  
  7082.              &BAL             The primitive pattern BAL.
  7083.  
  7084.              &ERRTEXT         String containing most recent system gener-
  7085.                               ated error text.
  7086.  
  7087.              &ERRTYPE         Integer code of the last execution error to
  7088.                               occur.  This keyword may be traced with func-
  7089.                               tion TRACE().
  7090.  
  7091.              &FAIL            The primitive pattern FAIL.
  7092.  
  7093.              &FENCE           The primitive pattern FENCE.
  7094.  
  7095.              &FNCLEVEL        Integer depth of program-defined function
  7096.                               calls.  It is initially zero, and incremented
  7097.                               by one for each function call, and decre-
  7098.                               mented for each function return.  This key-
  7099.                               word may be traced.
  7100.  
  7101.              &LASTNO          Integer statement number of the previous
  7102.                               statement executed.
  7103.  
  7104.  
  7105.  
  7106.        Reference                      - 109 -                        Keywords
  7107.  
  7108.  
  7109.  
  7110.  
  7111.  
  7112.              &LCASE           The 26 lower-case alphabetic letters.
  7113.  
  7114.              &PARM            The command string used to invoke SNOBOL4.
  7115.                               Begins with the blank following the word
  7116.                               SNOBOL4.
  7117.  
  7118.              &REM             The primitive pattern REM.
  7119.  
  7120.              &RTNTYPE         Contains a string describing the type of re-
  7121.                               turn most recently made by a program-defined
  7122.                               function, either 'RETURN', 'FRETURN', or
  7123.                               'NRETURN'.
  7124.  
  7125.              &STCOUNT         Integer count of the number of statements
  7126.                               executed.  This keyword may be traced.  Since
  7127.                               integers are 16-bit quantities, executing
  7128.                               more than 32,767 statements will cause this
  7129.                               keyword to overflow.  No harm results, and
  7130.                               the keyword may still be traced, but its
  7131.                               value will be a large negative number.
  7132.  
  7133.              &STFCOUNT        Integer count of the number of statements
  7134.                               which failed.  This keyword may be traced.
  7135.                               The same overflow problem discussed for
  7136.                               &STCOUNT occurs with this keyword.
  7137.  
  7138.              &STNO            Integer statement number of the current
  7139.                               statement being executed.
  7140.  
  7141.              &SUCCEED         The primitive pattern SUCCEED.
  7142.  
  7143.              &UCASE           The 26 upper-case alphabetic letters.
  7144.  
  7145.  
  7146.                               16.2 UNPROTECTED KEYWORDS
  7147.  
  7148.             These keywords may be set to integer values to modify SNOBOL4's
  7149.           behavior.
  7150.  
  7151.              &ANCHOR          Nonzero for anchored pattern match.  Ini-
  7152.                               tially 0, unanchored.
  7153.  
  7154.              &CASE            Zero to prevent case-folding during compila-
  7155.                               tion with the functions CODE and EVAL.  Ini-
  7156.                               tially 1, causing case-folding to occur.
  7157.  
  7158.              &CODE            The end-of-job code is an integer value in
  7159.                               the range 0 to 255 returned to the operating
  7160.                               system.  It can be tested with the DOS Batch
  7161.                               condition ERRORLEVEL.  Initially 0.
  7162.  
  7163.  
  7164.  
  7165.  
  7166.  
  7167.  
  7168.  
  7169.        Reference                      - 110 -                        Keywords
  7170.  
  7171.  
  7172.  
  7173.  
  7174.  
  7175.              &DUMP            Nonzero to list unprotected keywords and
  7176.                               variables with nonnull values at program ter-
  7177.                               mination.  A positive value causes the list
  7178.                               to be sorted; negative values leave them un-
  7179.                               sorted.  Initially 0.  The dump is produced
  7180.                               to I/O unit 6 (OUTPUT).
  7181.  
  7182.              &ERRLIMIT        Determines the number of conditionally fatal
  7183.                               execution errors permitted before terminating
  7184.                               a program.  The Execution Error Messages sec-
  7185.                               tion of Chapter 20, "System Messages," de-
  7186.                               scribes the errors which are conditionally
  7187.                               fatal.  Initially 0, causing SNOBOL4 to stop
  7188.                               if any error occurs.
  7189.  
  7190.              &FTRACE          Nonzero value causes each call and return of
  7191.                               a program-defined function to be listed.
  7192.                               Decremented for each trace.  Initially 0.
  7193.  
  7194.              &FULLSCAN        Nonzero to disable pattern matching heuris-
  7195.                               tics.  Initially 0, the quickscan mode of
  7196.                               pattern matching.
  7197.  
  7198.              &INPUT           Zero to disable all input.  When disabled,
  7199.                               using variable INPUT (or other input-associ-
  7200.                               ated variables) does not read data from the
  7201.                               file.  Initially 1, input is enabled.
  7202.  
  7203.              &MAXLNGTH        Maximum string length.  Initially 5000, maxi-
  7204.                               mum value is 32767.  Memory limitations in
  7205.                               Vanilla SNOBOL4 will limit actual strings to
  7206.                               a smaller size.
  7207.  
  7208.              &OUTPUT          Zero to disable all output.  When disabled,
  7209.                               assigning data to OUTPUT or SCREEN (or other
  7210.                               output-associated variables) does not write
  7211.                               data to the file.  Initially 1, output is en-
  7212.                               abled.
  7213.  
  7214.              &STLIMIT         The number of statements allowed to execute.
  7215.                               If positive, it is decremented for each
  7216.                               statement executed; execution terminates when
  7217.                               it reaches 0.  If negative, there is no
  7218.                               limit, and it is not decremented.  Initially
  7219.                               -1.
  7220.  
  7221.              &TRACE           Nonzero to permit tracing with the TRACE
  7222.                               function.  Initially 0, it is decremented for
  7223.                               each trace performed.
  7224.  
  7225.              &TRIM            Nonzero to strip trailing blanks from lines
  7226.                               read from ASCII files.  This is faster than
  7227.                               using the TRIM function.  It does not strip
  7228.                               trailing tab characters.  Initially 0: blanks
  7229.  
  7230.  
  7231.  
  7232.        Reference                      - 111 -                        Keywords
  7233.  
  7234.  
  7235.  
  7236.  
  7237.  
  7238.                               are not removed and short records are blank
  7239.                               padded to the file's standard record length.
  7240.  
  7241.  
  7242.                                  16.3 SPECIAL NAMES
  7243.  
  7244.             The following names have special meaning to SNOBOL4.  If case-
  7245.           folding is in effect, they may appear with any combination of
  7246.           upper- and lower-case letters.
  7247.  
  7248.              END              This is a special label which denotes the
  7249.                               last statement of the user's program.  An op-
  7250.                               tional label may follow the word END (in the
  7251.                               subject field) to denote where program execu-
  7252.                               tion is to begin.  A program should terminate
  7253.                               execution by transferring to label END.
  7254.  
  7255.              FRETURN          Transfer to this label to return from a
  7256.                               program-defined function with a failure indi-
  7257.                               cation.
  7258.  
  7259.              INPUT            Variable associated with input from unit
  7260.                               number 5.
  7261.  
  7262.              NRETURN          Transfer to this label to return successfully
  7263.                               from a program-defined function by name,
  7264.                               rather than by value.  The function name
  7265.                               should be assigned a name result (usually
  7266.                               with the period (.) unary operator).  This
  7267.                               permits a function call to be the object of
  7268.                               an assignment operation.
  7269.  
  7270.              OUTPUT           Variable associated with output to unit
  7271.                               number 6.
  7272.  
  7273.              RETURN           Transfer to this label to return from a
  7274.                               program-defined function with a success indi-
  7275.                               cation.  A value may be returned as the func-
  7276.                               tion's result; simply assign it to a variable
  7277.                               with the same name as the function before
  7278.                               transferring to RETURN.
  7279.  
  7280.  
  7281.  
  7282.  
  7283.  
  7284.  
  7285.  
  7286.  
  7287.  
  7288.  
  7289.  
  7290.  
  7291.  
  7292.  
  7293.  
  7294.  
  7295.        Reference                      - 112 -                        Keywords
  7296.  
  7297.  
  7298.  
  7299.  
  7300.  
  7301.                                                                  Chapter 17
  7302.  
  7303.  
  7304.                                                   DATA TYPES AND CONVERSION
  7305.           -----------------------------------------------------------------
  7306.  
  7307.             Most other programming languages require the user to explicitly
  7308.           declare the type of data to be stored in a variable.  In SNOBOL4,
  7309.           any variable may contain any data type.  Furthermore, the vari-
  7310.           able's type may be freely altered during program execution.
  7311.           SNOBOL4 remembers what kind of data is in each variable.
  7312.  
  7313.  
  7314.                                 17.1 DATA TYPE NAMES
  7315.  
  7316.             The formal name of a data type is specified by an upper-case
  7317.           string (or lower-case if case-folding is in effect), such as
  7318.           'INTEGER', or 'ARRAY'.  It is used with the CONVERT function to
  7319.           specify the data type conversion desired.  The formal name is
  7320.           also the string returned when the DATATYPE() function is used to
  7321.           determine an object's type.
  7322.  
  7323.           -----------------------------------------------------------------
  7324.  
  7325.           ARRAY                            N-dimensional array
  7326.  
  7327.           The primitive function ARRAY() creates an array storage area, and
  7328.           returns a pointer with this data type.  If this pointer is stored
  7329.           in a variable, the variable is said to be of type ARRAY, and may
  7330.           then be subscripted to access the elements of the array.
  7331.  
  7332.           -----------------------------------------------------------------
  7333.  
  7334.           CODE                             Compiled SNOBOL4 code
  7335.  
  7336.           The primitive function CODE() compiles a string containing
  7337.           SNOBOL4 statements, and returns a pointer to the resulting object
  7338.           code block.  If this pointer is stored in a variable, the vari-
  7339.           able is said to be of type CODE.  The variable may then be used
  7340.           with a direct GOTO by enclosing it in angle brackets.
  7341.  
  7342.           -----------------------------------------------------------------
  7343.  
  7344.           EXPRESSION                       Unevaluated expression
  7345.  
  7346.           When the unevaluated expression operator (*) is applied to an ex-
  7347.           pression, the result has the data type EXPRESSION.  Such expres-
  7348.           sions are not evaluated when they are defined, only when they are
  7349.           referenced.
  7350.  
  7351.                        E = *(LEN(K) POS(M))
  7352.  
  7353.           defines E as an unevaluated expression.  When this statement is
  7354.           executed, the code to concatenate two function calls is compiled,
  7355.  
  7356.  
  7357.  
  7358.        Reference                      - 113 -       Data Types and Conversion
  7359.  
  7360.  
  7361.  
  7362.  
  7363.  
  7364.           but not executed.  It is only when E is referenced in a subse-
  7365.           quent pattern match or appears as the argument of the EVAL
  7366.           function that the code is executed to produce a pattern.
  7367.  
  7368.             The unevaluated expression operator must be at the outermost
  7369.           level to create an object of type EXPRESSION.  If buried with the
  7370.           expression, the execution results may appear to be similar, but
  7371.           the object's data type is different.  That is, the two statements
  7372.  
  7373.                        P = *LEN(N)
  7374.                        P = LEN(*N)
  7375.  
  7376.           produce identical results when P is used in a pattern match (if
  7377.           LEN is not redefined).  However, the first statement produces P
  7378.           as type EXPRESSION, while the second produces P as type PATTERN.
  7379.           Expressions may also be produced explicitly with the CONVERT()
  7380.           function (see below).
  7381.  
  7382.           -----------------------------------------------------------------
  7383.  
  7384.           EXTERNAL                         Created by external function
  7385.  
  7386.           External assembly language functions may create new data types
  7387.           whose structure is known only to them.  This feature is only
  7388.           available in SNOBOL4+, Catspaw's enhanced implementation of the
  7389.           SNOBOL4 language.
  7390.  
  7391.           -----------------------------------------------------------------
  7392.  
  7393.           INTEGER                          Integer number
  7394.  
  7395.           A decimal number in the range -32767 to +32767.  No fractional
  7396.           part may appear.  One computer word (16 bits) is used to contain
  7397.           an integer value.
  7398.  
  7399.           -----------------------------------------------------------------
  7400.  
  7401.           NAME                             Name of a variable
  7402.  
  7403.           When the unary name operator (.) is applied to a variable, two
  7404.           results are possible.  If the variable's name is a simple string
  7405.           (a "natural variable"), such as ABC, the variable's name is
  7406.           returned as type STRING.  For example, .ABC has the value 'ABC'.
  7407.           However, if the variable is a created variable, such as a table
  7408.           or array element, the NAME data type results.  In either case,
  7409.           the result of the name operator can be thought of as the
  7410.           "address" or "storage location" of the variable.  When the indi-
  7411.           rect reference operator ($) is applied to such a result, the
  7412.           original, underlying object is obtained.  That is, $(.A) is the
  7413.           same as using the variable A.
  7414.  
  7415.             For natural variables, SNOBOL4 has the surprising property that
  7416.           the string 'XYZ' is the address (or name) of variable XYZ, so
  7417.           $'XYZ' is equivalent to XYZ.
  7418.  
  7419.  
  7420.  
  7421.        Reference                      - 114 -       Data Types and Conversion
  7422.  
  7423.  
  7424.  
  7425.  
  7426.  
  7427.           -----------------------------------------------------------------
  7428.  
  7429.           PATTERN                          Pattern match structure
  7430.  
  7431.           A pattern is created by an expression containing any of the fol-
  7432.           lowing:  other patterns, primitive patterns, pattern functions,
  7433.           the alternation operator (|), the conditional or immediate as-
  7434.           signment operator (. or $), or the cursor position operator (@).
  7435.           A simple string is not a pattern data type, even though it may
  7436.           appear in the pattern portion of a statement.  The following are
  7437.           examples of the pattern data type:
  7438.  
  7439.                        POS(0) "A" LEN(1)
  7440.                        "COLUMN A" | "COLUMN B"
  7441.                        "ZIP" . X
  7442.                        "MATCH" @Y
  7443.  
  7444.           -----------------------------------------------------------------
  7445.  
  7446.           Program-defined data type        Created by DATA() function
  7447.  
  7448.           Up to 899 new data types may be created with the primitive func-
  7449.           tion DATA.  The name specified in the prototype string becomes a
  7450.           new data type in SNOBOL4.  Any object created with the data
  7451.           type's creation function is given this name as its data type.
  7452.  
  7453.                DATA('COMPLEX(REAL, IMAG)')      ;* Define new type COMPLEX
  7454.                NUM = COMPLEX(2, -4)             ;* Create a COMPLEX object
  7455.                OUTPUT = DATATYPE(NUM)           ;* Print string 'COMPLEX'
  7456.  
  7457.           -----------------------------------------------------------------
  7458.  
  7459.           REAL                             Real number
  7460.  
  7461.           A floating-point decimal number in the range 2.3E-308 to
  7462.           1.7E+308.  Reals are only available in SNOBOL4+, Catspaw's
  7463.           enhanced implementation of the SNOBOL4 language.
  7464.  
  7465.           -----------------------------------------------------------------
  7466.  
  7467.           STRING                           Character string
  7468.  
  7469.           A sequence of characters.  Each character occupies one memory
  7470.           byte, and may contain any of the 256 possible bit combinations.
  7471.           A string of length zero is called the null string.  Maximum
  7472.           length of a string is determined by the keyword &MAXLNGTH
  7473.           (default 5000).  Memory restrictions in Vanilla SNOBOL4 will
  7474.           limit the longest string possible to less than the 32767
  7475.           characters allowed in SNOBOL4+, Catspaw's enhanced SNOBOL4
  7476.           implementation.
  7477.  
  7478.  
  7479.  
  7480.  
  7481.  
  7482.  
  7483.  
  7484.        Reference                      - 115 -       Data Types and Conversion
  7485.  
  7486.  
  7487.  
  7488.  
  7489.  
  7490.           -----------------------------------------------------------------
  7491.  
  7492.           TABLE                            Associatively referenced table
  7493.  
  7494.           The primitive function TABLE() creates a table storage area, and
  7495.           returns a pointer with this data type.  If this pointer is stored
  7496.           in a variable, the variable is said to be of type TABLE.  The
  7497.           variable may then be subscripted to access the elements of the
  7498.           table.  A table may be thought of as a one dimensional array in
  7499.           which the array subscripts may be any SNOBOL4 data type.  Arrays
  7500.           require integer subscripts, but table subscripts such as
  7501.           T<"TALLY"> or T<13.52> are acceptable.
  7502.  
  7503.  
  7504.                               17.2 DATA TYPE CONVERSION
  7505.  
  7506.             Data may be implicitly or explicitly converted from one type to
  7507.           another.
  7508.  
  7509.  
  7510.           17.2.1 Implicit Conversion
  7511.  
  7512.             Implicit conversion occurs automatically when SNOBOL4 requires
  7513.           a certain data type, and your program provides it in another
  7514.           form.  Conversion to the correct data type will be attempted, and
  7515.           an error message given if conversion is not possible.
  7516.  
  7517.  
  7518.           17.2.2 Explicit Conversion
  7519.  
  7520.             A program may use the CONVERT() function to explicitly convert
  7521.           an object to another data type.  The first argument is the object
  7522.           to be converted; the second is a string containing the formal
  7523.           name of the desired data type.  The formal name must be in upper-
  7524.           case (lower-case allowed if case-folding).  If conversion is
  7525.           possible, the function succeeds and returns the converted object.
  7526.           If not, the function fails.  The call looks like this:
  7527.  
  7528.                        NEWTYPE = CONVERT(OBJECT, "DESIRED TYPE")
  7529.  
  7530.  
  7531.           17.2.3 Permissible Conversions
  7532.  
  7533.           -----------------------------------------------------------------
  7534.  
  7535.           ARRAY to STRING                  
  7536.  
  7537.           The formal name "ARRAY" is produced.  The defining array dimen-
  7538.           sion string is appended if less than 20 characters:
  7539.  
  7540.                        A = ARRAY('1:50,6')
  7541.                        OUTPUT = A
  7542.  
  7543.           produces the string "ARRAY('1:50,6')".
  7544.  
  7545.  
  7546.  
  7547.        Reference                      - 116 -       Data Types and Conversion
  7548.  
  7549.  
  7550.  
  7551.  
  7552.  
  7553.           -----------------------------------------------------------------
  7554.  
  7555.           CODE to STRING                   
  7556.  
  7557.           The formal name "CODE" is produced:
  7558.  
  7559.                        C = CODE(' PIT2 = .OPPIT4 :(RETURN)')
  7560.                        OUTPUT = C
  7561.  
  7562.           displays the string "CODE".
  7563.  
  7564.           -----------------------------------------------------------------
  7565.  
  7566.           EXPRESSION to PATTERN            
  7567.  
  7568.           This occurs implicitly within a pattern match, or by using the
  7569.           EVAL function.  The deferred expression is evaluated, using
  7570.           current values for any variables which appear.  Example:
  7571.  
  7572.                        LASTN = *(RTAB(N) REM . LCHARS)
  7573.                         . . .
  7574.                        N = 4
  7575.                        SUBJECT LASTN                        :F(TOO_SHORT)
  7576.  
  7577.           -----------------------------------------------------------------
  7578.  
  7579.           EXPRESSION to STRING             
  7580.  
  7581.           The formal name "EXPRESSION" is produced.  For example,
  7582.  
  7583.                        LASTN = *(RTAB(N) REM . LCHARS)
  7584.                        OUTPUT = LASTN
  7585.  
  7586.           produces the string "EXPRESSION".
  7587.  
  7588.           -----------------------------------------------------------------
  7589.  
  7590.           INTEGER to PATTERN               
  7591.  
  7592.           This only occurs implicitly within a pattern match.  The integer
  7593.           is converted to a string, and the string converted to a pattern.
  7594.           Example:
  7595.  
  7596.                        SUBJECT 19 = ''
  7597.  
  7598.  
  7599.  
  7600.  
  7601.  
  7602.  
  7603.  
  7604.  
  7605.  
  7606.  
  7607.  
  7608.  
  7609.  
  7610.        Reference                      - 117 -       Data Types and Conversion
  7611.  
  7612.  
  7613.  
  7614.  
  7615.  
  7616.           -----------------------------------------------------------------
  7617.  
  7618.           INTEGER to STRING                
  7619.  
  7620.           Leading zeros are suppressed, and a minus sign appears if the
  7621.           integer was negative.  Integer zero is converted to the string
  7622.           "0".  For example,
  7623.  
  7624.                        A = -23;  B = 0;  C = 92
  7625.                        OUTPUT = A B C
  7626.  
  7627.           produces the string "-23092".
  7628.  
  7629.           -----------------------------------------------------------------
  7630.  
  7631.           NAME to STRING                   
  7632.  
  7633.           The formal name "NAME" is produced:
  7634.  
  7635.                        N = .A[2]
  7636.                        OUTPUT = N
  7637.  
  7638.           displays the string "NAME".
  7639.  
  7640.           -----------------------------------------------------------------
  7641.  
  7642.           PATTERN to STRING                
  7643.  
  7644.           The formal name "PATTERN" is produced.  For example,
  7645.  
  7646.                        WPAT = BREAK(LETTERS) SPAN(LETTERS) . WORD
  7647.                        OUTPUT = WPAT
  7648.  
  7649.           produces the string "PATTERN".
  7650.  
  7651.           -----------------------------------------------------------------
  7652.  
  7653.           DEFINED DATA TYPE to STRING      
  7654.  
  7655.           The formal name from the defining DATA function call is returned.
  7656.  
  7657.                        DATA('COMPLEX(REAL,IMAG)')
  7658.                        R1 = COMPLEX(2, 3)
  7659.                        OUTPUT = R1
  7660.  
  7661.           produces the string "COMPLEX".
  7662.  
  7663.           -----------------------------------------------------------------
  7664.  
  7665.           STRING to INTEGER                
  7666.  
  7667.           The string must not have any leading or trailing blanks.  A lead-
  7668.           ing plus or minus sign is allowed, but must be followed by at
  7669.           least one digit.  Leading zeros are allowed, and the resulting
  7670.  
  7671.  
  7672.  
  7673.        Reference                      - 118 -       Data Types and Conversion
  7674.  
  7675.  
  7676.  
  7677.  
  7678.  
  7679.           value must be in the legal range for integer values.  A null
  7680.           string is converted to integer zero.
  7681.  
  7682.                        RESULT = ("-14" + "") / "2"
  7683.  
  7684.           stores integer -7 in RESULT.
  7685.  
  7686.           -----------------------------------------------------------------
  7687.  
  7688.           STRING to PATTERN                
  7689.  
  7690.           This only occurs implicitly within a pattern match.  The pattern
  7691.           created will match the specified substring:
  7692.  
  7693.                        SUBJECT "HOPE"
  7694.  
  7695.           -----------------------------------------------------------------
  7696.  
  7697.           TABLE to ARRAY                   
  7698.  
  7699.           This only occurs when using the CONVERT function.  The table is
  7700.           converted to a two dimensional array.  Example:
  7701.  
  7702.                        T = TABLE(100)
  7703.                         . . .
  7704.                        A = CONVERT(T, "ARRAY")         :F(EMPTY)
  7705.  
  7706.             The table is converted to a rectangular array.  Null table
  7707.           entries are omitted, and there must be at least one nonnull entry
  7708.           or the function fails.  An N by 2 array is created, where N is
  7709.           the number of nonnull table values.  The first array column con-
  7710.           tains the table subscripts, the second column contains the entry
  7711.           values.
  7712.  
  7713.           -----------------------------------------------------------------
  7714.  
  7715.           TABLE to STRING                  
  7716.  
  7717.           The formal name "TABLE" is returned with the present size of the
  7718.           table and its expansion increment.  For example,
  7719.  
  7720.                        T = TABLE(10,10)
  7721.                         . . .
  7722.                ; Insert 45 nonnull elements into T
  7723.                         . . .
  7724.                        OUTPUT = T
  7725.  
  7726.           produces the string "TABLE(50,10)" (because table segments in
  7727.           this case are allocated in multiples of 10).
  7728.  
  7729.             The following matrix indicates conversions with CONVERT():
  7730.  
  7731.  
  7732.  
  7733.  
  7734.  
  7735.  
  7736.        Reference                      - 119 -       Data Types and Conversion
  7737.  
  7738.  
  7739.  
  7740.  
  7741.  
  7742.                           |      Result Type            E
  7743.                           |                             X
  7744.                           |                             P
  7745.                           |     I   P                   R   D
  7746.                           | S   N   A                   E   E
  7747.                           | T   T   T       A   T       S   F
  7748.                           | R   E   T   N   R   A   C   S   I
  7749.                           | I   G   E   A   R   B   O   I   N
  7750.                  Argument | N   E   R   M   A   L   D   O   E
  7751.                    Type   | G   R   N   E   Y   E   E   N   D
  7752.                -----------+-----------------------------------
  7753.                    STRING | *   I   P               C   E
  7754.                   INTEGER | S   *   P
  7755.                   PATTERN | F       *
  7756.                      NAME | F           *
  7757.                     ARRAY | A               *   1
  7758.                     TABLE | T               2   *
  7759.                      CODE | F                       *
  7760.                EXPRESSION | F       P                   *
  7761.                   DEFINED | F                               *
  7762.  
  7763.             *  The argument object is returned unchanged.
  7764.  
  7765.             A  The formal data type name "ARRAY" is returned with the
  7766.                defining prototype string if it is less than 20 characters.
  7767.  
  7768.             C  CONVERT(string,"CODE) behaves exactly like CODE(string).
  7769.  
  7770.             E  Produces an unevaluated expression, that may be subsequently
  7771.                used in a pattern, or evaluated with the EVAL() function.
  7772.  
  7773.             F  The formal data type name is returned.
  7774.  
  7775.             I  Numeric conversion is conditioned on magnitude and syntax
  7776.                restrictions. No leading or trailing blanks are permitted.
  7777.  
  7778.             P  Occurs implicitly within a pattern match.
  7779.  
  7780.             S  A number may always be converted to its string form.
  7781.  
  7782.             T  The string "TABLE" is returned with the present size of the
  7783.                table and its expansion increment:  "TABLE(50,10)".
  7784.  
  7785.             1  The array must be rectangular, with a second dimension of 2
  7786.                (N rows by 2 columns).  A table with N entries is created.
  7787.                The table subscripts are taken from the first column of the
  7788.                array; the table values are copied from the second column.
  7789.  
  7790.             2  The table is converted to a rectangular array.  Null table
  7791.                entries are omitted, and there must be at least one nonnull
  7792.                entry or the function fails.  An N by 2 array is created,
  7793.                where N is the number of nonnull table values.  The first
  7794.                array column contains the table subscripts, the second col-
  7795.                umn contains the entry values.
  7796.  
  7797.  
  7798.  
  7799.        Reference                      - 120 -       Data Types and Conversion
  7800.  
  7801.  
  7802.  
  7803.  
  7804.  
  7805.                                                                  Chapter 18
  7806.  
  7807.  
  7808.                                              PATTERNS AND PATTERN FUNCTIONS
  7809.           -----------------------------------------------------------------
  7810.  
  7811.             The SNOBOL4 pattern matcher is called the "scanner."  The
  7812.           "cursor" is the scanner's pointer into the subject string; it
  7813.           points between subject characters (no relation to your CRT cur-
  7814.           sor).  It is initially zero when positioned to the left of the
  7815.           subject, and is incremented as the scanner moves to the right in
  7816.           the subject.
  7817.  
  7818.  
  7819.                                18.1 PRIMITIVE PATTERNS
  7820.  
  7821.             These variables initially contain the primitive patterns of the
  7822.           same name.  They may be set to other values by a program, and re-
  7823.           stored to their original value from the corresponding protected
  7824.           keywords.
  7825.  
  7826.              ABORT            Causes immediate failure of the entire pat-
  7827.                               tern match, without seeking alternatives.
  7828.  
  7829.              ARB              Matches zero or more characters of the sub-
  7830.                               ject string.  It matches the shortest possi-
  7831.                               ble substring.
  7832.  
  7833.              BAL              Matches any nonnull string which is balanced
  7834.                               with respect to parentheses.  A string with-
  7835.                               out parentheses is considered balanced.  BAL
  7836.                               matches the shortest string possible.
  7837.  
  7838.              FAIL             Causes failure of this portion of the pattern
  7839.                               match, causing the scanner to backtrack and
  7840.                               try alternatives.
  7841.  
  7842.              FENCE            Matches the null string and succeeds when the
  7843.                               scanner is moving left to right in a pattern,
  7844.                               but fails if the scanner has to back up
  7845.                               through it, seeking alternatives.
  7846.  
  7847.              REM              Matches zero or more characters from the cur-
  7848.                               rent cursor position to the end of the sub-
  7849.                               ject string.
  7850.  
  7851.              SUCCEED          Matches the null string and always succeeds.
  7852.  
  7853.             Altering these primitive patterns can produce very confusing
  7854.           programs, unless the new value encompasses the old, like this:
  7855.  
  7856.                        ARB = &ARB . OUTPUT
  7857.  
  7858.  
  7859.  
  7860.  
  7861.  
  7862.        Reference                      - 121 -                        Patterns
  7863.  
  7864.  
  7865.  
  7866.  
  7867.  
  7868.                           18.2 PRIMITIVE PATTERN FUNCTIONS
  7869.  
  7870.             These functions produce a pattern based on the argument sup-
  7871.           plied.  The argument data type is shown below---other data types
  7872.           or expressions will be converted to the required type if
  7873.           possible.
  7874.  
  7875.             Pattern functions may be combined with other primitive pat-
  7876.           terns, functions, and strings using the alternation and concate-
  7877.           nation operators to produce larger patterns.
  7878.  
  7879.           -----------------------------------------------------------------
  7880.  
  7881.           ANY(string)                      Match one character from set
  7882.  
  7883.           Matches exactly one character from the set of characters speci-
  7884.           fied by the argument string.
  7885.  
  7886.           -----------------------------------------------------------------
  7887.  
  7888.           ARBNO(pattern)                   Match repeated pattern
  7889.  
  7890.           Matches zero or more consecutive occurrences of the string
  7891.           matched by the argument pattern.  ARBNO matches the shortest
  7892.           string possible--initially the null string--and only tries to
  7893.           match pattern if other pattern components in the statement re-
  7894.           quire it.
  7895.  
  7896.           -----------------------------------------------------------------
  7897.  
  7898.           BREAK(string)                    Match characters not in set
  7899.  
  7900.           Matches zero or more characters provided they are not in the set
  7901.           of characters in the argument string.  That is, it matches up to,
  7902.           but not including, a character from the argument string.
  7903.  
  7904.           -----------------------------------------------------------------
  7905.  
  7906.           LEN(integer)                     Match fixed length string
  7907.  
  7908.           Matches a string of the specified length.  There are no restric-
  7909.           tions on the subject string characters.  An argument of zero will
  7910.           match the null string.
  7911.  
  7912.           -----------------------------------------------------------------
  7913.  
  7914.           NOTANY(string)                   Match one character not in set
  7915.  
  7916.           Matches exactly one character provided it is not in the set of
  7917.           characters specified by the argument string.
  7918.  
  7919.  
  7920.  
  7921.  
  7922.  
  7923.  
  7924.  
  7925.        Reference                      - 122 -                        Patterns
  7926.  
  7927.  
  7928.  
  7929.  
  7930.  
  7931.           -----------------------------------------------------------------
  7932.  
  7933.           POS(integer)                     Verify scanner position
  7934.  
  7935.           Succeeds if the scanner's current cursor position in the subject
  7936.           string is equal to the specified integer value.  This function
  7937.           merely verifies scanner position---it does not consume or match
  7938.           any subject characters.  POS(0) as the first component of a pat-
  7939.           tern produces an anchored pattern match.
  7940.  
  7941.           -----------------------------------------------------------------
  7942.  
  7943.           RPOS(integer)                    Verify scanner position from end
  7944.  
  7945.           Succeeds if the scanner's current cursor position in the subject
  7946.           string is the specified number of characters from the end of the
  7947.           string.  Like POS(), it verifies scanner position but does not
  7948.           consume any characters.  RPOS(0) as the last component of a pat-
  7949.           tern forces the pattern to match to the end of the subject
  7950.           string.
  7951.  
  7952.           -----------------------------------------------------------------
  7953.  
  7954.           RTAB(integer)                    Match through position counting
  7955.                                            from end
  7956.  
  7957.           Matches all characters from the current cursor position up to the
  7958.           specified cursor position, counting from the end of the subject
  7959.           string.  RTAB(N) matches characters up to, but not including, the
  7960.           final N characters of the subject.
  7961.  
  7962.           -----------------------------------------------------------------
  7963.  
  7964.           SPAN(string)                     Match characters in set
  7965.  
  7966.           Matches one or more characters from the set of characters speci-
  7967.           fied by the argument string.  SPAN will not match the null
  7968.           string; at least one character from the argument string must be
  7969.           found in the subject.
  7970.  
  7971.           -----------------------------------------------------------------
  7972.  
  7973.           TAB(integer)                     Match through fixed position
  7974.  
  7975.           Matches all characters from the current cursor position up to the
  7976.           specified cursor position.  TAB(N) matches characters up to, and
  7977.           including, the initial N characters of the subject.  TAB will
  7978.           match the null string if the target position and current cursor
  7979.           position are the same.  The function fails if the current scanner
  7980.           position is to the right of the target position.
  7981.  
  7982.  
  7983.  
  7984.  
  7985.  
  7986.  
  7987.  
  7988.        Reference                      - 123 -                        Patterns
  7989.  
  7990.  
  7991.  
  7992.  
  7993.  
  7994.                                                                  Chapter 19
  7995.  
  7996.  
  7997.                                                          BUILT-IN FUNCTIONS
  7998.           -----------------------------------------------------------------
  7999.  
  8000.             In this chapter, the following items are used to indicate the
  8001.           required argument type.  Other types may be used, and will be
  8002.           automatically converted to the required type, if possible.  Inte-
  8003.           ger suffixes will be used to distinguish multiple arguments of
  8004.           the same type.
  8005.  
  8006.              arg              A generic argument of any SNOBOL4 data type.
  8007.  
  8008.              array            An array.
  8009.  
  8010.              i                An integer number.
  8011.  
  8012.              name             The name of a variable, function or label,
  8013.                               such as .VAR or 'VAR'.  When case-folding,
  8014.                               'VAR' and 'var' are equivalent as names.
  8015.  
  8016.              s                Any SNOBOL4 string.
  8017.  
  8018.              table            A table.
  8019.  
  8020.              unit             I/O unit; an integer between 1 and 16.
  8021.  
  8022.             If an argument is omitted in a function call, SNOBOL4 supplies
  8023.           the null string instead.
  8024.  
  8025.           -----------------------------------------------------------------
  8026.  
  8027.           APPLY(name, arg1, arg2,...,argn) Indirect call to a function
  8028.  
  8029.           Call function name with the specified arguments.  Since name may
  8030.           be a variable containing a function name, it allows an indirect
  8031.           call to a function, similar to the :($VAR) construct in the GOTO
  8032.           field.
  8033.  
  8034.           -----------------------------------------------------------------
  8035.  
  8036.           ARG(name, i)                     Get dummy argument name from
  8037.                                            function definition
  8038.  
  8039.           Returns a string which is the Ith argument from the formal defi-
  8040.           nition of program-defined function name.  ARG fails if i is
  8041.           greater than the number of arguments in name's definition.  ARG
  8042.           is useful when one function is used to trace another.  The trace
  8043.           function can access the actual argument used with the function
  8044.           being traced with an indirect reference: $ARG(name, i).
  8045.  
  8046.  
  8047.  
  8048.  
  8049.  
  8050.  
  8051.        Reference                      - 124 -              Built-In Functions
  8052.  
  8053.  
  8054.  
  8055.  
  8056.  
  8057.           -----------------------------------------------------------------
  8058.  
  8059.           ARRAY(s, arg)                    Create an array
  8060.  
  8061.           S is a prototype which specifies the dimensions of the array cre-
  8062.           ated, and the optional arg is the value used to initialize all
  8063.           array elements.  The form of the prototype string is:
  8064.  
  8065.                        "L1:H1,L2:H2,...,Ln:Hn"
  8066.  
  8067.           where L and H are integers giving the lower and upper bounds of
  8068.           each dimension.  Blanks are not permitted.  If the lower bound
  8069.           and colon are omitted from any dimension, '1:' is assumed.  ARRAY
  8070.           returns a pointer to the new array, which should be assigned to a
  8071.           variable.  The variable can then be subscripted to access the
  8072.           array elements.
  8073.  
  8074.             A common error when defining a multidimensional array is to use
  8075.           integers instead of a string for the prototype:
  8076.  
  8077.                        ARRAY(3,4) instead of ARRAY("3,4")
  8078.  
  8079.             The first example defines a 3-element, one-dimensional array,
  8080.           with elements initialized to integer 4.  The second defines a
  8081.           rectangular array, 3 rows by 4 columns.
  8082.  
  8083.           -----------------------------------------------------------------
  8084.  
  8085.           CHAR(i)                          Convert integer to ASCII
  8086.                                            character
  8087.  
  8088.           Converts an integer ASCII code to a one-character string.  The
  8089.           argument must be in the range 0 to 255, otherwise the function
  8090.           fails.
  8091.  
  8092.           -----------------------------------------------------------------
  8093.  
  8094.           CLEAR()                          Clear all variables
  8095.  
  8096.           The null string is assigned to all variables in the system
  8097.           (including primitive patterns, such as ARB.  These patterns and
  8098.           names may be restored from the protected keywords with the same
  8099.           names (e.g., ARB = &ARB).
  8100.  
  8101.             CLEAR does not modify variables which are currently saved on
  8102.           the function call stack.
  8103.  
  8104.           -----------------------------------------------------------------
  8105.  
  8106.           CODE(s)                          Compile a string
  8107.  
  8108.           Returns a pointer to the object code compiled from the SNOBOL4
  8109.           statements in string s.  This pointer can be assigned to a vari-
  8110.           able, and the code executed with the direct GOTO :<variable>.
  8111.  
  8112.  
  8113.  
  8114.        Reference                      - 125 -              Built-In Functions
  8115.  
  8116.  
  8117.  
  8118.  
  8119.  
  8120.           CODE fails if it finds a syntax error, and places an error mes-
  8121.           sage string in keyword &ERRTEXT.  Individual statements in s are
  8122.           separated by a semicolon (;).  The first character following a
  8123.           semicolon must be a blank, tab, the start of a label, or a com-
  8124.           ment.  Control and continuation statements are not allowed in s.
  8125.           Statements may be any length; the 120 character limit when com-
  8126.           piling from a file does not apply.  Case-folding of names is con-
  8127.           trolled by keyword &CASE.
  8128.  
  8129.           -----------------------------------------------------------------
  8130.  
  8131.           COLLECT(i)                       Regenerate storage
  8132.  
  8133.           This function calls SNOBOL4's garbage collection routine, which
  8134.           reclaims all unused storage.  It returns an integer result that
  8135.           is the number of free descriptors remaining in the work space (a
  8136.           descriptor contains 5 bytes of storage).  If there are less than
  8137.           i free descriptors after regeneration, the function fails.
  8138.           SNOBOL4 automatically calls COLLECT whenever memory becomes full.
  8139.  
  8140.           -----------------------------------------------------------------
  8141.  
  8142.           CONVERT(arg, s)                  Convert to specified data type
  8143.  
  8144.           The argument is converted to the specified data type and returned
  8145.           as the value of the function.  If conversion is not possible, the
  8146.           function fails.  S is a data type name string, such as 'STRING',
  8147.           'TABLE', etc.  Data type names may be lower case if case-folding
  8148.           is active.  Chapter 17, "Data Types and Conversion," lists allow-
  8149.           able conversions.
  8150.  
  8151.           -----------------------------------------------------------------
  8152.  
  8153.           COPY(arg)                        Make copy of argument
  8154.  
  8155.           Returns a distinct copy of arg.  The argument may be an array,
  8156.           code block, pattern, or program-defined data type.  If A is an
  8157.           array, the statement
  8158.  
  8159.                        B = COPY(A)
  8160.  
  8161.           creates a new array B, whose initial contents are the same as
  8162.           array A.  Their elements are independent; altering element A<I>
  8163.           does not affect element B<I>.  In contrast, the assignment B = A
  8164.           makes A and B alternate names for the same array.
  8165.  
  8166.           -----------------------------------------------------------------
  8167.  
  8168.           DATA(s)                          Create new data type
  8169.  
  8170.           Defines a new data type according to the prototype in string s.
  8171.           The prototype assumes a form similar to a function call, with the
  8172.           data type taking the place of the function name, and the field
  8173.           names replacing the arguments.  The form of the prototype string
  8174.  
  8175.  
  8176.  
  8177.        Reference                      - 126 -              Built-In Functions
  8178.  
  8179.  
  8180.  
  8181.  
  8182.  
  8183.           is
  8184.  
  8185.                        "NEWTYPE(FIELD1,FIELD2,...,FIELDn)"
  8186.  
  8187.             The DATA function implicitly defines a new function and n new
  8188.           field variables:
  8189.  
  8190.              NEWTYPE(ARG1,ARG2,...,ARGn)     Object creation function.
  8191.  
  8192.              FIELD1(x)        Reference to field variable 1.
  8193.  
  8194.              . . .
  8195.  
  8196.              FIELDn(x)        Reference to field variable n.
  8197.  
  8198.           where x is an object created with the NEWTYPE function.
  8199.  
  8200.             The fields may be of any data type, including pointers to other
  8201.           program-defined data items.
  8202.  
  8203.           -----------------------------------------------------------------
  8204.  
  8205.           DATATYPE(arg)                    Get data type of argument
  8206.  
  8207.           Returns a string specifying the data type of the argument.  Some
  8208.           typical arguments and their data types are:
  8209.  
  8210.              12               INTEGER
  8211.  
  8212.              'ABCD'           STRING
  8213.  
  8214.              POS(2) 'C' LEN(3)     PATTERN
  8215.  
  8216.              .Q<3>            NAME
  8217.  
  8218.              *PAT             EXPRESSION
  8219.  
  8220.             If the argument is a program-defined data type, the name from
  8221.           the creating DATA() function is returned.
  8222.  
  8223.           -----------------------------------------------------------------
  8224.  
  8225.           DATE()                           Get current date and time
  8226.  
  8227.           Returns a 20-character string of the form:
  8228.  
  8229.                        'MM-DD-YY HH:MM:SS.CC'
  8230.  
  8231.           representing month, day, year, hour, minute, second, and cen-
  8232.           tisecond respectively.  The centisecond field can only be approx-
  8233.           imated, since many personal computer clocks are only updated
  8234.           every 55 milliseconds.
  8235.  
  8236.           -----------------------------------------------------------------
  8237.  
  8238.  
  8239.  
  8240.        Reference                      - 127 -              Built-In Functions
  8241.  
  8242.  
  8243.  
  8244.  
  8245.  
  8246.           DEFINE(s, name)                  Create program-defined function
  8247.  
  8248.           This function creates a new, program-defined function.  S is a
  8249.           prototype string specifying the function's name, arguments, and
  8250.           local variables, if any.  Name is optional, and specifies a label
  8251.           as the first statement of the function body.  If absent, a label
  8252.           with the same name as the function is the assumed entry point.
  8253.           The form of the prototype string is
  8254.  
  8255.                        "FNAME(ARG1,ARG2,...,ARGn)LOCAL1,LOCAL2,...,LOCALn"
  8256.  
  8257.           where FNAME is the name of the function, and ARGi are names of
  8258.           formal arguments to the function.  Blanks are not permitted in
  8259.           the prototype.  The values of variables specified in the list of
  8260.           locals are saved prior to function entry, and restored upon func-
  8261.           tion return.
  8262.  
  8263.             Functions may return a value or variable name by assigning the
  8264.           result to a variable with the same name as the function.  Func-
  8265.           tions return by transferring to one of the reserved labels
  8266.           RETURN, NRETURN, or FRETURN to return by value, by name, or to
  8267.           fail respectively.
  8268.  
  8269.           -----------------------------------------------------------------
  8270.  
  8271.           DETACH(name)                     Remove I/O association
  8272.  
  8273.           Removes any input or output unit associated with the variable
  8274.           name.  The underlying file is not affected in any way.  Remember
  8275.           that name is the address of the variable (e.g. .X or 'X'), not
  8276.           the variable itself.
  8277.  
  8278.           -----------------------------------------------------------------
  8279.  
  8280.           DIFFER(arg1, arg2)               Check if arguments are different
  8281.  
  8282.           Succeeds and returns the null string if and only if arg1 and arg2
  8283.           are different.  Strings and integers are different if they have
  8284.           unequal values.  Other data types contain pointers to the actual
  8285.           data object, and differ only if the pointers are different.  If
  8286.           arg2 is omitted, DIFFER succeeds if arg1 is not null.
  8287.  
  8288.           -----------------------------------------------------------------
  8289.  
  8290.           DUMP(i)                          Dump variables
  8291.  
  8292.           This function causes all natural variables with nonnull values to
  8293.           be listed on the file associated with I/O unit 6 (normally
  8294.           OUTPUT).  If i is zero, the dump does not occur.
  8295.  
  8296.  
  8297.  
  8298.  
  8299.  
  8300.  
  8301.  
  8302.  
  8303.        Reference                      - 128 -              Built-In Functions
  8304.  
  8305.  
  8306.  
  8307.  
  8308.  
  8309.           -----------------------------------------------------------------
  8310.  
  8311.           DUPL(s, i)                       Duplicate string
  8312.  
  8313.           Returns the argument string s repeated i times.  The function
  8314.           returns the null string if i is zero, and fails if i is negative.
  8315.  
  8316.           -----------------------------------------------------------------
  8317.  
  8318.           ENDFILE(unit)                    Close file
  8319.  
  8320.           The file attached to the specified I/O unit is closed, and the
  8321.           file buffer is flushed and released.  All variables which have
  8322.           been associated with this unit have their association removed.
  8323.           Upon program termination, SNOBOL4 will automatically perform an
  8324.           ENDFILE function on all open units.
  8325.  
  8326.           -----------------------------------------------------------------
  8327.  
  8328.           EQ(i1, i2)                       Equality test for numbers
  8329.  
  8330.           This function succeeds and returns the null string if the two
  8331.           integer arguments are equal.  I1 and i2 must evaluate to integer
  8332.           values.  The function fails if i1 is not equal to i2.
  8333.  
  8334.           -----------------------------------------------------------------
  8335.  
  8336.           EVAL(s or n)                     Compile and evaluate expression
  8337.  
  8338.           If the argument is a string, it should contain a valid SNOBOL4
  8339.           expression to be compiled and evaluated.  The evaluation result
  8340.           is returned as the value of the function.  EVAL fails and sets
  8341.           &ERRTEXT to an error message string if s contains a syntactic er-
  8342.           ror.  If the argument is a number, i, it is returned unchanged.
  8343.           If the argument is an unevaluated expression, it is evaluated,
  8344.           and the result returned.
  8345.  
  8346.           -----------------------------------------------------------------
  8347.  
  8348.           FIELD(s, i)                      Get field name of defined data
  8349.                                            type
  8350.  
  8351.           Returns a string which is the Ith field name from the formal def-
  8352.           inition of the program-defined data type whose name is in string
  8353.           s.  FIELD fails if i is greater than the number of fields in the
  8354.           data type's definition.
  8355.  
  8356.           -----------------------------------------------------------------
  8357.  
  8358.           GE(i1, i2)                       Greater than or equal test for
  8359.                                            numbers
  8360.  
  8361.           This function succeeds and returns the null string if the two
  8362.           integer arguments satisfy the relationship i1 >= i2.  I1 and i2
  8363.  
  8364.  
  8365.  
  8366.        Reference                      - 129 -              Built-In Functions
  8367.  
  8368.  
  8369.  
  8370.  
  8371.  
  8372.           must evaluate to integer values.  The function fails if i1 is
  8373.           less than i2.
  8374.  
  8375.           -----------------------------------------------------------------
  8376.  
  8377.           GT(i1,i2)                        Greater than test for numbers
  8378.  
  8379.           This function succeeds and returns the null string if the two in-
  8380.           teger arguments satisfy the relationship i1 > i2.  I1 and i2 must
  8381.           evaluate to integer values.  The function fails if i1 is less
  8382.           than or equal to i2.
  8383.  
  8384.           -----------------------------------------------------------------
  8385.  
  8386.           IDENT(arg1, arg2)                Check if arguments are identical
  8387.  
  8388.           Succeeds and returns the null string if and only if arg1 and arg2
  8389.           are identical.  Strings and integers re identical if they have
  8390.           the same values.  Other data types contain pointers to the actual
  8391.           data object, and are identical only if they point to the same
  8392.           object.  If arg2 is omitted, IDENT succeeds if arg1 is the null
  8393.           string.
  8394.  
  8395.           -----------------------------------------------------------------
  8396.  
  8397.           INPUT(Name, Unit, i, s)          Open file for input
  8398.  
  8399.           This function opens a file for input, and associates it with a
  8400.           variable.  Data may then be read from the file by using the vari-
  8401.           able in an expression or an assignment statement.
  8402.  
  8403.             The file designated by string S is opened for input and given
  8404.           the specified unit number.  I is an optional record length.  The
  8405.           variable specified by Name is associated with this unit.
  8406.  
  8407.             The first argument, Name, specifies a SNOBOL4 variable, typi-
  8408.           cally as a quoted string or with the unary period operator:
  8409.  
  8410.                        INPUT('IN', ...
  8411.                        INPUT(.IN, ...
  8412.                        X = 'IN'
  8413.                        INPUT(X, ...
  8414.  
  8415.             The second argument, Unit, must evaluate to an integer value in
  8416.           the range 0 to 16 inclusive.  Unit 0 (or omitting the unit argu-
  8417.           ment) will select the default input unit, 5.
  8418.  
  8419.             The third argument, I, contains the record length in charac-
  8420.           ters.  0 < I <= &MAXLNGTH.  If omitted, the default is 80.
  8421.  
  8422.             The fourth argument, S, is a string containing the name of the
  8423.           file to be opened.  If the file is a disk file, S may contain an
  8424.           optional drive letter and pathname in addition to the filename.
  8425.           Besides disk files, MS-DOS device names such as NUL:, CON:,
  8426.  
  8427.  
  8428.  
  8429.        Reference                      - 130 -              Built-In Functions
  8430.  
  8431.  
  8432.  
  8433.  
  8434.  
  8435.           COM2:, etc., are permitted.
  8436.  
  8437.             If S is absent or null, and this unit is not currently open,
  8438.           the SNOBOL4 command line is searched for a file to use with this
  8439.           unit (/n:file).  If S is absent, but the unit is already open,
  8440.           the INPUT call serves only to establish another association
  8441.           between a variable and the unit.  If S is not null, any file pre-
  8442.           viously associated with this unit number is first closed by
  8443.           SNOBOL4 with an implicit ENDFILE(unit).
  8444.  
  8445.             An error message is generated for an illegal unit number.  The
  8446.           INPUT function fails (with no printed error message) if the file
  8447.           cannot be opened.
  8448.  
  8449.             The record length I (or its default value, 80), determines the
  8450.           number of characters returned in a string when the associated
  8451.           variable is referenced.  ASCII files will return I characters or
  8452.           less if an end-of-line condition is encountered.  End-of-line is
  8453.           defined as either a carriage return, or a carriage return fol-
  8454.           lowed by a line feed.  If I characters are read from an ASCII
  8455.           file without encountering an end-of-line, additional characters
  8456.           are read from the file and discarded until the end-of-line char-
  8457.           acter(s) are found.  That is, long lines are truncated.  If less
  8458.           than I characters are read from an ASCII file, and keyword &TRIM
  8459.           is zero, the line will be padded with blank characters until
  8460.           length i is obtained.
  8461.  
  8462.             A read operation will terminate on the last character of a disk
  8463.           file, returning a short record.  Reading past the End-of-File
  8464.           will cause statement failure.  If the file is ASCII, reading a
  8465.           control-Z character will be treated as an End-of-File.
  8466.  
  8467.             Note:  When program begins execution, the variable INPUT is
  8468.           associated with unit 5.  Unit 5 is normally device CON:, the key-
  8469.           board, unless redirected elsewhere by the /I=file command line
  8470.           option, or the MS-DOS redirection operation (<file).
  8471.  
  8472.           -----------------------------------------------------------------
  8473.  
  8474.           INTEGER(arg)                     Check if argument is an integer
  8475.  
  8476.           Succeeds and returns the null string if arg is an integer, or a
  8477.           string which can be converted to an integer.  If the argument is
  8478.           not an integer, the function fails.
  8479.  
  8480.           -----------------------------------------------------------------
  8481.  
  8482.           ITEM(array, i1, i2, ..., in)     Get array element
  8483.  
  8484.           ITEM(table, arg)                 Get table element
  8485.  
  8486.           Returns the specified array or table element.  I1, i2, ..., in
  8487.           are array subscripts, and arg is a table subscript.  Since the
  8488.           first argument may be a function which returns an array or table
  8489.  
  8490.  
  8491.  
  8492.        Reference                      - 131 -              Built-In Functions
  8493.  
  8494.  
  8495.  
  8496.  
  8497.  
  8498.           name, it allows an indirect reference in situations that would
  8499.           not be syntactically valid.  ITEM is an analog of the APPLY func-
  8500.           tion.  For example, if F(X) is a program-defined function which
  8501.           returns an array name,
  8502.  
  8503.                        ITEM(F(X), 20)
  8504.  
  8505.           references the 20th element of that array, whereas F(X)<20> is
  8506.           not acceptable.
  8507.  
  8508.           -----------------------------------------------------------------
  8509.  
  8510.           LE(i1, i2)                       Less than or equal test for
  8511.                                            numbers
  8512.  
  8513.           This function succeeds and returns the null string if the two
  8514.           integer arguments satisfy the relationship i1 <= i2.  I1 and i2
  8515.           must evaluate to integer values.  The function fails if i1 is
  8516.           greater than i2.
  8517.  
  8518.           -----------------------------------------------------------------
  8519.  
  8520.           LGT(s1, s2)                      Lexically greater than test for
  8521.                                            strings
  8522.  
  8523.           This function succeeds and returns the null string if s1 is lexi-
  8524.           cally greater than s2 (according to their alphabetic ordering).
  8525.           The two strings are compared left to right, character by charac-
  8526.           ter.  If one string is exhausted before the other---with all
  8527.           characters equal---the longer string is lexically greater than
  8528.           the shorter string.  The null string is lexically less than any
  8529.           other non-null string.  If there is a character mismatch at the
  8530.           same position in both strings, the relationship between the char-
  8531.           acters determines the relationship of the strings.  Strings are
  8532.           equal only if they are the same length, and are identical charac-
  8533.           ter by character.
  8534.  
  8535.           -----------------------------------------------------------------
  8536.  
  8537.           LOCAL(name, i)                   Get local variable name from
  8538.                                            function definition
  8539.  
  8540.           Returns a string which is the Ith local variable from the formal
  8541.           definition of program-defined function name.  LOCAL fails if i is
  8542.           greater than the number of local variables in name's definition.
  8543.           LOCAL is useful when one function is used to trace another.  The
  8544.           trace function can access the local variables used with the func-
  8545.           ion being traced with an indirect reference: $LOCAL(name, i).
  8546.  
  8547.  
  8548.  
  8549.  
  8550.  
  8551.  
  8552.  
  8553.  
  8554.  
  8555.        Reference                      - 132 -              Built-In Functions
  8556.  
  8557.  
  8558.  
  8559.  
  8560.  
  8561.           -----------------------------------------------------------------
  8562.  
  8563.           LPAD(s1, i, s2)                  Pad left end of string
  8564.  
  8565.           This function is useful for right-justifying columnar output.  It
  8566.           returns s1 padded on its left end until its total size is i char-
  8567.           acters.  The pad character used is the first character of s2 if
  8568.           present, otherwise a blank is used if s2 is absent or null.  If i
  8569.           is less than or equal to the length of s1, s1 is returned un-
  8570.           changed.
  8571.  
  8572.           -----------------------------------------------------------------
  8573.  
  8574.           LT(i1, i2)                       Less than test for numbers
  8575.  
  8576.           This function succeeds and returns the null string if the two in-
  8577.           teger arguments satisfy the relationship i1 < i2.  I1 and i2 must
  8578.           evaluate to integer values.  The function fails if i1 is greater
  8579.           than or equal to i2.
  8580.  
  8581.           -----------------------------------------------------------------
  8582.  
  8583.           NE(i1, i2)                       Not equal test for numbers
  8584.  
  8585.           This function succeeds and returns the null string if the two in-
  8586.           teger arguments are not equal.  I1 and i2 must evaluate to inte-
  8587.           ger values.  The function fails if i1 is equal to i2.
  8588.  
  8589.           -----------------------------------------------------------------
  8590.  
  8591.           OPSYN(s1, s2, i)                 Create operator synonym
  8592.  
  8593.           The function or operator name s1 becomes a synonym for s2.  If i
  8594.           is absent or 0, both strings are assumed to be function names.
  8595.           If i is 1 or 2, then the strings are assumed to be unary or
  8596.           binary operators, respectively.  Other values for i are illegal.
  8597.           Operators are specified by using their graphic symbol in a quoted
  8598.           literal, such as:
  8599.  
  8600.                        OPSYN('#', '/', 2)
  8601.  
  8602.             The concatenation operator is specified as a one-character
  8603.           string containing a blank: ' '.  The implicit pattern match oper-
  8604.           ator between subject and pattern cannot be OPSYNed.
  8605.  
  8606.           -----------------------------------------------------------------
  8607.  
  8608.           OUTPUT(name, unit, i, s)         Open file for output
  8609.  
  8610.           This function opens a file for output, and associates it with a
  8611.           variable.  Data may then be written to the file by assigning val-
  8612.           ues to the variable.
  8613.  
  8614.             The description of the OUTPUT function parallels that of the
  8615.  
  8616.  
  8617.  
  8618.        Reference                      - 133 -              Built-In Functions
  8619.  
  8620.  
  8621.  
  8622.  
  8623.  
  8624.           INPUT function, and will not be duplicated here.  The following
  8625.           differences are noted below.
  8626.  
  8627.             If the output file already exists, it is deleted and recreated
  8628.           anew.  Facilities for updating existing files (direct-access
  8629.           files) are not present in Vanilla SNOBOL4; they are contained in
  8630.           SNOBOL4+, Catspaw's enhanced implementation of the SNOBOL4 lan-
  8631.           guage.
  8632.  
  8633.             When an output variable is assigned a string value, the string
  8634.           is written to the associated file.  A carriage return and line
  8635.           feed appended to the string.  If the string is longer than the
  8636.           record length (i, or the default, 80), a carriage return and line
  8637.           feed will be inserted every i characters.  That is, long strings
  8638.           will create multiple output lines.
  8639.  
  8640.             Note:  When a program begins execution, the variable OUTPUT is
  8641.           associated with unit 6.  Unit 6 is normally device CON:, the dis-
  8642.           play, unless redirected elsewhere by the /O: command line option
  8643.           or the MS-DOS redirection operation (>file).  The variable SCREEN
  8644.           is associated with unit 7, which is also attached to device CON:.
  8645.  
  8646.           -----------------------------------------------------------------
  8647.  
  8648.           PROTOTYPE(array)                 Get prototype which created an
  8649.                                            array
  8650.  
  8651.           Returns the prototype string of dimensions used to create the
  8652.           specified array.  If the array was created by the ARRAY function,
  8653.           then the string returned is identical to the first argument of
  8654.           the original ARRAY function call.  If the array was produced from
  8655.           a table by the CONVERT function, the string has the form 'N,2',
  8656.           where N is the integer number of rows in the array.
  8657.  
  8658.           -----------------------------------------------------------------
  8659.  
  8660.           REMDR(i1, i2)                    Get remainder after division
  8661.  
  8662.           REMDR returns the integer remainder resulting from i1 divided by
  8663.           i2, that is, i1 modulus i2.  The result has the same sign as i1.
  8664.  
  8665.           -----------------------------------------------------------------
  8666.  
  8667.           REPLACE(s1, s2, s3)              Replace characters in string
  8668.  
  8669.           This function returns s1 transformed according to a translation
  8670.           specified by s2 and s3.  Each character of s1 found in s2 is re-
  8671.           placed by the corresponding character in s3.  S2 and s3 must be
  8672.           the same length.  If duplicate characters appear in s2, the
  8673.           rightmost one is used to obtain the mapping character from s3.
  8674.           Normally, s2 and s3 are thought of as parameters, and REPLACE
  8675.           performs character substitutions on the variable s1.  For
  8676.           instance:
  8677.  
  8678.  
  8679.  
  8680.  
  8681.        Reference                      - 134 -              Built-In Functions
  8682.  
  8683.  
  8684.  
  8685.  
  8686.  
  8687.                        REPLACE(S, 'aeiouAEIOU', '1234512345')
  8688.  
  8689.           replaces all upper- and lower-case vowels in S with the digits 1
  8690.           through 5.  It is possible to use REPLACE as a "transposition"
  8691.           function if s1 and s2 are considered parameters, and s3 allowed
  8692.           to vary.  If s1 and s2 are the same length, a simple positional
  8693.           transformation results.  For example,
  8694.  
  8695.                        REPLACE('123456', '214365', S)
  8696.  
  8697.           returns the six character string S with adjacent pairs of charac-
  8698.           ters interchanged ('ABCDEF' becomes 'BADCFE').  S1 and s2 can be
  8699.           different lengths---only s2 and s3 must be the same size.  If s2
  8700.           contains characters not in s1, the corresponding characters in s3
  8701.           are dropped from the result.  If s1 contains characters not in
  8702.           s2, they will appear in the result.  The function call
  8703.  
  8704.                        REPLACE('Yy/Mm/Dd', 'Mm-Dd-Yy xx:xx:xx.xx', DATE())
  8705.  
  8706.           returns the date in the form YY/MM/DD (e.g., 87/07/28).  Dupli-
  8707.           cate characters in s1 are permitted, so:
  8708.  
  8709.                        REPLACE('aaabbbccc', 'abc' '(1)')
  8710.  
  8711.           produces '(((111)))'.
  8712.  
  8713.           -----------------------------------------------------------------
  8714.  
  8715.           RPAD(s1, i, s2)                  Pad right end of string
  8716.  
  8717.           This function is useful for left-justifying columnar output.  It
  8718.           returns s1 padded on its right end until its total size is i
  8719.           characters.  The pad character used is the first character of s2
  8720.           if present, otherwise a blank (ASCII character 32) is used if s2
  8721.           is absent or null.  If i is less than or equal to the length of
  8722.           s1, s1 is returned unchanged.
  8723.  
  8724.           -----------------------------------------------------------------
  8725.  
  8726.           SIZE(s)                          Get length of string
  8727.  
  8728.           The function SIZE returns an integer value which is the number of
  8729.           characters in its argument string.  A null string argument
  8730.           returns 0.
  8731.  
  8732.           -----------------------------------------------------------------
  8733.  
  8734.           STOPTR(name, type)               Stop trace
  8735.  
  8736.           Discontinues the type of trace of the named item.  Consult the
  8737.           TRACE() function for a list of tracing types available.
  8738.  
  8739.  
  8740.  
  8741.  
  8742.  
  8743.  
  8744.        Reference                      - 135 -              Built-In Functions
  8745.  
  8746.  
  8747.  
  8748.  
  8749.  
  8750.           -----------------------------------------------------------------
  8751.  
  8752.           TABLE(i1, i2)                    Create a table
  8753.  
  8754.           A table is similar to a one-dimensional array, but the subscripts
  8755.           may be any SNOBOL4 data type.  The TABLE function creates a table
  8756.           and returns a pointer to it.  The integer i1 specifies the ini-
  8757.           tial number of entries in the table.  Integer i2 specifies the
  8758.           size by which the table is increased whenever it becomes full,
  8759.           and additional table space is required.  If either is omitted, 10
  8760.           is used as a default value.
  8761.  
  8762.           -----------------------------------------------------------------
  8763.  
  8764.           TIME()                           Get execution time
  8765.  
  8766.           Returns the number of tenths of a second elapsed since the start
  8767.           of program execution, including all I/O wait time.
  8768.  
  8769.           -----------------------------------------------------------------
  8770.  
  8771.           TRACE(name1, type, s, name2)     Trace an entity
  8772.  
  8773.           The item name1 is traced according to the action specified by
  8774.           type.  Trace output is written to the file associated with I/O
  8775.           unit 6.
  8776.  
  8777.             Name1 is a the name of a variable, function, statement label,
  8778.           or keyword.  It may appear as a string, or specified with the
  8779.           unary name operator (.).
  8780.  
  8781.             Type is a string that determines the type of trace desired.  It
  8782.           must be one of these values:
  8783.  
  8784.              'VALUE'          When value of name1 is changed (default if
  8785.                               type omitted).
  8786.  
  8787.              'CALL'           When function name1 is called.
  8788.  
  8789.              'RETURN'         When function name1 returns.
  8790.  
  8791.              'FUNCTION'       When function name1 is called, or returns.
  8792.  
  8793.              'LABEL'          When control is transferred to label name1.
  8794.  
  8795.              'KEYWORD'        When the value of keyword &name1 is changed.
  8796.                               Note that the ampersand character (&) is not
  8797.                               included in the first argument, name1.
  8798.  
  8799.             S is an optional identifying tag that is added to the trace
  8800.           output line when name1 is a created object, such as an array or
  8801.           table element.
  8802.  
  8803.             Name2 is an optional name of a program-defined function.
  8804.  
  8805.  
  8806.  
  8807.        Reference                      - 136 -              Built-In Functions
  8808.  
  8809.  
  8810.  
  8811.  
  8812.  
  8813.           Instead of producing a trace output line, this function is called
  8814.           when the trace action occurs.  The function is called with name1
  8815.           as the first argument, and string s as the second argument.
  8816.  
  8817.             Tracing will only occur when the keyword &TRACE is nonzero.
  8818.           Each trace will decrement &TRACE by one.  Tracing ends when it
  8819.           becomes zero.
  8820.  
  8821.           -----------------------------------------------------------------
  8822.  
  8823.           TRIM(s)                          Remove trailing blanks
  8824.  
  8825.           Returns the argument string with trailing blanks removed.  Trail-
  8826.           ing tab characters are not affected.  If the argument string was
  8827.           read from an input file, it is more efficient to set keyword
  8828.           &TRIM nonzero than to use TRIM(INPUT).
  8829.  
  8830.             By combining function TRIM with REPLACE, any trailing character
  8831.           can be removed.  The desired character is temporarily exchanged
  8832.           with blank, trimmed, then exchanged back.  For example, this
  8833.           expression returns string S with trailing zeros removed:
  8834.  
  8835.                        REPLACE(TRIM(REPLACE(S,'0 ',' 0')),'0 ',' 0')
  8836.  
  8837.           -----------------------------------------------------------------
  8838.  
  8839.           UNLOAD(name)                     Remove function definition
  8840.  
  8841.           The function name becomes undefined.
  8842.  
  8843.           -----------------------------------------------------------------
  8844.  
  8845.           VALUE(name)                      Get value of an object
  8846.  
  8847.           The VALUE function returns the value of the variable name,
  8848.           behaving like the unary indirect operator ($).
  8849.  
  8850.  
  8851.  
  8852.  
  8853.  
  8854.  
  8855.  
  8856.  
  8857.  
  8858.  
  8859.  
  8860.  
  8861.  
  8862.  
  8863.  
  8864.  
  8865.  
  8866.  
  8867.  
  8868.  
  8869.  
  8870.        Reference                      - 137 -              Built-In Functions
  8871.  
  8872.  
  8873.  
  8874.  
  8875.  
  8876.                                                                  Chapter 20
  8877.  
  8878.  
  8879.                                                             SYSTEM MESSAGES
  8880.           -----------------------------------------------------------------
  8881.  
  8882.             This chapter lists all messages displayed by SNOBOL4.
  8883.  
  8884.  
  8885.                                 20.1 INITIAL MESSAGES
  8886.  
  8887.             When SNOBOL4 begins execution, this title is displayed:
  8888.  
  8889.                Vanilla SNOBOL4      Version 2.14.
  8890.                (c) Copyright 1984,1988 Catspaw, Inc. All Rights Reserved.
  8891.  
  8892.             Additional messages which may appear:
  8893.  
  8894.           Cannot open file: name
  8895.           The file specified in the command line cannot be opened.
  8896.  
  8897.           Command line error:
  8898.           A syntactic error was detected in the SNOBOL4 command line.  The
  8899.           command line is displayed on two lines.  The line break shows
  8900.           where the error occurred.
  8901.  
  8902.           Errors detected in source program
  8903.           There were compilation errors in the source program.  Execution
  8904.           will proceed until a statement with a compilation error is
  8905.           encountered.
  8906.  
  8907.           Insufficient storage for initialization
  8908.           Not enough memory was available to initialize the SNOBOL4 system.
  8909.  
  8910.           No errors
  8911.           Compilation is complete, and without error.  Execution begins
  8912.           immediately.
  8913.  
  8914.  
  8915.                               20.2 TERMINATION MESSAGES
  8916.  
  8917.             Termination messages are normally produced on I/O unit 7, which
  8918.           defaults to the user's display screen.  If the /B option was used
  8919.           in the invoking command line, they are produced on I/O unit 6,
  8920.           associated with variable OUTPUT.  Dump messages are always pro-
  8921.           duced to unit 6.
  8922.  
  8923.           Normal termination at level LL
  8924.           The program transferred to the label END.  LL is the current
  8925.           program-defined function call depth.  This message is produced
  8926.           only if the /S command line option (statistics) was used.
  8927.  
  8928.  
  8929.  
  8930.  
  8931.  
  8932.  
  8933.        Reference                      - 138 -                 System Messages
  8934.  
  8935.  
  8936.  
  8937.  
  8938.  
  8939.           filename(XXX) : Last statement executed was NNN
  8940.           NNN is the statement number of the last statement executed, XXX
  8941.           is its source line number.  It is the statement that transferred
  8942.           to the END statement.  If this was a normal termination, it is
  8943.           only displayed if the /S option was used.
  8944.  
  8945.           filename(XXX) : Warning: Interrupted in statement NNN at level LL
  8946.           Execution was interrupted when you pressed the BREAK or control-C
  8947.           key.  The interruption occurred before the specified statement
  8948.           was executed.  LL is the current call depth of program-defined
  8949.           functions.
  8950.  
  8951.           Incomplete storage regeneration.  Terminal dump not possible
  8952.           Stack overflow occurred during storage regeneration, and the
  8953.           &DUMP keyword was nonzero.  Memory is in an indeterminate form,
  8954.           and a dump listing cannot be produced.
  8955.  
  8956.           Dump of variables at termination
  8957.           Natural variables
  8958.           Unprotected keywords
  8959.           These headings will appear if a termination dump was requested by
  8960.           setting the &DUMP keyword nonzero.  Variables are listed only if
  8961.           they contain a nonnull value.  The variable names will be sorted
  8962.           if the &DUMP keyword is positive; they are unsorted if it is
  8963.           negative.
  8964.  
  8965.  
  8966.           20.2.1 Job Statistics
  8967.  
  8968.             End-of-run statistics on program execution are provided if the
  8969.           /S command line option is used.  Compilation and execution times
  8970.           are in tenths of a second.  Times are wall-clock values, and
  8971.           include all I/O wait time, such as delays for keyboard input:
  8972.  
  8973.                        SNOBOL4 statistics summary-
  8974.                        NN tenths of a second compilation time
  8975.                        NN tenths of a second execution time
  8976.                        NN statements executed, NN failed
  8977.                        NN arithmetic operations performed
  8978.                        NN pattern matches performed
  8979.                        NN regenerations of dynamic storage
  8980.                        NN reads performed
  8981.                        NN writes performed
  8982.  
  8983.  
  8984.                               20.3 COMPILATION MESSAGES
  8985.  
  8986.             SNOBOL4 syntax errors are detected during compilation.  State-
  8987.           ment compilation ceases at the point where the error was de-
  8988.           tected.  The error message contains a marker which indicates the
  8989.           valid portion of the statement accepted by the compiler---the
  8990.           error occurred after this point.  Only the first error in a
  8991.           statement is detected.  The erroneous statement is compiled with
  8992.           an internal error code which produces an error message if the
  8993.  
  8994.  
  8995.  
  8996.        Reference                      - 139 -                 System Messages
  8997.  
  8998.  
  8999.  
  9000.  
  9001.  
  9002.           statement is executed.  Compilation resumes with the next state-
  9003.           ment.  Compilation ceases and SNOBOL4 terminates if more than 50
  9004.           errors are found.
  9005.  
  9006.             When compiling without a list file (/L: command line option),
  9007.           the compiler will attempt to display the erroneous line on your
  9008.           screen.  If a statement is continued over several lines, only the
  9009.           line in error is displayed.  Several errors cannot be detected
  9010.           until the absolute end-of-statement is found.  This may require
  9011.           reading the next line, and finding it is NOT a continuation
  9012.           statement.  In this case, the single line displayed will be the
  9013.           NEXT line, with the error marker in the first character position.
  9014.  
  9015.             The CODE function may be used to compile SNOBOL4 statements
  9016.           that have been concatenated into a long string.  The CODE func-
  9017.           tion fails if a syntax error is found, and the keyword &ERRTEXT
  9018.           contains the error message string for the error encountered.
  9019.  
  9020.           Binary operators must be surrounded by blanks
  9021.           Omitting a blank will often cause this error.  An illegal or
  9022.           undefined binary operator will also produce this error.
  9023.  
  9024.           Error in GOTO
  9025.           There is a syntactic error in the GOTO field.
  9026.  
  9027.           Erroneous END statement
  9028.           The END statement contains a syntactic error, or the label speci-
  9029.           fied in the subject field for initial transfer could not be
  9030.           found.
  9031.  
  9032.           Erroneous integer
  9033.           An integer number appears which is too large for the SNOBOL4 sys-
  9034.           tem.  The allowable range for magnitude values is 0 to 32767.
  9035.  
  9036.           Erroneous label
  9037.           The first character of a statement must be blank, tab, alphanu-
  9038.           meric, * (comment), + or . (continuation), or - (control).
  9039.  
  9040.           Erroneous or missing break character
  9041.           A character which separates language elements occurs in an ille-
  9042.           gal context, or an expression is not balanced with respect to
  9043.           parentheses.
  9044.  
  9045.           Erroneous subject
  9046.           A compiler break character appears before the statement subject
  9047.           field.  The break characters are comma, equal sign, right paren-
  9048.           thesis, right square bracket (]), and right angular bracket (>).
  9049.  
  9050.           Illegal character in element
  9051.           A character was found which was incorrect for the type of lan-
  9052.           guage object being compiled.  This often occurs when a blank is
  9053.           omitted between elements, causing them to run together.
  9054.  
  9055.  
  9056.  
  9057.  
  9058.  
  9059.        Reference                      - 140 -                 System Messages
  9060.  
  9061.  
  9062.  
  9063.  
  9064.  
  9065.           Improperly terminated statement
  9066.           The source statement terminated with an incomplete language con-
  9067.           struction.
  9068.  
  9069.           Limit on compilation errors exceeded
  9070.           More than 50 compilation errors were found in the source program.
  9071.  
  9072.           No END statement in source file
  9073.           End-of-File was encountered in the source file without an END
  9074.           statement.
  9075.  
  9076.           Previously defined label
  9077.           A duplicate label appears.  The first definition is retained;
  9078.           subsequent definitions are discarded.
  9079.  
  9080.           Unclosed literal
  9081.           The closing quotation mark from a literal string is missing.
  9082.           This error also occurs if the closing quotation mark (single or
  9083.           double) was different from the opening mark.
  9084.  
  9085.  
  9086.                             20.4 EXECUTION ERROR MESSAGES
  9087.  
  9088.             Most program logic errors can only be detected during program
  9089.           execution.  Some are unconditionally fatal, and cause the SNOBOL4
  9090.           system to terminate.  Others are conditionally fatal---the system
  9091.           terminates if the value of the keyword &ERRLIMIT is zero.  If
  9092.           &ERRLIMIT is nonzero, the keyword &ERRTYPE is set to the error
  9093.           message number, &ERRTEXT is set to the message text, &ERRLIMIT is
  9094.           decremented, and execution continues.
  9095.  
  9096.             The protected keyword &ERRTYPE may be traced, permitting a
  9097.           program-defined function to gain control when a conditional error
  9098.           occurs.  THe program CODE.SNO provides an example of how to do
  9099.           this.  The initial value of the unprotected keyword &ERRLIMIT is
  9100.           zero, forcing program termination upon any error.
  9101.  
  9102.             Errors 1-16 are conditionally fatal.  Errors 17-28 are uncondi-
  9103.           tionally fatal.  When execution terminates due to an error, the
  9104.           following is displayed:
  9105.  
  9106.                filename(XXX) : Error NN, -- description --
  9107.                In statement NNN, at level LL
  9108.  
  9109.           NN is the error number below.  NNN is the statement number
  9110.           assigned in the compiler list file, XXX is the absolute line
  9111.           number in the source file.  LL specifies the current program-
  9112.           defined function call depth (0 is the normal main-program level).
  9113.  
  9114.           1. Illegal data type
  9115.           The data type of an operand was incorrect for the type of opera-
  9116.           tion attempted.  This occurs most frequently with arithmetic op-
  9117.           erations, when one operand is a string which cannot be converted
  9118.           to a number.
  9119.  
  9120.  
  9121.  
  9122.        Reference                      - 141 -                 System Messages
  9123.  
  9124.  
  9125.  
  9126.  
  9127.  
  9128.           2. Error in arithmetic operation
  9129.           An arithmetic operation upon integer values produced a result
  9130.           which was out of range, or was undefined, such as division by
  9131.           zero.
  9132.  
  9133.           3. Erroneous array or table reference
  9134.           An array or table reference was made to a variable which did not
  9135.           contain an array or table pointer.
  9136.  
  9137.           4. Null string in illegal context
  9138.           The null string appeared where it is not permitted, such as the
  9139.           object of an indirect reference.
  9140.  
  9141.           5. Undefined function or operation
  9142.           A function was called before it was defined, or an undefined
  9143.           operator was used.
  9144.  
  9145.           6. Erroneous prototype
  9146.           A syntactic error occurred in the prototype string used with the
  9147.           functions ARRAY, DATA or DEFINE.  Note that the blank and tab
  9148.           characters are not permitted within the prototype string.
  9149.  
  9150.           7. Unknown keyword
  9151.           The keyword specified is unknown to the SNOBOL4 system.
  9152.  
  9153.           8. Variable not present where required
  9154.           A variable name must be used as the subject of an assignment
  9155.           statement, or as the argument of the unary cursor, name, or key-
  9156.           word operator (@, ., &), or the binary pattern match assignment
  9157.           operators (., $).
  9158.  
  9159.           9. Entry point of function not label
  9160.           At the time a program-defined function was first called, its
  9161.           entry point label did not appear as the label of any SNOBOL4
  9162.           statement.
  9163.  
  9164.           10. Illegal argument to primitive function
  9165.           An illegal value was used as an argument to the function ARG,
  9166.           FIELD, LOCAL, OPSYN, STOPTR, or TRACE, or an illegal value was
  9167.           specified in the third argument to INPUT or OUTPUT.
  9168.  
  9169.           11. Reading error
  9170.           An error condition was returned when reading from a file.
  9171.  
  9172.           12. Illegal I/O unit
  9173.           Allowable unit numbers are 1 through 16 (inclusive).  (Unit 0 is
  9174.           allowed in functions INPUT and OUTPUT, and is converted to units
  9175.           5 and 6 respectively.)
  9176.  
  9177.           13. Limit on defined data types exceeded
  9178.           SNOBOL4 allows 899 different program-defined data types.
  9179.  
  9180.  
  9181.  
  9182.  
  9183.  
  9184.  
  9185.        Reference                      - 142 -                 System Messages
  9186.  
  9187.  
  9188.  
  9189.  
  9190.  
  9191.           14. Negative number in illegal context
  9192.           A negative number was used incorrectly as the argument of the
  9193.           function LEN, POS, TAB, or RTAB.
  9194.  
  9195.           15. String overflow
  9196.           The program attempted to create a string larger than &MAXLNGTH
  9197.           characters.
  9198.  
  9199.           16. Overflow during pattern matching
  9200.           The internal SNOBOL4 stack overflowed during pattern matching.
  9201.           This can happen when a recursive or looping pattern is incor-
  9202.           rectly specified.
  9203.  
  9204.           17. Error in SNOBOL4 system
  9205.           This message indicates an internal SNOBOL4 system error.
  9206.  
  9207.           18. Return from level zero
  9208.           An attempt was made to transfer to the function return label
  9209.           RETURN, FRETURN, or NRETURN outside of any function call.
  9210.  
  9211.           19. Failure during GOTO evaluation
  9212.           The expression used for an indirect transfer within the GOTO
  9213.           field failed when evaluated.
  9214.  
  9215.           20. Insufficient storage to continue
  9216.           All available memory has been used.  Vanilla SNOBOL4 is limited
  9217.           to 30K bytes for program and data.  SNOBOL4+, Catspaw's enhanced
  9218.           version, allocates 300K bytes for program and data.
  9219.  
  9220.           21. Stack overflow
  9221.           The SNOBOL4 internal stack has overflowed.  This may be caused by
  9222.           excessive function recursion, or occur during memory garbage
  9223.           collection.
  9224.  
  9225.           22. Limit on statement execution exceeded
  9226.           The number of statements executed was greater than the value in
  9227.           the keyword &STLIMIT.  &STLIMIT is initially -1, specifying
  9228.           unlimited execution.
  9229.  
  9230.           23. Object exceeds size limit
  9231.           The program attempted to create an object larger than the maximum
  9232.           size allowed.
  9233.  
  9234.           24. Undefined or erroneous GOTO
  9235.           A transfer was attempted to an undefined label, or an expression
  9236.           in a GOTO field evaluated to a string, rather than a label
  9237.           name---usually the result of omitting the indirect operator ($).
  9238.  
  9239.           25. Incorrect number of arguments
  9240.           A primitive function was called with too many arguments.
  9241.  
  9242.           28. Execution of statement with compilation error
  9243.           Execution proceeded to a statement that contained a compilation
  9244.           error.
  9245.  
  9246.  
  9247.  
  9248.        Reference                      - 143 -                 System Messages
  9249.  
  9250.  
  9251.  
  9252.  
  9253.  
  9254.                             20.5 EXECUTION TRACE MESSAGES
  9255.  
  9256.             Tracing is provided for variables, certain keywords, label
  9257.           transfers, and function calls and returns.  A trace message is
  9258.           output to I/O unit 6 for each trace occurrence.  Program execu-
  9259.           tion time, in tenths of a second, is appended to each message.
  9260.  
  9261.             Tracing normally occurs only if the keyword &TRACE is nonzero.
  9262.           However, another keyword, &FTRACE, may be set nonzero to trace
  9263.           all function calls and returns independently of keyword &TRACE.
  9264.  
  9265.           STATEMENT NN: <vname> = <value>,TIME = TT
  9266.           Value trace; produced by the function call TRACE('vname',
  9267.           'VALUE'), where vname is the name of the variable to be traced.
  9268.  
  9269.           STATEMENT NN: &<keyname> = <value>,TIME = TT
  9270.           Keyword trace; produced by the function call TRACE('keyname',
  9271.           'KEYWORD'), where keyname is the upper case keyword name, without
  9272.           the leading ampersand.
  9273.  
  9274.           STATEMENT NN: TRANSFER TO <labname>,TIME = TT
  9275.           Label trace; produced by the function call TRACE('labname',
  9276.           'LABEL'), where labname is the desired label name.  Tracing only
  9277.           occurs on a transfer of control; it does not occur if the labeled
  9278.           statement is flowed into.
  9279.  
  9280.           STATEMENT NN: LEVEL LL CALL OF <fname>(arg1,...,argn),TIME = TT
  9281.           Call trace; produced by the function call TRACE('fname', 'CALL'),
  9282.           where fname is the name of the function to be traced.  The func-
  9283.           tion's arguments at the time of the call are evaluated and dis-
  9284.           played.
  9285.  
  9286.           STATEMENT NN: LEVEL LL RETURN OF <fname> = <value>,TIME = TT
  9287.           STATEMENT NN: LEVEL LL NRETURN OF <fname> = <value>,TIME = TT
  9288.           STATEMENT NN: LEVEL LL FRETURN OF <fname>,TIME = TT
  9289.           Return trace; produced by the function call TRACE('fname',
  9290.           'RETURN'), where fname is the name of the function whose return
  9291.           is to be traced.  The type of return that occurred is displayed
  9292.           in the trace message.
  9293.  
  9294.           ***Print request too long***
  9295.           An internal buffer is used to display trace messages, and vari-
  9296.           able values during dumps.  If the required display is longer than
  9297.           1,800 characters, this error message is produced instead.
  9298.  
  9299.  
  9300.  
  9301.  
  9302.  
  9303.  
  9304.  
  9305.  
  9306.  
  9307.  
  9308.  
  9309.  
  9310.  
  9311.        Reference                      - 144 -                 System Messages
  9312.