|
|
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.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.