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