Annotation of 43BSD/contrib/icon/docs/tr83-3, revision 1.1

1.1     ! root        1: .so tmac.tr
        !             2: .DA "May 13, 1983"
        !             3: .TR 83-3a
        !             4: .GR MCS81-01916
        !             5: .GE
        !             6: .TL
        !             7: An Overview of the Icon Programming Language
        !             8: .AU
        !             9: Ralph E. Griswold
        !            10: .AE
        !            11: .tr *\(**
        !            12: .NH
        !            13: Introduction
        !            14: .PP
        !            15: Icon is a high-level programming language with extensive facilities for
        !            16: processing strings and lists. Icon has several novel features, including
        !            17: expressions that may produce sequences of results, goal-directed
        !            18: evaluation that automatically searches for a successful result, and
        !            19: string scanning that allows operations on strings to be formulated at
        !            20: a high conceptual level.
        !            21: .PP
        !            22: Icon resembles SNOBOL4 [1] in its emphasis on high-level string
        !            23: processing and a design philosophy that allows ease of programming
        !            24: and short, concise programs. Like SNOBOL4, storage allocation and
        !            25: garbage collection are automatic in Icon, and there are few restrictions on the
        !            26: sizes of objects. Strings, lists, and other structures are created
        !            27: during program execution and their size does not need to be known when
        !            28: a program is written.
        !            29: Values are converted to expected types automatically; for example,
        !            30: numeral strings read in as input can be used in numerical computations
        !            31: without explicit conversion.
        !            32: Whereas SNOBOL4 has a pattern-matching facility that is separate from
        !            33: the rest of the language, string scanning is integrated with the
        !            34: rest of the language facilities in Icon.
        !            35: Unlike SNOBOL4,
        !            36: Icon has an expression-based syntax with reserved words;
        !            37: in appearance, Icon programs resemble those of several other conventional programming
        !            38: languages.
        !            39: .PP
        !            40: Examples of the kinds of problems for which Icon is well suited are:
        !            41: .in .5i
        !            42: .IP \(bu
        !            43: text analysis, editing, and reformatting
        !            44: .IP \(bu
        !            45: document preparation
        !            46: .IP \(bu
        !            47: symbolic mathematics
        !            48: .IP \(bu
        !            49: text generation
        !            50: .IP \(bu
        !            51: program parsing and translation
        !            52: .IP \(bu
        !            53: data laundry
        !            54: .IP \(bu
        !            55: graph manipulation
        !            56: .in 0
        !            57: .PP
        !            58: Icon is implemented in C [2] and runs under UNIX\u*\d
        !            59: .FS
        !            60: \u*\dUNIX is a trademark of Bell Laboratories.
        !            61: .FE
        !            62: on the PDP-11, VAX-11, and Onyx C8002 computers. Implementations for
        !            63: other computers and operating systems are presently underway.
        !            64: An earlier version of Icon [3] is available on several large-scale
        !            65: computers, including the CRAY-1, DEC-10, IBM 360/370, PRIME 450/550/650, DG
        !            66: MV8000,
        !            67: and CDC Cyber/6000.
        !            68: .PP
        !            69: A brief description of some of the representative features of Icon
        !            70: is given in the following sections. This description is not rigorous
        !            71: and does not include many features of Icon. See [4] for a
        !            72: complete description.
        !            73: .NH
        !            74: Strings
        !            75: .PP
        !            76: Strings of characters may be arbitrarily long, limited only by the
        !            77: architecture of the computer on which Icon is implemented. A string
        !            78: may be specified literally by enclosing it in double quotation marks,
        !            79: as in
        !            80: .Ds
        !            81: greeting := "Hello world"
        !            82: .De
        !            83: which assigns an 11-character string to \*Mgreeting\fR, and
        !            84: .Ds
        !            85: address := ""
        !            86: .De
        !            87: which assigns the zero-length \fIempty\fR string to \*Maddress\fR.
        !            88: The number of characters in a string \*Ms\fR, its size, is given
        !            89: by \*M*s\fR. For example, \*M*greeting\fR is 11 and \*M*address\fR
        !            90: is 0.
        !            91: .PP
        !            92: Icon uses the ASCII character set, extended to 256 characters.
        !            93: There are escape conventions, similar to those of C, for representing
        !            94: characters that cannot be keyboarded.
        !            95: .PP
        !            96: Strings also can be read in and written out, as in
        !            97: .Ds
        !            98: line := read()
        !            99: .De
        !           100: and
        !           101: .Ds
        !           102: write(line)
        !           103: .De
        !           104: Strings can be constructed by concatenation, as in
        !           105: .Ds
        !           106: element := "(" || read() || ")"
        !           107: .De
        !           108: If the concatenation of a number of strings is to be written
        !           109: out, the \*Mwrite\fR function can be used with several arguments
        !           110: to avoid actual concatenation:
        !           111: .Ds
        !           112: write("(",read(),")")
        !           113: .De
        !           114: .PP
        !           115: Substrings can be formed by subscripting strings with range
        !           116: specifications that indicate, by position, the desired range of
        !           117: characters. For example,
        !           118: .Ds
        !           119: middle := line\^[10:20]
        !           120: .De
        !           121: assigns to \*Mmiddle\fR the string of characters of \*Mline\fR between
        !           122: positions 10 and 20.
        !           123: Similarly,
        !           124: .Ds
        !           125: write(line\^[2])\fR
        !           126: .De
        !           127: writes the second character of \*Mline\fR.
        !           128: The value 0 is used to refer to the position after the last character
        !           129: of a string. Thus
        !           130: .Ds
        !           131: write(line\^[2:0])
        !           132: .De
        !           133: writes the substring of \*Mline\fR from the second character to the end, thus
        !           134: omitting the first character.
        !           135: .PP
        !           136: An assignment can be made to the substring of string-valued variable
        !           137: to change its value. For example,
        !           138: .Ds
        !           139: line[2] := "..."
        !           140: .De
        !           141: replaces the second character of \*Mline\fR by three dots. Note that
        !           142: the size of \*Mline\fR changes automatically.
        !           143: .PP
        !           144: There are many functions for analyzing strings. An example is
        !           145: .Ds
        !           146: find(s1,\*bs2)
        !           147: .De
        !           148: which produces the position in \*Ms2\fR at which \*Ms1\fR occurs as
        !           149: a substring. For example, if the value of \*Mgreeting\fR is as
        !           150: given earlier,
        !           151: .Ds
        !           152: find("or",\*bgreeting)
        !           153: .De
        !           154: produces the value 8.
        !           155: See Section 4.2 for the handling of situations in which \*Ms1\fR does not
        !           156: occur in \*Ms2\fR, or in which it occurs at several different positions.
        !           157: .NH
        !           158: Character Sets
        !           159: .PP
        !           160: While strings are sequences of characters, \fIcsets\fR are sets of characters
        !           161: in which membership rather than order is significant. Csets are
        !           162: represented literally using single enclosing quotation marks, as
        !           163: in
        !           164: .Ds
        !           165: vowels := 'aeiouAEIOU'
        !           166: .De
        !           167: Two useful built-in csets are \*M&lcase\fR and \*M&ucase\fR, which
        !           168: consist of the lowercase and uppercase letters, respectively.
        !           169: Set operations are provided for csets. For example,
        !           170: .Ds
        !           171: letters := &lcase ++ &ucase
        !           172: .De
        !           173: forms the cset union of the lowercase and uppercase letters and assigns the
        !           174: resulting cset to \*Mletters\fR, while
        !           175: .Ds
        !           176: consonants := letters -- 'aeiouAEIOU'
        !           177: .De
        !           178: forms the cset difference of the letters and the vowels and assigns the
        !           179: resulting cset to \*Mconsonants\fR.
        !           180: .PP
        !           181: Csets are useful in situations in which any one of a number of characters
        !           182: is significant. An example is the string analysis function
        !           183: .Ds
        !           184: upto(c,\*bs)
        !           185: .De
        !           186: which produces the position \*Ms\fR at which any character in \*Mc\fR occurs.
        !           187: For example,
        !           188: .Ds
        !           189: upto(vowels,\*bgreeting)
        !           190: .De
        !           191: produces 2. Another string analysis function that uses csets is
        !           192: .Ds
        !           193: many(c,\*bs)
        !           194: .De
        !           195: which produces the position in \*Ms\fR after an initial substring consisting
        !           196: only of characters that occur in \*Ms\fR.
        !           197: An example of the use of \*Mmany\fR is in locating words. Suppose, for
        !           198: example, that a word is defined to consist of a string of letters.
        !           199: The expression
        !           200: .Ds
        !           201: write(line\^[1:many(letters,\*bline)])
        !           202: .De
        !           203: writes a word at the beginning of \*Mline\fR. Note the use of the
        !           204: position returned by a string analysis function to specify the
        !           205: end of a
        !           206: substring.
        !           207: .NH
        !           208: Expression Evaluation
        !           209: .NH 2
        !           210: Conditional Expressions
        !           211: .PP
        !           212: In Icon there are \fIconditional expressions\fR that may \fIsucceed\fR and
        !           213: produce a result, or may \fIfail\fR and not produce any result. An example
        !           214: is the comparison operation
        !           215: .Ds
        !           216: i > j
        !           217: .De
        !           218: which succeeds (and produces the value of \*Mj\fR) provided that the value
        !           219: of \*Mi\fR is greater than the value of \*Mj\fR, but fails otherwise.
        !           220: .PP
        !           221: The success or failure of conditional operations is used instead of
        !           222: Boolean values to drive control structures in Icon. An example is
        !           223: .Ds
        !           224: if i > j then k := i else k := j
        !           225: .De
        !           226: which assigns the value of \*Mi\fR to \*Mk\fR if the value of \*Mi\fR
        !           227: is greater than the value of \*Mj\fR, but assigns the value of \*Mj\fR to
        !           228: \*Mk\fR \%otherwise.
        !           229: .PP
        !           230: The usefulness of the concepts of success and failure is illustrated by
        !           231: \*Mfind(s1,\*bs2)\fR, which fails
        !           232: if \*Ms1\fR does not occur as a substring of \*Ms2\fR.
        !           233: Thus
        !           234: .Ds
        !           235: if i := find("or",line) then write(i)
        !           236: .De
        !           237: writes the position at which \*Mor\fR occurs in \*Mline\fR, if it occurs,
        !           238: but does not write a value if it does not occur.
        !           239: .PP
        !           240: Many expressions in Icon are conditional. An example is \*Mread()\fR,
        !           241: which produces the next line from the input file, but fails when the
        !           242: end of the file is reached. The following expression is typical of
        !           243: programming in Icon and illustrates the integration of conditional
        !           244: expressions and conventional control structures:
        !           245: .Ds
        !           246: while line := read() do
        !           247:    write(line)
        !           248: .De
        !           249: This expression copies the input file to the output file.
        !           250: .PP
        !           251: If an argument of a function fails, the function is not called,
        !           252: and the function call fails as well. This ``inheritance'' of failure allows the
        !           253: concise formulation of many programming tasks. Omitting the optional
        !           254: \f3do\fR clause in \f3while-do\fR, the previous expression can be
        !           255: rewritten as
        !           256: .Ds
        !           257: while write(read())
        !           258: .De
        !           259: .NH 2
        !           260: Generators
        !           261: .PP
        !           262: In some situations, an expression may be capable of producing more than
        !           263: one result. Consider
        !           264: .Ds
        !           265: sentence := "Store it in the neighboring harbor"
        !           266: find("or",\*bsentence)
        !           267: .De
        !           268: Here \*Mor\fR occurs in \*Msentence\fR at positions 3, 23, and 33. Most
        !           269: programming languages treat this situation by selecting one of the
        !           270: positions, such as the first, as the result of the expression. In Icon,
        !           271: such an expression is a \fIgenerator\fR and is capable of producing
        !           272: all three positions.
        !           273: .PP
        !           274: The results that a generator produces depend on context. In a situation
        !           275: where only one result is needed, the first is produced, as in
        !           276: .Ds
        !           277: i := find("or",\*bsentence)
        !           278: .De
        !           279: which assigns the value 3 to \*Mi\fR.
        !           280: .PP
        !           281: If the result produced by a generator does not lead to the success of
        !           282: an enclosing expression, however, the generator is \fIresumed\fR
        !           283: to produce another value. An example is
        !           284: .Ds
        !           285: if (i := find("or",\*bsentence)) > 5 then write(i)
        !           286: .De
        !           287: Here the first result produced by the generator, 3, is assigned to
        !           288: \*Mi\fR, but this value is not greater than 5 and the comparison
        !           289: operation fails. At this point, the generator is resumed and
        !           290: produces the second position, 23, which is greater than 5. The
        !           291: comparison operation then succeeds and the value 23 is written.
        !           292: Because of the inheritance of failure and the fact that comparison
        !           293: operations return the value of their right argument, this expression
        !           294: can be written in the following more compact form:
        !           295: .Ds
        !           296: write(5 < find("or",\*bsentence))
        !           297: .De
        !           298: .PP
        !           299: Goal-directed evaluation is inherent in the expression evaluation
        !           300: mechanism of Icon and can be used in arbitrarily complicated situations.
        !           301: For example,
        !           302: .Ds
        !           303: find("or",\*bsentence1) = find("and",\*bsentence2)
        !           304: .De
        !           305: succeeds if \*Mor\fR occurs in \*Msentence1\fR at the same position
        !           306: as \*Mand\fR occurs in \*Msentence2\fR.
        !           307: .PP
        !           308: A generator can be resumed repeatedly to produce all its results by
        !           309: using the \f3every-do\fR control structure. An example is
        !           310: .Ds
        !           311: every i := find("or",\*bsentence)
        !           312:    do write(i)
        !           313: .De
        !           314: which writes all the positions at which \*Mor\fR occurs in \*Msentence\fR.
        !           315: For the example above, these are 3, 23, and 33.
        !           316: .PP
        !           317: Generation is inherited like failure, and this expression can be written
        !           318: more concisely by omitting the optional \f3do\fR clause:
        !           319: .Ds
        !           320: every write(find("or",\*bsentence))
        !           321: .De
        !           322: .PP
        !           323: There are several built-in generators in Icon. One of the most frequently
        !           324: used of these is
        !           325: .Ds
        !           326: i to j
        !           327: .De
        !           328: which generates the integers from \*Mi\fR to \*Mj\fR. This generator can be
        !           329: combined with \f3every-do\fR to formulate the traditional \f3for\fR-style
        !           330: control structure:
        !           331: .Ds
        !           332: every k := i to j do
        !           333:    f(k)
        !           334: .De
        !           335: Note that this expression can be written more compactly as
        !           336: .Ds
        !           337: every f(i to j)
        !           338: .De
        !           339: .PP
        !           340: There are a number of other control structures related to generation.
        !           341: One is \fIalternation\fR,
        !           342: .Ds
        !           343: \*1 | \*2
        !           344: .De
        !           345: which generates the results of \*1 followed by the results of \*2.
        !           346: Thus
        !           347: .Ds
        !           348: every write(find("or",\*bsentence1) | find("or",\*bsentence2))
        !           349: .De
        !           350: writes the positions of \*Mor\fR in \*Msentence1\fR followed by
        !           351: the positions of \*Mor\fR in \*Msentence2\fR. Again, this sentence can
        !           352: be written more compactly by using alternation in the second
        !           353: argument of \*Mfind\fR:
        !           354: .Ds
        !           355: every write(find("or",\*bsentence1 | sentence2))
        !           356: .De
        !           357: .PP
        !           358: Another use of alternation is illustrated by
        !           359: .Ds
        !           360: (i | j | k) = (0 | 1)
        !           361: .De
        !           362: which succeeds if any of \*Mi\fR, \*Mj\fR, or \*Mk\fR has the value 0 or 1.
        !           363: .NH
        !           364: String Scanning
        !           365: .PP
        !           366: The string analysis and synthesis operations described in
        !           367: Sections 2 and 3 work best for relatively simple operations on strings.
        !           368: For complicated operations, the bookkeeping involved in keeping track of
        !           369: positions in strings becomes burdensome and error prone.
        !           370: In such cases, Icon has a string scanning facility that is
        !           371: analogous in many respects to pattern matching in SNOBOL4. In string
        !           372: scanning, positions are managed automatically and attention is
        !           373: focused on a current position in a string as it is examined by a sequence of
        !           374: operations.
        !           375: .PP
        !           376: The string scanning operation has the form
        !           377: .Ds
        !           378: s ? \*0
        !           379: .De
        !           380: where \*Ms\fR is the \fIsubject\fR string to be examined and \*0 is an expression that
        !           381: performs the examination.
        !           382: A position in the subject, which starts at 1, is the focus of examination.
        !           383: .PP
        !           384: \fIMatching functions\fR change this position.
        !           385: One matching function, \*Mmove(i)\fR, moves the position by \*Mi\fR and
        !           386: produces the substring of the subject between the previous and new
        !           387: positions. If the position cannot be moved by the specified amount
        !           388: (because the subject is not long enough), \*Mmove(i)\fR fails. A
        !           389: simple example is
        !           390: .Ds
        !           391: line ? while write(move(2))
        !           392: .De
        !           393: which writes successive two-character substrings of \*Mline\fR, stopping
        !           394: when there are no more characters.
        !           395: .PP
        !           396: Another matching function is \*Mtab(i)\fR, which sets the position in the
        !           397: subject to \*Mi\fR and also returns the substring of the subject between
        !           398: the previous and new positions.
        !           399: For example,
        !           400: .Ds
        !           401: line ? if tab(10) then write(tab(0))
        !           402: .De
        !           403: first sets the position in the subject to 10 and then to the end of the subject, writing
        !           404: \*Mline\^[10:0]\fR.
        !           405: Note that no value is written if the subject is not long enough.
        !           406: .PP
        !           407: String analysis functions such as \*Mfind\fR
        !           408: can be used in string scanning. In this context, the string that they
        !           409: operate on is not specified and is taken to be the subject. For example,
        !           410: .Ds
        !           411: line ? while write(tab(find("or")))
        !           412:    do move(2)
        !           413: .De
        !           414: writes all the substrings of \*Mline\fR prior to occurrences of \*Mor\fR.
        !           415: Note that \*Mfind\fR produces a position, which is then used by \*Mtab\fR
        !           416: to change the position and produce the desired substring. The \*Mmove(2)\fR
        !           417: skips the \*Mor\fR that is found.
        !           418: .PP
        !           419: Another example of the use of string analysis functions in scanning is
        !           420: .Ds
        !           421: line ? while tab(upto(letters)) do
        !           422:    write(tab(many(letters)))
        !           423: .De
        !           424: which writes all the words in \*Mline\fR.
        !           425: .PP
        !           426: As illustrated in the examples above, any expression may occur in
        !           427: the scanning expression. Unlike SNOBOL4, in which the operations that
        !           428: are allowed in pattern matching are limited and idiosyncratic, string
        !           429: scanning is completely integrated with the rest of the operation
        !           430: repertoire of Icon.
        !           431: .NH
        !           432: Structures
        !           433: .NH 2
        !           434: Lists
        !           435: .PP
        !           436: While strings are sequences of characters, lists in Icon are sequences
        !           437: of values of arbitrary types. Lists are created by enclosing the lists
        !           438: of values in brackets. An example is
        !           439: .Ds
        !           440: car1 := ["buick",\*b"skylark",\*b1978,\*b2450]
        !           441: .De
        !           442: in which the list \*Mcar1\fR has four values, two of which are strings
        !           443: and two of which are integers. Note that the values in a list need not
        !           444: all be of the same type. In fact, any kind of value can occur in a list
        !           445: \(em even another list, as in
        !           446: .Ds
        !           447: inventory := [car1,\*bcar2,\*bcar3,\*bcar4]
        !           448: .De
        !           449: .PP
        !           450: Lists also can be created by
        !           451: .Ds
        !           452: a := list(i,\*bx)
        !           453: .De
        !           454: which creates a list of \*Mi\fR values, each of which has the value
        !           455: \*Mx\fR.
        !           456: .PP
        !           457: The values in a list can be referenced by position much like the
        !           458: characters in a string. Thus
        !           459: .Ds
        !           460: car1\^[4] := 2400
        !           461: .De
        !           462: changes the last value in \*Mcar1\fR to 2400.
        !           463: A reference that is out of the range of the list fails. For example,
        !           464: .Ds
        !           465: write(car1\^[5])
        !           466: .De
        !           467: fails.
        !           468: .PP
        !           469: The values in a list \*Ma\fR are generated by \*M!a\fR. Thus
        !           470: .Ds
        !           471: every write(!a)
        !           472: .De
        !           473: writes all the values in \*Ma\fR.
        !           474: .PP
        !           475: Lists can be manipulated like stacks and queues. The function
        !           476: \*Mpush(a,\*bx)\fR
        !           477: adds the value of \*Mx\fR to the left end of the list \*Ma\fR,
        !           478: automatically increasing the size of \*Ma\fR by one. Similarly,
        !           479: \*Mpop(a)\fR removes the leftmost value from \*Ma\fR, automatically
        !           480: decreasing the size of \*Ma\fR by one, and produces the removed value.
        !           481: .PP
        !           482: A list value in Icon is a pointer (reference) to a structure. Assignment
        !           483: of a structure
        !           484: in Icon does not copy the structure itself but only the pointer to it. Thus the
        !           485: result of
        !           486: .Ds
        !           487: demo := car1
        !           488: .De
        !           489: causes \*Mdemo\fR and \*Mcar1\fR to reference the same list. Graphs with
        !           490: loops can be constructed in this way. For example,
        !           491: .Ds
        !           492: node1 := ["a"]
        !           493: node2 := [node1,\*b"b"]
        !           494: push(node1,\*bnode2)
        !           495: .De
        !           496: constructs a structure that can be pictured as follows:
        !           497: .if \n(Ex .ig
        !           498: .Ds
        !           499: .ta 1.2i
        !           500: .sp 2
        !           501: node1  a
        !           502: .sp 2
        !           503: node2  b
        !           504: .sp 2
        !           505: .De
        !           506: ..
        !           507: .if !\n(Ex .ig
        !           508: .ne 2i
        !           509: .nf
        !           510: .in 1i
        !           511: .ft B
        !           512: .sp 2
        !           513: .cs B 20
        !           514: node1  .->a--.
        !           515:        |     |
        !           516:        |     |
        !           517: node2  '--b<-'
        !           518: .sp 2
        !           519: .cs B
        !           520: .in 0
        !           521: .fi
        !           522: ..
        !           523: .NH 2
        !           524: Tables
        !           525: .PP
        !           526: Icon has a table data type similar to that of SNOBOL4. Tables essentially
        !           527: are sets of pairs of values, an \fIentry value\fR and a corresponding
        !           528: \fIassigned value\fR. The entry and assigned values may be of any type,
        !           529: and the assigned value for any entry value can be looked up automatically.
        !           530: Thus tables provide a form of associative access in contrast with the
        !           531: positional access to values in lists.
        !           532: .PP
        !           533: A table is created by an expression such as
        !           534: .Ds
        !           535: symbols := table(x)
        !           536: .De
        !           537: which assigns to \*Msymbols\fR a table with the default assigned value
        !           538: \*Mx\fR.
        !           539: Subsequently, \*Msymbols\fR can be referenced by any entry value, such as
        !           540: .Ds
        !           541: symbols\^["there"] := 1
        !           542: .De
        !           543: which assigns the value 1 to the \*Mthere\fRth entry in symbols.
        !           544: .PP
        !           545: Tables grow automatically as new entry values are added.
        !           546: For example, the following program segment produces a
        !           547: table containing a
        !           548: count of the
        !           549: words that appear in the input file:
        !           550: .Ds
        !           551: words := table(0)
        !           552: while line := read() do
        !           553:    line ? while tab(upto(letters)) do
        !           554:       words\^[tab(many(letters))] +:= 1
        !           555: .De
        !           556: Here the default assigned value for each word is 0, as given
        !           557: in \*Mtable(0)\fR, and \*M+:=\fR is an augmented assignment operation that
        !           558: increments the assigned values by one.
        !           559: There are augmented assignment operations for all binary operators.
        !           560: .PP
        !           561: Tables can
        !           562: be converted to lists, so that their entry and assigned values can be
        !           563: accessed by position.
        !           564: This is done by \*Msort(t)\fR, which produces a list of two-element
        !           565: lists from \*Mt\fR, where each two-element list consists of an
        !           566: entry value and its corresponding assigned value. For example,
        !           567: .Ds
        !           568: wordlist := sort(words)
        !           569: every pair := !wordlist do
        !           570:    write(pair\^[1],\*b" : ",\*bpair\^[2])
        !           571: .De
        !           572: writes the words and their counts from \*Mwords\fR.
        !           573: .NH
        !           574: Procedures
        !           575: .PP
        !           576: An Icon program consists of a sequence of procedure declarations.
        !           577: An example of a procedure declaration is
        !           578: .Ds
        !           579: procedure max(i,\*bj)
        !           580:    if i > j then return i else return j
        !           581: end
        !           582: .De
        !           583: where the name of the procedure is \*Mmax\fR and its formal parameters
        !           584: are \*Mi\fR and \*Mj\fR. The \f3return\fR expressions return the value of
        !           585: \*Mi\fR or \*Mj\fR, whichever is larger.
        !           586: .PP
        !           587: Procedures are called like built-in functions. Thus
        !           588: .Ds
        !           589: k := max(*s1,\*b*s2)
        !           590: .De
        !           591: assigns to \*Mk\fR the size of the longer of the strings \*Ms1\fR and
        !           592: \*Ms2\fR.
        !           593: .PP
        !           594: A procedure also may suspend instead of returning. In this case, a
        !           595: result is produced as in the case of a return, but the procedure
        !           596: can be resumed to produce other results. An example is
        !           597: the following procedure that generates the words in the input file.
        !           598: .Ds
        !           599: procedure genword()
        !           600:    local line, letters, words
        !           601:    letters := &lcase ++ &ucase
        !           602:    while line := read() do
        !           603:       line ? while tab(upto(letters)) do {
        !           604:          word := tab(many(letters))
        !           605:          suspend word
        !           606:          }
        !           607: end
        !           608: .De
        !           609: The braces enclose a compound expression.
        !           610: .PP
        !           611: Such a generator is used in the same way that a built-in generator is
        !           612: used. For example
        !           613: .Ds
        !           614: every word := genword() do
        !           615:    if find("or",\*bword) then write(word)
        !           616: .De
        !           617: writes only those words that contain the substring \*Mor\fR.
        !           618: .NH
        !           619: An Example
        !           620: .PP
        !           621: The following program sorts graphs topologically.
        !           622: .Ds
        !           623: .ta 3.5i
        !           624: .Px
        !           625: procedure main()
        !           626:    local sorted, nodes, arcs, roots
        !           627:    while nodes := read() do {  # get next node list
        !           628:       arcs := read()   # get arc list
        !           629:       sorted := ""     # sorted nodes
        !           630:        # get nodes without predecessors
        !           631:       while *(roots := nodes -- snodes(arcs)) > 0 do {
        !           632:          sorted ||:= roots     # add to sorted nodes
        !           633:          nodes --:= roots      # delete these nodes
        !           634:          arcs := delarcs(arcs,\*broots)        # delete their arcs
        !           635:          }
        !           636:       if *arcs = 0 then write(sorted)  # successfully sorted
        !           637:       else write("graph has cycle")    # cycle if node remains
        !           638:    }
        !           639: end
        !           640: .De
        !           641: .Ds
        !           642: .Px
        !           643: procedure snodes(arcs)
        !           644:    local nodes
        !           645:    nodes := ""
        !           646:    arcs ? while move(1) do {   # predecessor
        !           647:       move(2)  # skip "->"
        !           648:       nodes ||:= move(1)       # successor
        !           649:       move(1)  # skip ";"
        !           650:       }
        !           651:    return nodes
        !           652: end
        !           653: .De
        !           654: .Ds
        !           655: .Px
        !           656: procedure delarcs(arcs,\*broots)
        !           657:    local newarcs, node
        !           658:    newarcs := ""
        !           659:    arcs ? while node := move(1) do {   # get predecessor node
        !           660:       if many(roots,\*bnode) then move(4)      # delete arc from root node
        !           661:       else newarcs ||:= node || move(4)        # else keep arc
        !           662:       }
        !           663:    return newarcs
        !           664: end
        !           665: .De
        !           666: Graph nodes are represented
        !           667: by single characters with a list of the nodes on one input line followed by
        !           668: a list of arcs. For example, the graph
        !           669: .if \n(Ex .ig
        !           670: .Ds
        !           671: .ta .75i +.75i +.75i
        !           672: \0
        !           673: \0
        !           674: \0
        !           675:        a       b       c
        !           676: .sp 2
        !           677:        d       e
        !           678: .sp 2
        !           679: .De
        !           680: ..
        !           681: .if !\n(Ex .ig
        !           682: .nf
        !           683: .ft B
        !           684: .cs B 20
        !           685: .in 1i
        !           686: .ne 2i
        !           687: .sp 2
        !           688:         .---------------.
        !           689:         |               |
        !           690:         |               \o'v|'
        !           691:         a------>b------>c
        !           692:         \o'^|'       |       \o'^|'
        !           693:         |       |       |
        !           694:         |       \o'|v'       |
        !           695:         d------>e-------'
        !           696: .sp 1
        !           697: .cs B
        !           698: .fi
        !           699: .in 0
        !           700: .sp 1
        !           701: .ft R
        !           702: ..
        !           703: is given as
        !           704: .Ds
        !           705: abcde
        !           706: a\*(->b;a\*(->c;b\*(->c;b\*(->e;d\*(->a;d\*(->e;e\*(->c;
        !           707: .De
        !           708: for which the output is
        !           709: .Ds
        !           710: dabec
        !           711: .De
        !           712: .PP
        !           713: The nodes are represented by csets and automatic type conversion
        !           714: is used to convert strings to csets and vice versa.
        !           715: Note the use of augmented assignment operations for concatenation and in the computation of
        !           716: cset differences.
        !           717: .SH
        !           718: Acknowledgement
        !           719: .PP
        !           720: Icon was designed by the the author in collaboration with Dave Hanson,
        !           721: Tim Korb, Cary Coutant, and Steve Wampler. The current implementation is
        !           722: largely the work of Cary Coutant and Steve Wampler with recent
        !           723: contributions by Bill Mitchell.
        !           724: Dave Hanson and Bill Mitchell also made several helpful suggestions on the presentation
        !           725: of material in this paper.
        !           726: .SH
        !           727: References
        !           728: .LP
        !           729: .IP 1.
        !           730: Griswold, Ralph E., Poage, James F., and Polonsky, Ivan P.
        !           731: \fIThe SNOBOL4 Programming Language\fR, second edition.
        !           732: Prentice-Hall, Inc., Englewood Cliffs, New Jersey. 1971.
        !           733: .IP 2.
        !           734: Kernighan, Brian W. and Ritchie, Dennis M. \fIThe C
        !           735: Programming Language\fR. Prentice-Hall, Inc.,
        !           736: Englewood Cliffs, New Jersey. 1978.
        !           737: .IP 3.
        !           738: Griswold, Ralph E. \fIDifferences Between Versions 2 and 5 of Icon\fR,
        !           739: Technical Report TR 83-5, Department of Computer Science, The University
        !           740: of Arizona. 1983.
        !           741: .IP 4.
        !           742: Griswold, Ralph E. and Griswold, Madge T. \fIThe Icon Programming
        !           743: Language\fR. Prentice-Hall, Inc., Englewood Cliffs, New Jersey.
        !           744: 1983.

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.