You are on page 1of 206


Edit ion

Ralph E. Griswold • Madge T. Griswold

The Icon Programming Language
Third Edition

Ralph E. Griswold and Madge T. Griswold

Contents iii

This book originally was published by Peer-to-Peer Communications. It is out
of print and the rights have reverted to the authors, who hereby place it in the public

Library of Congress Cataloging-in-Publication Data
Griswold, Ralph E., 1934-
The Icon programming language / Ralph E. Griswold and Madge T. Contents
Griswold. -- 3rd ed.
p. cm.
Includes bibliographical references (p. ) and index.
ISBN 1-57398-001-3 (pbk.)
1. Icon (computer program language) I. Griswold, Madge T., 1941- .
II. Title.
QA76.73.I19G74 1996
005.13'3--dc20. 96-43514

10 9 8 7 6 5 4 3 2 1
ISBN 1-57398-001-3

This book is provided "as is". Any implied warranties of merchantability and fitness for a particular purpose are
expressly disclaimed. This book contains programs that are furnished as examples. These examples have not been
thoroughly tested under all conditions. Therefore, the reliability, serviceability, or function of any program code Program Structure 1
herein is not guaranteed.
Success and Failure 4
To the best of the authors' and publisher's knowledge, the information presented in this book was correct at the time
it was written and conveyed as accurately as possible. However, some information may be incorrect or may have Control Structures 6
changed prior to publication. The authors and publisher make no claim that the material contained in this book is
entirely correct, and assume no liability for use of the material contained herein. Procedures 7
A number of words that appear in initial capitalization in the text may be trademarks or service marks, or signify Expression Syntax 9
other proprietary rights. No attempt has been made, however, to designate as trademarks or service marks all
personal computer words or terms in which proprietary rights might exist. The inclusion, exclusion, or definition Preprocessing 11
of a word or term is not intended to affect, or to express any judgement on, the validity or legal status of any
proprietary right that may be claimed in that word or term.
Notes 12


Note: This book describes Version 9.3 of the Icon programming language. All known Sequential Evaluation 17
errors in the original printing have been corrected. Marginal revision bars identify Goal-Directed Evaluation 18
substantive corrections.
Iteration 20
Integer Sequences 20
Ralph E. Griswold and Gregg M. Townsend, August 2002 iii
Alternation 21

iv Contents Contents v

Conjunction 22
Loops 23
Selection Expressions 25 Numeric Literals 63
Comparison Operations 28 Arithmetic 64
Assignment 28 Numerical Comparison 65
Values, Variables, and Results 30 Mathematical Computations 65
Argument Evaluation 30 Random Numbers 66
Procedure Returns 31 Bit Operations 66
Notes 32 Notes 67


The Concept of Scanning 37 Records 71
String Positions 38 Lists 72
String Analysis 39 Sets 79
Csets 40 Tables 81
String-Analysis Functions 41 Properties of Structures 83
Scanning Environments 43 Notes 84
Scanning Keywords 44
Augmented String Scanning 44
Notes 45 Backtracking 87
Bounded Expressions 90
Mutual Evaluation 92
Characters 47 Limiting Generation 93
Strings 48 Repeated Alternation 94
Lexical Comparison 50 Notes 95
String Construction 51
String-Valued Functions 52
Substrings 56 Procedure Declarations 97
Csets 60 Scope 99
String Analysis 61 Procedure Invocation 101
Conversion between Csets and Strings 61 Variables and Dereferencing 103
Notes 62 Notes 105

vi Contents Contents vii 9 CO-EXPRESSIONS 109 Events 155 Co-Expression Operations 109 Dialogs 157 Using Co-Expressions 113 Visual Interfaces 158 Programmer-Defined Control Structures 115 Other Features 159 Other Features of Co-Expressions 118 Notes 160 Notes 122 13 OTHER FEATURES 161 10 DATA TYPES 123 Sorting Structures 161 Type Determination 123 String Names 163 Type Conversion 124 String Invocation 164 The Null Value 127 Dynamic Loading 166 Comparing Values 128 Storage Management 166 Copying Values 130 Miscellaneous Facilities 169 Notes 131 Notes 171 11 INPUT AND OUTPUT 133 14 RUNNING AN ICON PROGRAM 173 Files 133 Basics 173 Input 135 Input and Output Redirection 174 Output 136 Command-Line Arguments 175 Text Files and Binary Files 138 Environment Variables 175 Pipes 140 Notes 176 Keyboard Functions 141 15 LIBRARIES 177 Random-Access Input and Output 141 Operations on Files 141 Using Procedure Libraries 177 Notes 142 The Icon Program Library 178 Creating New Library Modules 184 12 AN OVERVIEW OF GRAPHICS 143 Notes 185 Window Operations and Attributes 143 16 ERRORS AND DIAGNOSTIC FACILITIES 187 Drawing 145 Text 149 Errors 187 Color 151 Error Conversion 189 Images 153 String Images 190 .

viii Contents Contents ix Program Information 192 B CHARACTERS 261 Tracing 192 Glyphs 261 The Values of Variables 195 ASCII Control Characters 268 Variables and Names 197 Notes 198 C PREPROCESSING 269 17 PROGRAMMING WITH GENERATORS 201 Include Directives 269 Line Directives 270 Nested Iteration 201 Define Directives 270 Goal-Directed Evaluation and Searching 203 Undefine Directives 271 Recursive Generators 210 Predefined Symbols 271 18 STRING SCANNING AND PATTERN MATCHING 211 Substitution 271 Conditional Compilation 272 Arithmetic Expressions 211 Error Directives 272 Pattern Matching 216 Grammars and Languages 220 D LANGUAGE REFERENCE MANUAL 273 19 USING STRUCTURES 227 Functions 275 Prefix Operations 295 Trees 227 Infix Operations 298 Dags 231 Other Operations 303 Graphs 233 Keywords 306 Two-Way Tables 235 Control Structures 311 20 MAPPINGS AND LABELINGS 237 Generators 314 Mapping Techniques 237 E COMMAND-LINE OPTIONS 315 Labelings 242 F ENVIRONMENT VARIABLES 317 Appendixes G ERROR MESSAGES 319 A SYNTAX 247 Preprocessor Errors 319 Programs 248 Syntax Errors 320 Language Elements 252 Linking Error 321 Program Layout 255 Run-Time Errors 321 Precedence and Associativity 257 .

those programs wouldn’t be written and tasks that could be automated would be done manually instead. I took the liberty of attempting to identify the design philosophy of Icon: • provide a “critical mass” of types and operations • free the programmer from worrying about details • put the burden of efficiency on the language implementation C scores about zero on those points. I think every programmer can benefit by knowing a language like Icon. I think that many programmers don’t have a language like Icon in their toolbox.and space-efficient language well suited for applications that call for neither abstract data types or object-oriented design (to manage complexity). C++. the task is done manually. With Icon. I can write programs I don’t GLOSSARY 357 have the time to write in C or C++. it comes in the box. but that takes effort. and Icon can be viewed as filling three different niches: C A time. REFERENCES 369 When teaching a course in comparative programming languages at The Univer- INDEX 373 sity of Arizona. xi . C++ provides the ability to build or buy a “critical mass” and it also can free the programmer from worrying about details in many cases. The result is that instead of building a personal tool to automate a task. C. Without Icon.x Contents Foreword xi H PLATFORM-SPECIFIC DIFFERENCES 323 Character Sets 324 Language Features 325 Other Issues 326 I SAMPLE PROGRAMS 329 Command-Line Options 329 Structure Images 331 Foreword Concordances 334 Animal Game 337 Randomly Generated Sentences 341 N Queens 348 N Queens Displayed Graphically 350 J ICON RESOURCES 355 A simple fact keeps me coming back to Icon: With Icon.

to be impossible to build a large software system in C without memory management problems. C++ wouldn’t have the capability to fill the niche Icon occupies. toolbox. tors and destructors. One design goal of C++ is that it can be used to build (or buy) whatever higher-level data types one might need. Several years ago. there is still no generally accepted and widely used library of foundation classes such as strings. but I’ve yet to see a string class that approaches the simple elegance and power of Icon’s string type. I’ve seen many C++ string classes. sets. I think C became The Programming Experience very popular because it allowed one to work at a relatively higher level without paying a significant price in terms of either execution time or memory usage. I saw program after program that were thousands of lines in C that I pictured as William H. C++ addresses memory management to a certain extent with construc- Icon A compact but powerful language that’s well suited for building tools. but the fact remains that the C++ programmer must be very cognizant of the lifetime of objects and where responsibility should lie for destroy- Icon Versus C ing a given object. the task is often done manually. for applications where speed and memory utilization are not primary me a compact set of tools whose various usages are easy to remember and that lets concerns. the fine-grained nature of C becomes a liability. and associative arrays.xii Foreword Foreword xiii C++ Everything that C offers plus abstract data types and object orientation On Memory Management to manage complexity in larger applications. Objects that are no cally an order of magnitude) and less memory usage (perhaps half as much). . For most of those programs Icon would have provided The University of Arizona a completely suitable execution profile in terms of both speed and space. I was truly saddened by all the effort that had been needlessly expended to write those programs in C. In Fundamentally. in C. solution is completely correct than would the C programmer. sets. C presents three advantages over Icon: faster execution (typi- contrast. perhaps most. The result is that instead of being able to build a tool to automate a given it’s three of lines of code. it’s maybe a dozen. I think every programmer can benefit by think the Icon programmer would be far more likely to bet a day’s pay that his knowing a language like Icon. Icon gives However. There is a significant segment of the software market that consists of tools to help C and C++ programmers locate memory management bugs. C longer needed are deleted automatically. programmers don’t have a language like Icon in their of strings to produce a single string with the elements separated by commas. associative arrays. Consider a simple example: a function that concatenates each element in a list Many. and so forth. working with Icon is a lot like drawing with pencil and paper. But you can’t have your cake and eat it too — the cost of C++ is language complexity and fairly At the 1988 Usenix C++ technical conference Bill Joy said that he considered it primitive debugging environments. in fact. lists. when reading the net. Today. Icon provides fully automatic storage management. What’s more interesting is that I task. Mitchell maybe a few hundred in Icon. The same is true for lists. me focus on the problem I’m trying to solve. To me. Icon Versus C++ When first learning C++ I wondered if. In contrast.sources newsgroup on a regular basis. but the fact is that it’s a major undertaking to do that. Icon provides a great set of abstract data types right out of the box. In Icon. evolved in an environment where machines were 100 times slower and processes had 100 times less memory available to them than is the case today. almost a decade after C++ came onto the scene.

Strings may be arbitrarily long. the length of a string is limited only by the amount of memory available. a string of characters is a value in its own right rather than being represented as an array of characters. Icon has neither storage declarations nor explicit allocation and deallocation operations. It is a high-level. general-purpose language that contains a wide variety of features for processing and presenting symbolic data — strings of characters and structures — both as text and as graphic images. generating computer programs. rapid prototyping. Management of storage for strings and other values is handled automatically. Icon is well suited to applications where quick solutions are needed — solutions that can be obtained with a minimum amount of time and programming effort. to name just a few. Icon is far more powerful than they are. Although Icon programs superfi- cially resemble programs written in Pascal and C.Introduction xv Introduction Icon is one of the most elegant and powerful programming languages in use today. It is very useful for one-shot programs and for speculative efforts like computer-generated poetry. The syntax of Icon is similar in appearance to Pascal and C. formatting documents. In Icon. reformatting data. in which a proposed solution is more heuristic than algorithmic. It also excels in very complicated applications that involve complex data structures. manipulating formulas. Applications of Icon include analyzing natural languages. Several general characteristics contribute to Icon’s “personality”. xv . artificial intelligence. and graphic display of complex objects.

Consider. while other combinations may not. Scanning operations natural and concise ways. The izes the concept of expression evaluation to allow an expression to produce more function find() is the same as the one given earlier. uses the concept of the success or failure of a computa- tion. For example. This is. which writes the initial substring of text up to the first occurrence of "the". the position in the subject may be changed. to fail. String scanning estab- The concept of failure allows many other computations to be phrased in lishes a subject that is the focus for string-processing operations. s2) = 10 then expr1 else expr2 if find(s1. For example. languages. A simple example find("th". A scanning expression has the form while line := read() do process(line) s ? expr reads lines of input and processes them until the end of the file.s2) succeeds if the string s1 exists in s2 but fails otherwise. every expr1 do expr2 Records allow references to values by field name and provide programmer-defined data types. a large repertoire of functions for operating on strings. Matching functions change the position in the subject and produce the substring Many computations can have more than one result. but many possibilities at the same time to control program flow. As operations on the subject take place. cessful computations. if there is one. Sets are unordered collections of values. Lists consist of ordered sequences of values that can be referenced by which evaluates expr2 for every result produced by expr1. A structure can contain values of different types. which causes read() where s is the subject and expr performs scanning operations on this subject. For example. Icon. for Many of Icon’s control structures resemble those of other programming example. then apply to this subject. s2) then write(i) Since Icon is oriented toward the processing of textual and symbolic data. In most programming text ? write(tab(find("the"))) languages. it has which writes the location of s1 in s2 if there is one. This Neither generators nor goal-directed evaluation depends on any particular mechanism allows an expression to produce a meaningful value. This interpretation discards potentially useful information. For example. One context is iteration: in string scanning. exactly the expression find(s1. alternative values from generators are produced auto- sage.xvi Introduction Introduction xvii Icon has no type declarations. what this expression does in Icon. some combinations of alternatives may lead to suc- a string is converted automatically to a number if it is used in a numerical operation. can appear produced in sequence as determined by context. such a situation is resolved by selecting one position for the value of the function. not Boolean values. a numeric value read into a program as In many computations. Set membership can be tested and values can be inserted into and deleted every i := find(s1. Icon also has a high-level string scanning facility. Type conversion is automatic. if i := find(s1. otherwise evaluate expr2”. Consider of the subject that they “match”. An example is position. Icon also allows programmers to write their own generators. in if find(s1. and there is no limit to the range of their applicability. of which find() is only one example. but in string scanning its second than one result. terminating the while loop. If a computation fails. to drive control structures. "this thesis is the best one") of string scanning is Here "th" occurs at three positions in the second argument. Icon provides several types of structures for organizing data in different ways. The results of a generator are argument need not be specified. matically in an attempt to produce an overall successful result. Such expressions are called generators. then evaluate expr1. s2) do write(i) . and feature for processing strings. Icon general. which writes all the positions at which s1 occurs in s2. Note that any operation. however. find() is useful pedagogically. as in exist in numerical computation and other contexts. such as write(). a value that cannot be converted to a required type in a success and failure in combination with generators to perform goal-directed evalua- meaningful way causes termination of program execution with a diagnostic mes- tion. Icon uses the concepts of Error checking is rigorous. The success or failure of this expression determines which action is taken. tab(i) moves the position to i and produces the substring between the previous and new positions. Lists also can be used as stacks and queues. s2) then write("found") else write("not found") The intuitive meaning of this expression is: “If s1 occurs in s2 at a position that is equal to 10. in fact.

The principal contributors are Bob Alexander. such Cheyenne Wills have made significant contributions to the implementation of Icon. MS-DOS. Chapters 17 through 20 illustrate programming material in Appendix I. Lyle Raines designed the Icon “Rubik’s Cube” on page xiv. the Amiga. and Townsend. and difference are available as well. Frank Lhota. original conception of Icon and was invaluable in its subsequent development. Chapter 14 provides Several of the program examples in this book were derived from programs information about running Icon programs. intersection. The usual set operators of union. like many other programming languages. and platform-specific aspects of Icon are described in Appendix H. and Townsend. Chapter 15 describes libraries of Icon written by students in computer science courses at The University of Arizona. and so on. The Icon logo and other graphics and their glyphs. In addition. Gregg Townsend. Janalee O’Bagy. Mark Emmer. forthcoming). Bill Mitchell. the book is adapted from Graphics Programming in Icon (Griswold. The book concludes with a glossary of Gregg Townsend designed the Icon logo that appears on the title page of this terms related to Icon. but it also is and implementation. Cary Coutant. Ralph Griswold. Dave Hanson. Tim Korb. The first edition of this book described Version 5 of Icon. and environment variables are discussed in Appendix F. This material is used here with the permission of the copyright holders. Command-line options appear in Appendix E. and Windows NT. tion about obtaining material related to Icon. the Atari ST. techniques and provide examples of programming in Icon. Acknowledgments Microsoft Windows. these are just the highlights of the language. for Icon is contained in Appendix D. 1990-). A reference manual originally appeared in The Icon Newsletter (Griswold. writing text in different fonts. 1978-). completely revised. has evolved over a period of time. These implementations are in the public domain and most of them can be downloaded via the World Wide Web.xviii Introduction Acknowledgements xix from sets as needed. The reader of this book should have a general understanding of the concepts of computer programming languages and a familiarity with the current terminol. and Steve Wampler contributed to the program with errors and diagnostic facilities. and so on. the Macintosh. Appendix B lists character codes (Griswold. The support of the National Science Foundation was instrumental in the Appendix I contains complete sample programs and Appendix J provides informa. and Townsend. Appendix C describes preprocessing facilities. book. xix . Tables provide associative lookup in which subscripting with a key produces the corresponding value. The first 11 chapters of this book describe the main features of Icon. references to other material. Ken Walker. and the second edition described Version 8. Icon. Chapter and made suggestions that shaped the final result. MVS. Icon has extensive graphics facilities for creating and manipulating windows. accepting user input from the keyboard and mouse. The third edition describes Version 9. Jeffery. Griswold. 12 contains an overview of Icon’s graphics facilities. including the Acorn Archimedes. is desirable. It not only includes Over the course of Icon’s evolution. These sections provide ming Language for Apple Macintosh Computers (Bright Forest. Icon has been implemented for many computers and operating systems. It contains many improvements based on continuing experi. and Chapter 13 describes features of Icon that do not fit neatly into other categories. The reference material in Appendix D is adapted from The ProIcon Program- Some chapters have a final section entitled Notes. assisted in parts of the implementation. Clint Jeffery. Programming experience with other programming languages. 1989). McConeghy. many different UNIX platforms. drawing. implemented Icon for various platforms. Bob Goldberg. VAX/VMS. Gregg Townsend. Chris Smith. and Steve Wampler. programming tips. CMS. Chapter 16 deals Alexander. persons too numerous to acknowledge individually contributed ideas. Error messages are listed in Appendix G. OS/2. Some material previously appeared in The Icon Analyst Appendix A summarizes the syntax of Icon. Griswold. Icon has much more. and ogy in the field. Other material in additional information. Bob procedures available to extend and enhance Icon’s capabilities.3. Rob ence in teaching and using Icon. many persons have been involved in its design descriptions of features that have been added since Version 8. Dave Gudeman. as Pascal or C. Alan Beale.

In Icon this takes the form: procedure main() write("Hello world") end This program writes Hello world. Procedure declarations contain expressions that are evaluated when the procedure is called. Most programs. Every program must have a procedure with the name main. The procedure name is main. except the simplest ones. Griswold Getting Started This chapter introduces a few basic concepts of Icon — enough to get started. We especially acknowledge his perceptive reading of the draft of this book and his suggestions that were incorporated as a result. The call of the function write simply writes its argument. The reserved words procedure and end bracket a procedure declaration. When execution of a procedure 1 . PROGRAM STRUCTURE A good way to learn a programming language is to write programs. 1 Getting Started 1 Finally. 1 Ralph E. consist of several procedures. There is a fine tradition for beginning to learn a new programming language by writing a program that produces a greeting. Subsequent chapters discuss these concepts in greater detail. our warmest thanks go to Gregg Townsend. Griswold and Madge T. this is where program execution begins. whose contributions to Icon and the Icon Project have been many and varied. a string that is given literally in enclosing quotation marks.xx Acknowledgements Chap.

which are given in a list enclosed in the parenthe- occurs. it returns. For example. contains no characters. the program line is then passed to the function write. The value of appear. an identifier is assumed to be local to the procedure in which it Procedures may have parameters. the preceding program can be divided into two procedures as follows: writes procedure main() Hello world hello() Like most programming languages. its length is 0. Strings may be written literally procedure main() as in the example above. program execution write(who) stops. which is a variable. The procedure hello writes the greeting and returns to main. and underscores. The default to local is an example of a design greet("Hello". while procedures are declared in programs. Therefore. . 1 Chap. as is the case with line. There is no write("Hello world") limit on the length of a string except the amount of memory available. Any variable can have any type of procedure greet(what. terminating program execution. line := "Hello world" The procedure main then returns. The correctness of types is checked when operations are performed. Scope declarations. In the absence of a scope declaration. these are described in later chapters. Icon has both values and variables that end have values. The programmer need not be concerned about it. "world") philosophy of Icon: Common usages usually default automatically without the need end for the programmer to write them out. given literally by "". which may be followed by other letters. Icon has no type or storage declarations.2 Getting Started Chap. this is a new beginning which are described in Chapter 8. Storage write(what) for values is provided automatically. Label. procedure main() Most identifiers are local. and they can be computed in a variety of ways. Upper. There are other kinds of variables besides identifiers. end Identifiers must begin with a letter or underscore. writes two lines: Examples of identifiers are comp. Hello world Note that there is no declaration for the identifier line. Procedures and functions are used in the same way. the program called and are destroyed when the procedure returns. All 256 ASCII characters may occur in strings. Local identifiers are created when a procedure is ses that follow the procedure name in the declaration. The empty write(" this is a new beginning") string. When the main procedure returns. while write is a function that is built into the Icon language. Expressions in the body of a procedure are evaluated in the order in which they assigns the value "Hello world" to the identifier line. who) value. and entry_value. The only The operation distinction between the two is that functions are built into Icon. A local identifier can only be accessed in the procedure call in which it is created. digits. test10. This is illustrated by procedure hello() procedure main() write("Hello world") line := "Hello world" end write(line) end Note that main and hello are procedures. are optional for local identifiers. 1 Getting Started 3 reaches its end. end To illustrate the use of procedures.and lowercase letters are distinct.

the recognition of failure. since "on" is not a substring of "radio noise" because of the intervening blank between the "o" and the "n". it stands for itself and does not signal the beginning of a comment. "slow motion") SUCCESS AND FAILURE fails. s2) succeeds only if s1 is an initial substring that Note that the end of a line terminates a comment. The expression line := read() count > 0 write(line) . For example. match("slo". #======# match("on". Com. in The function read() is one of a number of expressions in Icon that may either succeed or fail. The context in which failure occurs is important. must have a #. "slow motion") If a # occurs in a quoted literal. "slow motion") write(read()) succeeds. succeeds. It accounts for the fact that there are situations # parameter specifies the recipient. s2) and match(s1. since there is no value for its argument. and the possibility of alternatives. For example. while the second part of the design philosophy of Icon. Consider parison operations. such as a line of input. there is nothing to write. Expressions that may succeed or fail are called conditional expressions. An greater than 0. A substring is a string end that occurs in another string. whether it is success or failure. example of the use of comments is As a general rule. but write("#======#") find("on". whole expression fails. These write(who) # recipient functions succeed if s1 is a substring of s2 but fail otherwise. expression fails also. find("on". since "on" is contained in "slow motion". while match(s1. s2) succeeds if s1 occurs anywhere in s2. The function read() reads a line. Note that the value produced by read() is the argument If an expression that fails is an argument in another expression. For example. "radio noise") writes fails. The function find(s1. in which operations cannot be performed. are conditional expressions. It corresponds to many real-world # situations and allows programs to be formulated in terms of attempts to perform procedure greet(what. failure occurs if a relation does not hold or if an operation cannot be performed but is not actually erroneous. write(what) # message Two other conditional expressions are find(s1. who) computations. it produces a value. If an expression succeeds. Each line of a multi-line comment occurs at the beginning of s2. The term outcome is used to describe the result of if read() fails. 1 Getting Started 5 The character # in a program signals the beginning of a comment. For example. 1 Chap. write(read()) If an expression fails. failure occurs when # This procedure illustrates the use of parameters. Failure is an important # first parameter provides the message. Therefore. In the case of read(). for example. since "on" does not occur at the beginning of "slow motion". The # and succeeds if the value of count is greater than 0 but fails if the value of count is not the remaining characters on the line are ignored when the program is compiled. failure occurs when the end of the input file is reached. the other of write(). The an attempt is made to read but when there are no more lines. s2). 4 Getting Started Chap. Similarly. reads a line and writes it out. The function write() is not called and the evaluating an expression. On the other hand. it produces no value.

which distinguish control structures. while line := read() do if find(s. the value it writes all the lines of the input file that contain an occurrence of the string "fancy". It can be used anywhere that any expression is allowed. the failure of read() does not affect write(line). write(line) The following procedure prints only the lines that contain the string s: are separate expressions. For example. if find(s. the values of the arguments are written one after . because read() is an argument of the assignment operation. however. tion of other expressions. 1 Chap. the success or failure of the expression that follows while controls contain s. A complete list of reserved words is given in lineno := lineno + 1 Appendix A. as in needed. the assignment operation fails and the loop terminates. 1 Getting Started 7 If read() succeeds. and the value of line is not changed. Compound expressions assigns 1 to sign if the value of count is greater than 0. line) then write(line) CONTROL STRUCTURES end Control structures use the success or failure of an expression to govern the evalua. performed. procedure main() while line := read() do locate("fancy") write(line) end repeatedly evaluates read() in a loop. One expression increments the line number and the other writes the line if it contains the desired substring. ": ". which in this case if count > 0 then sign := 1 else sign := –1 consists of two expressions. There is no value to assign to line if read() fails. For example. The assignment is conditional on the success of read(). produces is assigned to line and write(line) is evaluated to write that value. it just writes procedure locate(s) whatever value line had previously. To do this. which selects one of two expressions to evaluate. however. if count > 0 then sign := 1 no new value is assigned to line. If read() fails. The else clause is optional. line) then write(lineno. but assigns –1 to sign must be used wherever one expression is expected by Icon’s syntax but several are otherwise. Each time read() succeeds. are reserved while line := read() do { and cannot be used as identifiers. it is necessary to count each line as it is read: evaluation of the expression that follows do. When read() fails. In This procedure is more useful if it also writes the numbers of the lines that other words. For example. Note that write() has three arguments in this procedure. no assignment is which assigns a value to sign only if count is greater than 0. The braces in this procedure enclose a compound expression. Each procedure in a program typically performs a separate logical task. procedure locate(s) Note that assignment is an expression. 6 Getting Started Chap. The function write() can be called with many arguments. Some examples follow. lineno := 0 Words like while and do. depending on the success or failure of a conditional end expression. Since line := read() PROCEDURES and Procedures are the major units of a program. line) } Another frequently used control structure is if-then-else. the value it produces is assigned to line.

"world") example of a default. while line := read() do if match(s. easily recognizable syntax for word return is used to indicate a value to be returned from a procedure call. how nourished? Reply. which makes programs shorter and saves the need to explicitly specify routine actions where they clearly are the natural thing to do. consider an input file that consists of the while line := read() do following song from Shakespeare’s play The Merchant of Venice: if match(s. count := 0 To illustrate the use of this procedure. as illustrated in the preceding sections. and fancy dies Function and procedure calls. bell. Like other expressions. In this case there is a line number. are expressions in which parentheses enclose arguments. the sum of i and j. 6: With gazing fed. write(line) This example illustrates one of the more important features of Icon: the automatic conversion of values from one type to another. This is indicated by the reserved word fail. have precedences that determine which count := 0 operations apply to which arguments when they are used in combination. line) then count := count + 1 Tell me. The procedure fails. For common operations. Identifiers. The term argument is used for both operators and functions to describe the expressions on which they operate. example. – Ding. which since multiplication has higher precedence than addition. Icon has several types of expressions. is greater than 0. 1 Chap. A procedure call also can fail. Literals The lines written by locate("fancy") are: such as "Hello world" and 0 are expressions that designate values literally. line) then count := count + 1 i+j∗k return count groups as end i + (j ∗ k) produces a count of the number of input lines that begin with s. 1: Tell me. where is fancy bred. the procedure . With gazing fed. while i + j produces example. This is another greet("Hello". −i produces the negative of i. procedure calls may produce values. dong. reply. such as line. where is fancy bred. 1 Getting Started 9 another. if no line begins with the string s. such as 8: Let us all ring fancy's knell. are also expressions. The first argument of and write() in this example is an integer. as is conventional in causes the procedure call to terminate but fail instead of producing a value. followed by a colon procedure countm(s) and a blank. Since write() expects to write strings. provided that the count It is engender'd in the eyes. and fancy dies In the cradle where it lies: Let us all ring fancy's knell. EXPRESSION SYNTAX I'll begin it. For example. procedure countm(s) Infix operations. all on the same line. followed by the line itself. if count > 0 then return count else fail Or in the heart or in the head? end How begot. it is not necessary to specify conversion. For example. such as i + j and i ∗ j. For numerical computation.8 Getting Started Chap. however. this integer is converted to a string. produces a count of the number of lines that begin with s. The reserved Operators are used to provide a concise.

Preprocessor directives are indicated by a $ at the beginning of a line. The outcome of such a control structure is the outcome of expr2 or groups as expr3. . Thus. whichever is selected. Programs usually are easier to read if the expressions in a compound expression are written on separate lines. consisting of the character & followed by one of a number of specific words.10 Getting Started Chap. it is safest to use parentheses to assure that operations group in the desired way. any kind of expression can be used in any context Assignment also associates from right to left. line) then write(line)} defines suits to be a four-character string. There are no distinctions among the kinds of expressions. Where the expressions in a compound expression appear on the same line. if find(s. code can be included or excluded. which defines the symbol Limit and gives it the value 100. Even control structures. are used to designate special operations that require no arguments. expressions. other files inserted. (i + j) ∗ k depending on the definition of constants. The precedences and associativities of various operations are mentioned as the operations are introduced in subsequent chapters. as illustrated by the examples in this chapter. exponentiation associates from right to left so that Keywords. while line := read() do { if count > Limit then write("limit reached") count := count + 1 if find(s. For example. Icon has no statements. as in Icon programs are preprocessed before they are compiled. i^j^k For example. For example. procedure. 1 Chap. On the other hand. 1 Getting Started 11 Associativity determines how expressions group when there are several Unlike many programming languages. it is replaced by 100 prior to compilation. Appendix A summarizes the PREPROCESSING precedences and associativities of all operations. line) then write(line) becomes } if count > 100 then write("limit reached") also can be written as The text of a definition need not be a number. They (i – j) – k usually stand alone as if they were statements. and so on. whenever they must be separated by semicolons. the value of &time is the number of milliseconds of processing time since the beginning of program execution. it just has occurrences of the same operation in combination. such as ates from left to right so that if expr1 then expr2 else expr3 i–j–k are expressions. constants can be defined. in which case semicolons are not needed. Limit appears. where an expression is legal. as in Since there are many operations in Icon with various precedences and associativi- ties. while line := read() do $define suits "SHDC" {count := count + 1. however complicated that expression is. Even though control structures are expressions. $define Limit 100 especially for operations that are not used frequently. or control structure may be i ^ (j ^ k) any expression. During preprocessing. Subsequently. operator. Parentheses can be used to group expressions in desired ways. subtraction associ. For example. they usually are not used in ways that the values they produce are important. groups as Any argument of a function.

Consult the Icon user manual for your platform. . to know how to name Icon files and how to compile and execute them. Italics are used for expressions such as expr. an argument that is expected to be an integer. x and y are used for arguments that are of unknown type or that may have one of several types. mentioned previously. Chapter 10 discusses types in more detail. the notation expr. match. The shorter phraseology is used when there can be no confusion about its meaning. and so forth. If you are using a visual environment rather than a command-line one. integers.icn. expressions that are important. enter fashion. emphasizes that the control structure is concerned with the evaluation of its Library procedures are organized into modules. NOTES Running an Icon Program Notation and Terminology The best way to learn a new programming language is to write programs in it. Finally. the value of s in a program could be an integer. Therefore. This notation is extended following usual mathematical conventions.icn i1 and i2. real numbers. In describing functions. The letters are MS-DOS and UNIX. 1996). no matter how compli. These are only conventions. as in write(). Other types are indicated in a similar or have no suffix at all. As to run the program. the steps will cated that expression is. −i indicates the operation of computing the negative of the integer i. from the command-line prompt. For example. Other preprocessor directives and matters related to preprocessing are de. expr1. “an integer between 1 and i” sometimes inserts the contents of the file "disclaim. A module can be added to a program using the link declaration. while i1 + i2 indicates the operation of adding the integers icont hello.icn. in command-line environments like Single letters are used in this book to indicate the types of arguments. s2) is not a function but rather a call of the function gram. In describing what operators and functions do. 1 Getting Started 13 Another useful preprocessor directive allows a file to be included in a pro. such as procedure and read(). enter expected to be a string.exe that j and k also are used to indicate integers. For example. many procedures. An example is hello. while expr1 do expr2 The procedures contain reusable code that extends Icon’s built-in repertoire. For example. 12 Getting Started Chap. while s indicates an argument that is • At the command-line prompt. In any event. not with their values or their types. Chapter 14 describes how to run Icon programs. The letters in identifiers have no meaning to Icon. other readily under- stood abbreviations are used. Similarly. The sans serif typeface denotes literal program text. match(s1.icn" in place of the $include directive.icn" relevant. The programs range from games to utilities. These letters usually are taken from the first character of the type name. any argument can be an expression. i indicates • Enter an Icon program in a file with the suffix . varies somewhat from platform to platform. the fact that their arguments Just entering the simple examples in this chapter and then extending them will teach may be syntactically complicated is not significant. In situations The Icon Program Library where the type produced by an expression is not important. and so on is used. distinguish program material and terminology. s2) … ” are used to indicate the name of a function and the number and types of its arguments. so • The result is an executable file that starts with hello and may end with . For example. is used in place of “an integer between 1 and the value of i”. Although this Many functions and operations require specific types of data for their arguments. phrases such as “the function match(s1. A module may contain one or arguments. 1 Chap. arguments. It is the values produced by these you a lot. different typefaces are used to scribed in Appendix C. See is used in this book for conciseness and to emphasize the expected data types of Appendix J for sources of Icon and documentation about it. expr2. it’s this simple: chosen to indicate the types that operations and functions expect. the arguments are omitted. The use of letters to stand for expressions is just a device that be somewhat different. In describing function calls in places where the specific arguments are not $include "disclaim. hello This notation does not mean that arguments must be written as identifiers. The Icon program library contains a large collection of programs and proce- dures (Griswold and Townsend. Strictly speaking. As illustrated by examples in this chapter. For example. All you need to get started is Icon has several types of data: strings.

) The computation is then performed and the result is shown as an produces the expected result: assignment to a variable. enter :help followed by a return. (k ∗ i) + j Testing Icon Expressions Interactively which presumably is not what is wanted and certainly does not produce the result suggested by Although Icon itself does not provide a way to enter and evaluate individual expressions interactively. allows a user to type an expression and see the result of its evaluation. At the > prompt. r3_. Successive expressions accumulate and results are assigned to On the other hand variables so that previous results can be used in subsequent computations. there is a program in the Icon program library that does. Useful material in the program library is mentioned at appropriate places in k ∗i + j this book. Here is an example of a simple interaction. The use of library procedures and ways of creating new library proce- dures are described in Chapter 15. For example. named qei. as in > 1 < 0. qei responds with Failure. starting with r1_ and continuing with r2_. followed by a semicolon and $define Sum (i + j) a return. an expression can be entered. Syntactic Considerations The value of a constant defined by preprocessing can be any string. expressions should be parenthesized to assure proper grouping. k ∗ (i + j) > 1 + 3.14 Getting Started Chap. 1 Getting Started 15 as in defines Sum to be i + j and i + j is substituted wherever sum appears subsequently. To get a brief summary of qei’s features and how to use them. r1_ := 4 > r1_ ∗ 10. 1 Chap. r2_ := 40 If an expression fails. Failure The program qei has several other useful features. subsequent lines are included until there is a semicolon. k ∗ Sum This program. (If a semicolon is not provided. For link strings example. $define Sum i + j . The string simply is substituted for subsequent uses of the defined symbol. and so on. which groups as See Appendix J for information on how to get the Icon program library. such as optionally showing the types of results. In such uses. in procedure main() k ∗ Sum … the result of substitution is which adds the module strings to a program.

2 Expressions 17 2 Expressions The evaluation of expressions causes the computations that are performed during program execution. Chapter 7 contains additional information about expression evaluation. inner expressions are evaluated first to provide values for outer ones. For example. Where expressions are nested. this is called sequential evaluation. This chapter introduces the basic concepts of expression evaluation in Icon. Chap. or a sequence of results (generation). These possibilities also make expression evaluation a more important topic than it is in most other programming languages. expressions in an Icon procedure are evaluated in the order in which they appear. Icon has a large repertoire of functions and operations. Several control structures in Icon are specifically concerned with failure and generation. each of which performs a different kind of computation. SEQUENTIAL EVALUATION In the absence of control structures. in i := k + j write(i) 17 . no result at all (failure). The most important aspect of expression evaluation in Icon is that the outcome of evaluating an expression may be a single result. The possibilities of failure and generation distin- guish Icon from most other programming languages and give it its unusual expressive capability.

assignment needs only one result. s2) may produce a single result or it may fail. i is not changed. s2) fails. in the preceding example. It is a large part of what makes Icon programs short and easy to write. 8. 8. s2) fails. This method of expression evalu- its arguments failed. its resumption fails. s2) > 10 in which addition always produces a single result. It embodies in a concise way a conceptually simple computation. The results are generated. The two lines also could be combined into one. 2 Expressions 19 the values of k and j are added to provide the value assigned to i. writes the value i had prior to the evaluation of these two lines. which tion caused evaluation to return to a function that had already produced a value. result is assigned to i and sequential execution continues (writing the newly While the term failure is used to describe an expression that produces no value at all. find(s1. s2) > 10 then write("good location") The sequential nature of expression evaluation is familiar and natural. for Suppose s1 occurs in s2 at positions 2. assigned value of i). as instead other possibilities are tried in an attempt to find a combination of values that makes the entire expression succeed. and 30. since failure . Instead of just producing a value and “going away”. There is no value to assign to i and the is. GOAL-DIRECTED EVALUATION Failure during the evaluation of an expression causes previously evaluated genera- tors to produce additional values. It is mentioned here because of the possibilities of failure and generation. They are discarded when there is no longer any need for them. as needed. The effect is as if the assignment failed because one of this computation in Pascal or C for comparison. s2) does not produce the values 20 The single-result case is easy — it is just like or 30. write(i) Failure may cause expression evaluation to go back to a previously evaluated expression. An expression that produces a value and may be capable of producing discussed in more detail later. Try formulating assignment is not performed. and execution continues with write(i). 20. 2 Chap. Observe how natural the formulation i := k + j find(s1. write(i := k + j) Goal-directed evaluation is illustrated by the following expression although the former version is more readable and generally better style. s2) are not produced. if find(s1. in ation is used very frequently in Icon programs. 12. Suppose that find(s1. and the comparison is: i := find(s1. The next section illustrates situations in which a generator may produce more than one result. 18 Expressions Chap. find(s1. As in assignment. in order again. If a generator is resumed but has no more values. Note that when an outer computation succeeds there may be suspended generators. no more values are needed. i is written. s2) is 2. it keeps Since a substring can occur in a string at more than one place. a resumed generator that does not produce a value (failed resumption) has the same effect on expression evaluation — there is no value to use in an outer expression. s2) to produce its next value. s2) 2 > 10 write(i) This comparison fails. comparison again fails. so the first another value. Failure causes a suspended generator to be resumed so that it may produce from left to right. and find(s1. The As shown in Chapter 1. In the example above. It generally is not This is called control backtracking. For example. which causes find(s1. This subject is of generators. once the comparison succeeds. failure of a comparison opera- if find(s1. It is not necessary to think about all the details of i := find(s1. Control backtracking only happens in the presence good programming practice to let possible failure go undetected. The other possible results of find(s1. s2) produces 12. the value of of a part of an expression does not necessarily cause the entire expression to fail. and good location is written. Note that find(s1. Next. another one suspends. The first value produced by example find(s1. The comparison now succeeds It may also generate a sequence of results. s2) what is going on. Consider. s2) can track of what it was doing and remains “in the background” in case it is needed have more than one possible result. Consequently. This is called goal-directed evaluation.

36. and 100. 2 Chap. it reads more naturally as “i is assigned 0 then 1”. For example. Note that iteration in combination with integer generation corresponds to the The or/then distinction reflects the usual purpose of alternation in the two for control structure found in many programming languages. expr2 is evaluated for every value structure. s2). 3. expr1 is first evaluated and sequence of values to apply to more than one expression. in The do clause is optional. 2. 2 Expressions 21 ITERATION every write((1 to Limit) ^ 2) The function seq(i. expr1 | expr2 every i := find(s1. This expression can be written more compactly as if i = (0 | 1) then write("okay") every write(find(s1. 64. There are. Thus. it reads naturally as “if i is equal to 0 or 1. On the other hand. s2) provides a sequence of values for assignment. 81. One of the most generates 1. Note that the repeated resumption of 0|1 find(s1. For example. the increment is 1. 16. generates 0 and 1. 3. but with no upper bound. there are many situations in which all (or most) of the values of a generator are needed. In fact. then …”. if it is omitted. 1. 25. as many assign- ments are performed as there are values for find(s1. For write(i) example. but without any concept of failure. In this control structure. 9. Thus. s2) do does this by first producing the values for expr1 and then the values for expr2. The alternation control then repeatedly resumed to produce all its values. many other ways iteration and integer generation can be used in combination. s2). INTEGER SEQUENCES (1 to 3) | (3 to 1 by –1) Icon has several expressions that generate sequences of values. 49. however. that is produced by expr1. useful is When alternation is used in goal-directed evaluation. The arguments in an alternation expression may themselves be generators. For example. For example. if alternation is used in iteration. 2. writes all the values produced by find(s1. 20 Expressions Chap. The iteration control structure ALTERNATION every expr1 do expr2 Since a generator may produce a sequence of values and those values may be used in goal-directed evaluation and iteration. such as i to j by k if i = (0 | 1) then write(i) which generates the integers from i to j in increments of k. different contexts and suggests how to use alternation to formulate computations. j) generates a sequence of integers starting at i with It is not necessary to rely on failure and goal-directed evaluation to produce several increments of j. s2)) okay is written if the value of i is either 0 or 1. 4. the expression above can be written more compactly as . as in $define Limit 10 every i := 1 to Limit do every i := (0 | 1) do write(i ^ 2) write(i) writes the squares 1. values from a generator. it is natural to extend the concept of a is provided for these situations. The by clause is optional.

22 Expressions Chap. 2 Chap. 2 Expressions 23


There are two control structures that evaluate an expression repeatedly, depending
As explained earlier, an expression succeeds only if all of its component
on the success or failure of a control expression:
subexpressions succeed. For example, in
while expr1 do expr2
find(s1, s2) = find(s1, s3)
described earlier, and
the comparison expression fails if either of its argument expressions fails. The same
is true of
until expr1 do expr2
find(s1, s2) + find(s1, s3)
which repeatedly evaluates expr2 until expr1 succeeds. In both cases expr1 is
evaluated before expr2. The do clauses are optional. For example,
and, in fact, of all operations and functions. It often is useful to know if two or more
expressions succeed, although their values may be irrelevant. This operation is
while write(read())
provided by conjunction,
copies the input file to the output file.
expr1 & expr2
A related control structure is
which succeeds (and produces the value of expr2) only if both expr1 and expr2
succeed. For example, not (expr)

if find(s1, s2) & find(s1, s3) then write ("okay") which fails if expr succeeds, but succeeds if expr fails. Therefore,

writes okay only if s1 is a substring of both s2 and s3. until expr1 do expr2
Note that conjunction is just an operation that performs no computation (other
than returning the value of its second argument). It simply binds two expressions
while not (expr1) do expr2
together into a single expression in which the components are mutually involved in
goal-directed evaluation. Conjunction normally is read as “and ”. For example,
are equivalent. The form that is used should be the one that is most natural to the
situation in which it occurs.
if (i > 100) & (i = j) then write(i)
The while and until control structures are loops. Loops normally are terminated
might be read as “if i is greater than 100 and i equals j …” only by the failure or success of their control expressions. Sometimes it is necessary
to terminate a loop, independent of the evaluation of its control expression.
Note also that in goal-directed contexts,
The break expression causes termination of the loop in which it occurs. The
expr1 | expr2 | ... | exprn following program illustrates the use of the break expression:

and procedure main()
count := 0
expr1 & expr2 & … & exprn
while line := read() do
correspond closely to logical disjunction and conjunction, respectively. Thus, and/ if match("stop", line) then break
or conditions can be easily composed using conjunction and alternation. else count := count + 1

24 Expressions Chap. 2 Chap. 2 Expressions 25

This program counts the number of lines in the input file up to a line beginning with procedure main()
the substring "stop".
setcount := 0
Sometimes it is useful to skip to the beginning of the control expression of a
repeat {
loop. This can be accomplished by the next expression. Although the next expression
setcount := setcount + 1
is rarely needed in simple cases, the following example illustrates its use:
linecount := 0
while line := read() do {
procedure main()
linecount := linecount + 1
while line := read() do if match("end", line) then {
if match("comment", line) then next write(linecount)
else write(line) break
if linecount = 0 then break # end of file
This program copies the input file to the output file, omitting lines that begin with
the substring "comment".
write(setcount, " sections")
The break and next expressions may appear anywhere in a loop, but they apply
only to the innermost loop in which they occur. For example, if loops are nested, a end
break expression only terminates the loop in which it appears, not any outer loops.
The use of a break expression to terminate an inner loop is illustrated by the The outcome of a loop, once it is complete, is failure. That is, a loop itself
following program, which copies the input file to the output file, omitting lines produces no value. In most cases, this failure is not important, since loops usually
between those that begin with "skip" and "end", inclusive. are not used in ways in which their outcome is important.

procedure main()
while line := read() do
if match("skip", line) then { # check for lines to skip The most common form of selection occurs when one or another expression is
while line := read() do # skip loop evaluated, depending on the success or failure of a control expression. As described
if match("end", line) then break in Chapter 1, this is performed by
else write(line) # write line in main loop if expr1 then expr2 else expr3
which evaluates expr2 if expr1 succeeds but evaluates expr3 if expr1 fails.

There is one other looping control structure: If there are several possibilities, if-then-else expressions can be chained to-
gether, as in
repeat expr
if match("begin", line) then depth := depth + 1
This control structure evaluates expr repeatedly, regardless of whether it succeeds else if match("end", line) then depth := depth – 1
or fails. It is useful when the controlling expression cannot be placed conveniently else other := other + 1
at the beginning of a loop. A repeat loop can be terminated by a break expression.
The else portion of this control structure is optional:
Consider an input file that is organized into several sections, each of which is
terminated by a line beginning with "end". The following program writes the if expr1 then expr2
number of lines in each section and then the number of sections.

26 Expressions Chap. 2 Chap. 2 Expressions 27

evaluates expr2 only if expr1 succeeds. The not expression is useful in this abbrevi- Any kind of value can be used in the control expression. For example,
ated if-then form:
case s of {
if not (expr1) then expr2 "begin" : depth := depth + 1
"end" : depth := depth – 1
which evaluates expr2 only if expr1 fails. In this situation, parentheses are often }
needed around expr1 because not has high precedence.
increments depth if the value of s is the string "begin" but decrements depth if the
While if-then-else selects an expression to evaluate, depending on the success
value of s is the string "end". Since there is no default clause, this case expression fails
or failure of the control expression, it is often useful to select an expression to
if the value of s is neither "begin" nor "end". In this case, the value of depth is not
evaluate, depending on the value of a control expression. The case control structure
provides selection based on value and has the form
The expression in a case clause does not have to be a constant. For example,
case expr of {
case-clause case i of {
case-clause j+1 : write("high")
. j–1 : write("low")
. j : write("equal")
default : write("out of range")
The expression expr after case is a control expression whose value controls the
selection. There may be several case clauses. Each case clause has the form
writes one of four strings, depending on the relative values of i and j.
expr1 : expr2 The expression in a case clause can be a generator. If the first value it produces
is not the same as the value of the control expression, it is resumed for other possible
The value of the control expression expr is compared with the value of expr1 in each values. Consequently, alternation provides a useful way of combining case clauses.
case clause in the order in which the case clauses appear. If the values are the same, An example is:
the corresponding expr2 is evaluated, and its outcome becomes the outcome of the
entire case expression. If the values of expr and expr1 are different, or if expr1 fails, case i of {
the next case clause is tried. 0 : write("at origin")
1 | –1 : write("near origin")
There is also an optional default clause that has the form
default : write("not near origin")
default : expr2
Since the outcome of a case expression is the outcome of the selected expres-
If no comparison of the value of the control expression with expr1 is successful, expr2
sion, it sometimes is possible to “factor out” common components in case clauses.
in the default clause is evaluated, and its outcome becomes the outcome of the case
For example, the case expression above can be written as
expression. The default clause may appear anywhere in the list of case clauses, but
it is evaluated last. It is good programming style to place it last in the list of case
case i of {
Once an expression is selected, its outcome becomes the value of the case 0 : "at origin"
expression. Subsequent case clauses are not processed, even if the selected expres- 1 | –1 : "near origin"
sion fails. A case expression itself fails if (1) its control expression fails, (2) if the default : "not near origin"
selected expression fails, or (3) if no expression is selected. }

Such constructions can be difficult to read and should be used with restraint.

28 Expressions Chap. 2 Chap. 2 Expressions 29

Note that each case clause allows just a single expression to be executed. If Augmented Assignment
multiple expressions are needed, they must be grouped using braces.
One of the most common operations in programming is incrementing the
numerical value of a variable, as in
i := i + 1
A comparison operation such as
In order to make such operations more concise and to avoid two references to
i=j the same variable, Icon provides augmented assignment operations that combine
assignment with the computation to be performed. For example,
produces the value of its right operand if it succeeds. For example
i +:= 1
write(find(s1, s2) = find(s3, s4))
adds one to the value of i.
writes the first common position if there is one.
There are augmented assignment operations corresponding to all infix opera-
Comparison operations are left associative, so an expression such as tions (except assignment operations themselves); the := is simply appended to the
operator symbol. For example,
i ∗:= 10
groups as
is equivalent to
(i < j) < k
i := i ∗10
Since a comparison operation produces the value of its right operand if it succeeds,
the expression above succeeds if and only if the value j is between the values of i and Similarly,
i >:= j
ASSIGNMENT assigns the value of j to i if the value of i is greater than the value of j. This may seem
a bit strange at first sight, since most programming languages do not treat compari-
One of the most commonly used operations is assignment, which has the form son operations as numerical computations, but this feature of Icon sometimes can be
used to advantage.
x := y
Exchanging Values
and assigns the value of y to the variable x.
Assignment associates to the right, so that The operation

x := y := z x :=: y

groups as exchanges the values of x and y. For example, after evaluating

x := (y := z) s1 := "begin"
s2 := "end"
Consequently, the value of z is assigned to both y and x. s1 :=: s2

30 Expressions Chap. 2 Chap. 2 Expressions 31

the value of s1 is "end" and the value of s2 is "begin". If an argument is omitted, as in write(), the value of that argument is null. Many
functions have defaults that are used if an argument is null. For example, in write(),
The exchange operation associates from right to left and returns its left
the null value defaults to an empty string and an empty (blank) line is written.
argument as a variable. Consequently,
Another example is the function seq(i, j), which was described earlier. If its
arguments are omitted, and hence null, they default to 1. Consequently, seq()
x :=: y :=: z
generates 1, 2, 3, … and seq(7) generates 7, 8, 9 … .
groups as The keyword &null produces the null value. Consequently, write() and
write(&null) are equivalent. The null value is described in more detail in Chapter 10.
x :=: (y :=: z)

As shown in Chapter 1, a procedure call may return a value, as in
Some expressions produce values, while others (such as assignment) produce
variables, which in turn have values. For example, the string literal "hello" is a value, return count
while the identifier line is a variable. It is always possible to get the value of a
variable. This is done automatically by operations such as i + j, in which the values or it may fail and not return a value by using fail. A procedure call also may fail by
of i and j are used in the computation. flowing off the end of the procedure body without an explicit return.
On the other hand, values are not obtained from variables unless they are A procedure also may generate a sequence of values by using suspend, as in
needed. For example, the expression x | y generates the variables x and y, so that the following example:

every (x | y) := 0 procedure To(i, j)
while i <= j do {
assigns 0 to both x and y. The if-then-else and case control expressions also produce
suspend i
variables if the selected expression does.
i +:= 1
The term result is used collectively to include both values and variables. }
Consequently, it is best to describe
expr1 | expr2 end

as generating the results of expr1 followed by the results of expr2. The suspend expression produces a value from the procedure call in the same
manner as return, but the call is suspended and can be resumed. If it is resumed,
Note that the term outcome includes results (values and variables) as well as
evaluation continues following the point of suspension. In the example above, the
first result produced is the value of i, provided it is less than or equal to j. If the call
The keyword &fail does not produce a result. It can be used to indicate failure is resumed, i is incremented. If i is still less than or equal to j, the call suspends again
explicitly. with the new value of i. If i is greater than j, the loop terminates and fail is evaluated,
which causes the resumption of the call to fail. The fail expression is not necessary,
since flowing off the end of the procedure body has the same effect. Consequently,
every write(To(1, 10))
The arguments of function and procedure calls are evaluated from left to right. If the
evaluation of an argument fails, the function or procedure is not called. If more is equivalent to
arguments are given in a call than are expected, the extra arguments are evaluated,
but their values are not used. If the evaluation of an extra argument fails, the function every write(1 to 10)
or procedure is not called, just as in the case of the evaluation of any other argument.

32 Expressions Chap. 2 Chap. 2 Expressions 33

The suspend expression is like the every expression; if its argument is a The grouping of conjunction and alternation with other operations is a
generator, the generator is resumed when the procedure call is resumed. Thus, frequent source of problems. Conjunction has the lowest precedence of all opera-
tions. Alternation, on the other hand, has a medium precedence. Consequently,
suspend (1 | 3 | 5 | 7 | 11)
expr1 & expr2 | expr3
suspends with the values 1, 3, 5, 7, 11 as the call in which it appears is successively
resumed. groups as

expr1 & (expr2 | expr3)
Since, in the absence of parentheses, such expressions are easily misinterpreted, it is
Testing Icon Expressions Interactively good practice to use parentheses even if they are not necessary. There are many other
cases where this rule applies. For example,
Success, failure, and generation in expression evaluation are powerful pro-
gramming tools, but they may be unfamiliar. Testing various expressions interac- 1 to 10 | 20
tively (or in a simple program) can help with understanding expression evaluation
in Icon and dispel potential misconceptions. groups as

The program qei, mentioned in the Notes section of Chapter 1, is particularly 1 to (10 | 20)
useful in this context. The command :every at the beginning of a line instructs qei to
show every result of a generator. For example The moral is clear: Parenthesize for readability as well as correctness.

> :every 1 to 5; When control structures are nested, braces can be used for grouping as shown
in examples earlier in this chapter. Even if braces are not necessary, using them helps
produces avoid errors that may result from unexpected groupings in complicated expres-
sions. Using braces to delimit expressions also can make programs easier to read —
1 it is difficult for human beings to parse nested expressions.
3 Consistent and appropriate indentation (“paragraphing”) also makes pro-
4 grams easier to read. There are several styles of indentation. The one to use is largely
5 a matter of taste, but it should be consistent and should accurately reflect the
grouping of expressions.

Care should be taken not to specify a generator that has a large number of results. There are a few common syntactic problems that arise in control structures.
One is that the do clause in every, which, and until is optional. If a do clause is
Syntactic Considerations intended but omitted by accident, the results can be unexpected. Consider for
The way that expressions are grouped in the absence of braces or parentheses
is determined by the precedence and associativity of the syntactic tokens that while line := read()
comprise expressions. Appendix A contains detailed information on these matters. process(line)

Ideally, precedence and associativity lead to natural groupings of expressions This is syntactically correct, but since there is no do, all input lines are read and then
and produces the expected results. In some cases, however, what is natural in one process(line) is evaluated once. Because of the omitted do, only the last input line is
context is not natural in another, and precedence and associativity rules may cause processed.
expressions to group differently than expected. Such potential problems are noted
at the ends of subsequent chapters.

34 Expressions Chap. 2 Chap. 2 Expressions 35

The precedence of not is higher than that of any infix operation. For example, to assign 0 to either i or j, depending on the relative magnitudes of their values.
Although Icon allows such constructions, they tend to make programs difficult to
not find(s1, s2) = 10 read. It usually is better style to write such an expression as

groups as if i > j then i := 0 else j := 0

(not find(s1, s2)) = 10 The assignment and numerical comparison operators are easily confused.
As a general rule, it is advisable to use parentheses for grouping in expressions
containing not to avoid such unexpected results, as shown in earlier examples. i = (1 | 2)
If there is a “dangling” else in nested if-then-else expressions, the else clause
compares the value of i to 1 and then 2, while
is grouped with the nearest preceding if. Consider, for example, the following
section of a program for analyzing mailing lists:
i := (1 | 2)
if find("Mr.", line) then
assigns 1 to i. (The second argument of alternation is not used, since assignment only
if find("Mrs.", line)
needs one value.)
then mm := mm + 1
else mr := mr + 1

These lines group as

if find("Mr.", line) then {
if find("Mrs.", line) then mm := mm + 1
else mr := mr + 1

The precedence of then and else is lower than the precedence of any infix operation,

if i > j then k := i else k := j

groups as

if i > j then (k := i) else (k := j)

which usually is what is intended.
In Icon, unlike many other programming languages, control structures are
expressions. For example, the outcome of

if expr1 then expr2 else expr3

is the outcome of expr2 or expr3 depending on whether expr1 succeeds or fails.
Consequently, it is possible to write expressions such as

(if i > j then i else j) := 0

Furthermore. Chap. the focus of attention of this succession of operations. By making this string. it need not be mentioned in each operation. the position serves as a focus of attention within the subject. The term scanning refers to changing the position in the subject. The outcome of the scanning expression is the outcome of expr2. 3 String Scanning 37 3 String Scanning Icon has many facilities for manipulating strings of characters (text). called the subject. String scanning is illustrated by the function move(i). This chapter is devoted to string scanning. The form of a string-scanning expression is expr1 ? expr2 where expr1 provides the subject to be scanned and expr2 does the scanning. which increments the position by i characters if 37 . String scanning therefore involves operations that examine a subject string at a specific position and possibly change the position. operations on a string often involve finding a position of interest in the string and working from there. Its most powerful facility is high-level scanning for analyzing and synthesizing strings in a general way. Other string-processing facilities are described in Chapter 4. THE CONCEPT OF SCANNING Icon’s string scanning facility is based on the observation that many operations on strings can be cast in terms of a succession of operations on one string at a time. Thus.

positions in strings are between characters and are numbered starting with and the subject is used in its place. so that For example. For example. Conse- } quently. This function also produces the portion of the writes the characters of text from right to left. Note that the scanning expression generates d r a g o n all the values generated by find("the"). Similarly. text ? { if tab(3) then write(text ? tab(find(". its second argument is omitted. what precedes or follows it. 3 Chap. In Icon. } . write(tab(0)) and a negative argument to move() decreases the position in the subject. Since a string-analysis function produces a position and the The matching function tab(i) sets the position in the subject to i. the subject while changing the position is called a matching function. The string-analysis STRING POSITIONS function find(s1. writes the portion of text after the first comma in it (if any). ↑ ↑ ↑ ↑ ↑ ↑ ↑ In string analysis. STRING ANALYSIS String analysis often involves finding a particular substring. For convenience in referring to characters with respect to the right end of the every write(text ? find("the")) string. Notice that it is not necessary to know subject between the old and new positions. The argument of tab() can be given by a nonpositive specification. which is the position to the left of the first character: write(text ? find("the")) d r a g o n ↑ ↑ ↑ ↑ ↑ ↑ ↑ writes the position of the first occurrence of "the" in text. } text ? { writes the even-numbered characters of text starting with the fourth one. The function pos(i) succeeds if the position in the subject is i but fails otherwise. 1. s2). provided there is one. provided if tab(find(". Scanning starts at the beginning of the subject. used earlier to illustrate failure and generation. performs this operation. the two can be used in combination. 1 2 3 4 5 6 7 Similarly. text ? { expr & pos(0) while move(1) do write(move(1)) succeeds if the position is at the right end of the string after expr is evaluated. there are corresponding nonpositive position specifications: writes all the positions of "the" in text. text ? { tab(0) Alternation may be used in the argument of find() to look for any one of several while write(move(–1)) strings. For example. } writes the even-numbered characters of text on separate lines. the actual value of the position of a substring usually is not –6 –5 –4 –3 –2 –1 0 as interesting as the context in which the substring occurs — for example."))) while move(1) do write(move(1)) writes the initial portion of text prior to the first comma in it (if any). For example. For example. 38 String Scanning Chap. 3 String Scanning 39 that is possible but fails if it is not.") + 1) then text is that long. matching function tab() moves to a position and produces the matched substring. A function that produces a substring of how long text is. When find() is used in string scanning.

produces the position in the subject at the end of s. if there is an "a" in text. even if there is writes the strings of characters between strings of blanks. There are three string-analysis functions in addition to find(). "The theory is fallacious" ? match("The") every write(text ? upto(vowel)) produces 4. which generates the positions in the subject in which any character in the cset c occurs. Thus. and "The theory is fallacious" ? match(" theory") text ? { fails. For example. if ="checkpoint" then Another string-analysis function that uses csets is many(c). Note that tab(0) is used to match the remainder of the subject after the last blank (if any). A cset is just what it Treating a “word” as simply a string of letters is. On the other hand. matched by the expression tab(many(' ')). } Csets (character sets) are provided for such purposes. then } line ? { writes the portion of text after the first instance of a lowercase vowel (if any). vowel := 'aeiou' Matching Substrings is a cset that contains the five lowercase “vowels”. the following scanning expression writes all the “words” in text: In the example above. For example. a sequence of characters in which order is very important. skipping over them in scanning. 3 Chap. the scanning expression at the end of the preceding write(tab(many(&letters))) section does not write the first lowercase vowel. For example. naive. A cset can be given literally by using single quotes to enclose the characters (as STRING-ANALYSIS FUNCTIONS opposed to double quotes for string literals). of course. the value of the keyword &letters is a cset containing the upper. there is no sounds like — a set of characters. In fact. CSETS Similarly. } . all the simple definition of “word” that is satisfactory in all situations. There is no concept of order in a cset. and upto(). of these is upto(c). the string after it is written. if tab(upto(vowel) + 1) then The operation =s is equivalent to tab(match(s)). since string scanning starts at the beginning of the subject. 40 String Scanning Chap. For example. the function match(s) lowercase letters. in string analysis. Strings of blanks are another vowel before the "a".and If s occurs at the current position in the subject. For example. many(). which produces base := tab(0) the position after a sequence of characters in c. It fails if s does not occur at the Icon has several string-analysis functions that use csets instead of strings. A cset is therefore very different from a string. However. There also are built-in csets. this naive characters in it are on a par. order often is not important or even while tab(upto(&letters)) do appropriate. what happens depends on the order in which the alternatives text ? { are written. One current position in the subject. while writes the positions of every vowel in text. For example. if line begins with write(tab(0)) the substring "checkpoint". 3 String Scanning 41 text ? { text ? { if tab(find("a" | "e" | "i" | "o" | "u") + 1) then while write(tab(upto(' '))) do write(tab(0)) tab(many(' ')) } write(tab(0)) } writes the portion of text after a lowercase vowel. Since alternatives are tried only if they are needed. which is one is easy to express and suffices in many situations.

it may produce more than one result. ')]') write("Our conjecture has support" ? tab(any('aeiou'))) is 8.42 String Scanning Chap. 10]]" ? tab(bal('. a count is kept starting at word ? { zero as characters in the subject are examined. the value produced by writes O. [2. expres- sions. its presence in c2 counts. For example. not a substring. All characters in c2 and c3 have equal status. several. taken together. For example. It first saves the current scanning environment. except that any() depends on the character no effect as a character in c3. [5. [2. pro. the count is incremented. 3 String Scanning 43 assigns the remainder of line to base. [∗. bal() fails. It also resembles many(). the count is zero. A scanning expression. the former is balanced with respect to parentheses. An example is: write("[+. vided the preceding substring is “balanced” with respect to characters in c2 and c3. write("((2∗x)+3)+(5∗y)" ? tab(bal('+'))) then starts a new environment with the subject set to the string produced by expr1 and the position set to 1 (the beginning of the subject). "–35" ? bal('–') expr1 ? expr2 produces 1 (the string preceding the minus is empty) but starts a new scanning environment. If a character in c1 is encountered and . This function is useful in applications that involve the analysis of formulas. Note that the position of the first "+" is not preceded by a string that the evaluation of expr2 is complete (whether it produces a result or fails). c3) generates the positions of characters in c1. produces the position after that character. Bracketing characters other than parentheses can be specified. c2. or if the count is positive after examining If the character at the current position in the subject is in the cset c. Next. bal() produces that position. When writes ((2∗x)+3). while tab(upto(&letters)) do { word := tab(many(&letters)) In determining whether or not a string is balanced. any(c) the last character of the subject. but any() matches one character instead of Since bal() is a generator. while "([a+b))+c]" ? bal('+'. Otherwise. c3 are omitted. and any one of several of characters may be specified. Other characters leave the count unchanged. string- scanning expressions can be nested. except that c2 and c3 specify sets of characters The subject and position in string scanning. If c2 and ment” in which matching and string-analysis functions operate. 3]]. '['. every write(formula ? bal('∗')) Matching Balanced Strings writes the positions of all asterisks in formula that are preceded by parenthesis- The function bal(c1. and other strings that have balanced bracketing characters. bal() cannot be used to determine write("Our conjecture has support" ? tab(any('aeiouAEIOU'))) proper nesting of different bracketing characters. If the counter ever becomes negative. scanning environment is restored. balanced substrings. expr2 is evaluated. For example. '(' and ')' are assumed. if a character in c2 is encountered. The expression Since scanning environments are saved and restored in this fashion. it has Note that any() resembles match(). 3]]. For example. If c2 and c3 both contain the same character. ']'))) text ? { writes [+. while the count is decremented if a character Matching a Character in c3 is encountered. constitute an “environ- that must be balanced in the usual algebraic sense up to a character in c1. fails and does not write anything. SCANNING ENVIRONMENTS The function bal() is like upto(). '(['.'. It fails otherwise. 3 Chap. at the current position.

as in write("subject=". There usually is no need to refer to In qei (available in the Icon program library and described in the Notes section the subject and position explicitly — in fact. In addition. it becomes the subject in the current scanning r2_ := 4 environment and the position is automatically set to 1. the whole purpose of string scanning is of Chapter 1) a helpful approach is to set up a string for subsequent tests. &subject. > text := "The theory is fallacious". it may be useful. can be used to scan s and assign a new value to it. 3 Chap. expression fails and the value of line is not changed. If a value is assigned to &pos. > text ? { > tab(5) s ?:= expr > move(1) > }. scanning may involve several expressions. however. the following line writes the subject and position: if r1_ already has been created). If it is not in range. position =". the assignment to &pos fails. ". as in Augmented assignment. For example. The subject and position in scanning environments are maintained automatically by scanning expressions and matching functions. The value assigned is the value > r3_ := "t" produced by expr. Now various scanning expressions can be tried. 44 String Scanning Chap. provided > Failure the value is in the range of the subject. If a value is assigned to &subject. As in examples shown earlier. If line does not begin with a blank. and it may be hard to see how to use it to perform string analysis. the scanning subject and the current position in scanning. testing expressions interactively (or writing small programs) can be very helpful in learning to use string scanning. 3 String Scanning 45 if upto('aeiou') then write(move(1)) NOTES } } Testing Expressions Interactively } String scanning is one of the most powerful features of Icon. > text ? match("theory"). the position in the current scanning environment is changed accordingly. This is easily handled in qei by opening a compound expression with a left brace without a terminating semicolon and writing the remaining expressions on separate lines AUGMENTED STRING SCANNING without semicolons. Its apparent This expression writes the first letter of those words that contain a lowercase vowel. this module contains a procedure snapshot() that shows the removes any initial blanks from line. . simplicity masks a wealth of uses. String scanning also may be difficult to under- stand initially. Two keywords are provided for this purpose: &subject and &pos. Library Resources line ?:= { tab(many(' ')) & tab(0) The library module scan contains several procedures that supplement Icon’s } built-in scanning functions. In some situations. Note that the string is assigned to both text and r1_ (or some other variable qei creates For example. An example to treat these values implicitly so that they do not have to be mentioned during string from this chapter is: scanning. &pos) > text ? match("The"). finally ending with a right brace and semicolon. or even necessary. SCANNING KEYWORDS Again. to refer to the r1_ := text := "The theory is fallacious" subject or position explicitly.

it is important to be careful 256 characters to be entered from input devices. so that and Strings text ? i := find(s1) & j := find(s2) groups as (text ? i := find(s1)) & (j := find(s2)) This probably is not what is intended. but it has two data types that are composed of since the completion of the scanning expression at the left of the conjunction restores characters: strings. 3 Chap. and any character can be computed directly during program execution. Consider the following expression: programs by escape sequences in string and cset literals. and their uses vary from one computer system to another. it is form. find(s2) does not characters. Csets. line ?:= { Most files are composed of characters. are useful for representing various kinds of information and for operating the subject is a zero-length. it is good practice to clearly delimit the second argument of the scanning expression. described briefly in previous operate on text but on some other subject. Other characters are used for control purposes. it looks like it does. they all can be represented in Icon that the outcome of scanning is the intended one. outcome has nothing to do with text. which is used in most of the examples of string scanning in this book. its on textual data in different ways. The associa- The scanning expression eventually fails. 47 . is important to understand the significance of the characters from which they are s?{ composed. and most input and output consists of while tab(upto(&letters)) do characters. Although most computer systems do not allow all Since scanning expressions can be complicated. Csets. and csets only somewhat less so. control characters. and csets. Some characters are “printable” and have graphics (“glyphs”) associ- tab(many(&letters)) ated with them. since it contains the expressions that perform scanning. (In the absence of any scanning expression. chapters. such as for indicat- } ing the end of a line on a display device or printer. Icon has no character data type. and the source of the problem may be hard to locate. One such Since strings are of major importance in Icon. Consequently. which may make debugging difficult. These two organizations of characters. and Strings 47 4 Syntactic Considerations The second argument of ? often is fairly complicated. the precedence of ? is low. However. no } characters are excluded from use. and text ? i := find(s) groups as text ? (i := find(s)) Characters. no value is assigned to line. which are sets of the subject and position to their former values.) Whether find(s2) succeeds or fails. Consequently. since the tion between the numeric value of the pattern of bits (code) for a character and its while loop itself fails. Consequently. However. The difficulty is that j := find(s2) is not evaluated with text as the subject. The printable characters. the precedence of ? is greater than & (conjunction). … Icon uses eight-bit characters and allows all 256 of them to be used. CHARACTERS Because of the likelihood of conjunction in scanning expressions. regardless of the value of line.46 String Scanning Chap. which are sequences of characters. 4 Characters. empty string.

so char(65) produces the one-character string "A" in ASCII. especially when it is read in. however. while in EBCDIC they are near consisting of a single backslash. and Strings 49 graphic also depend on the “character set” the system uses. For example. String Length String Literals The length of a string is the number of characters in it. so strings of digits compare the same way in both ASCII and EBCDIC. " \"" is a string representing a double quote and " \\" is a string with codes near the beginning of the character set. and stored in files. "Hello world" almost all computers use ASCII. There is no practical limit to the length of a string. Therefore. For example. in terms of the graphics for the characters (such as A) and the associated codes are irrelevant. For example. The exceptions are IBM mainframes." example. For example. The escape sequences can be used in string literals for characters that cannot be keyboarded directly. Similarly. An example is EBCDIC. Character Codes The function char(i) produces the one-character string corresponding to the STRINGS integer i. . but with the bit pattern 11000001 (decimal code 193) in the EBCDIC character set. they usually do not cause problems because an Icon program running on an ASCII system produces the results that the user of an ASCII What I want to say is system expects. " \ t" is a string consisting of a tab and "\n" is a string consisting of a newline on the numeric codes associated with graphics. See Appendix B for more information about character sets. the digits are in the order of their character codes. Such programs usually are written Note that blanks to separate words are put before underscores at the ends of lines. for long to be written comfortably _ the most part. Writ. regardless of whether the character set is ASCII or EBCDIC. Escape sequences start with the character \ (backslash). Most of the information the one-character string s. processed by computers consists of sequences of characters. Csets. space (blanks and tabs) are discarded at the beginning of the next line and the parts Most computer systems use ASCII. The operation ∗s produces the length of s. so strings containing both letters and digits may compare differently in ASCII and EBCDIC. is just a sequence of characters. although very long strings assigns the string "aeiou" to vowel. such as this book. As described earlier. the digits are associated character. In both cases. The empty string is represented literally by "". And. which use are joined. as mentioned earlier. strings are represented literally with surrounding double quotation marks. While these writes differences cannot be helped. 4 Characters. the digits write("What I want to say is\n\"Hello world\"") occur before the letters in ASCII but after the letters in EBCDIC. 4 Chap. programs that analyze text files usually work the same way. and Strings Chap. For There are exceptions. and listings for several platforms. The inverse function ord(s) produces the integer (ordinal) corresponding to ten text. ∗"Hello world" vowel := "aeiou" produces the integer 11. However. For on a single line. Comparison of characters and sorting depend example. 48 Characters. and similarly on an EBCDIC system. which contains no characters and has zero length. it does not matter which codes correspond to which characters. The smallest string is the empty string. A complete listing of escape sequences is given in Appendix A. the internal integer representation for A is 65 in ASCII. White set. the end. Csets. In ASCII. the letter A single string literal can be continued from one line to the next by ending each A is associated with the bit pattern 01000001 (decimal code 65) in the ASCII character line that is incomplete with an underscore and continuing on the next line. sentence := "This string literal is too _ Most text processing involves printable characters that have graphics and. are awkward and expensive to manipulate. the glyphs used in different situations. Strings are used more frequently than csets because the sequential organization of strings allows the representation of complex relationships among characters. written out.

For example. lexical order is determined by the lexical order of their characters. Concatenation For longer strings. s1 == s2 lexically equal The empty string is the identity with respect to concatenation. Then the following procedure produces a list of these procedure main() words with each followed by a comma. while the code for "R" is 82. STRING CONSTRUCTION there is relatively little relationship between the codes for other characters. less than "ab". tions. As mentioned end earlier. s1 << s2 lexically less than s1 <<= s2 lexically less than or equal "Hello " || "world" s1 >> s2 lexically greater than s1 >>= s2 lexically greater than or equal produces the string "Hello world". Csets. the shorter string is lexically less than the longer. The comparison of strings is based on lexical (alphabetical) procedure main() order rather than numerical value. For example. concatenating s1 ~== s2 lexically not equal the empty string with another string just produces the other string. the ASCII codes for the digits are smaller than the codes for letters. and Strings Chap. For example. such as punctuation. and Strings 51 LEXICAL COMPARISON This program can be rephrased in a way that is more idiomatic to Icon by using augmented assignment operations: Strings can be compared for their relative magnitude in a manner similar to the comparison of numbers. Therefore. Csets. 4 Characters. The character c1 is lexically less than c2 if the code for c1 is less than the code for c2. there are impor. 50 Characters. while the opposite is true in EBCDIC. write("lexically smallest line is: ". character by character. max) write("lexically smallest line is: ". min) return wlist end end . uppercase letters in ASCII have smaller codes than lowercase letters." write("lexically largest line is: ". If one string is an initial substring of another. In addition. Lexical order is based on the codes for the min := max := read() # initial min and max characters. in ASCII the code for "B" is 66. Two s1 || s2 strings are lexically equal if and only if they have the same length and are identical. in ASCII "AB" is less than "aA" and "aB" is One of the more commonly used operations on strings is concatenation. The empty string is lexically less than any other string. 4 Chap. (max <<:= line) | (min >>:= line) Although the relative values of letters and digits are the same in ASCII and write("lexically largest line is: ". in the two character sets. There are six lexical comparison operations: which produces a string consisting of the characters in s1 followed by those in s2. while line := read() do so "B" is lexically less than "R". min := max := read() # initial min and max procedure wordlist() while line := read() do wlist := "" # initialize if line >> max then max := line else if line << min then min := line while word := read() do wlist := wlist || word || ". For example. each of which contains a single word. Furthermore. suppose that the input file consists of a number of lines. "Aba" is lexically less than "Abaa" in both ASCII and EBCDIC. min) tant differences between the ordering in the two character sets. The empty string The use of lexical comparison is illustrated by the following program. which therefore is a natural initial value for building up a string by successive concatena- determines the lexically largest and smallest lines in the input file. max) EBCDIC and produce the expected results in lexical comparisons. from left to right. while the opposite is true in EBCDIC.

if necessary. 4 Characters. but it may be of any length. Note that the padding string is truncated at the right." $define Limit 10 is equivalent to procedure main() wlist := wlist || word || "." every i := 1 to Limit do { write(right(i. Csets. 10. If s1 cannot be centered exactly. The function center(s1. aligning the string in the field at the right. right(i ^ 3. 10. 8). it is truncated at the left so that the value has length i. the expression can be written } more compactly as end while wlist ||:= read() || ". illustrates such an application: wlist ||:= word || ". center("Detroit". and Strings Chap. while produces "+∗+Detroit". 6) . blanks are used for padding. Therefore. There are three functions that position a string in a 5 25 125 625 field of a specified width. Truncation is then done at the left and right if necessary. right(i ^ 2. i. and Strings 53 The augmented assignment operation for concatenation is particularly useful A common use of right() is to position data in columns. for appending strings onto an evolving value. with s2. center("Detroit". padding on the produces "etroit"." The output of this program is: 1 1 1 1 STRING-VALUED FUNCTIONS 2 4 8 16 3 9 27 81 When producing formatted output. The following program. i. left("Detroit". "+") produces "+++Detroit". any extra characters that might result from prepending copies of s2 are discarded. i. it often is useful to have “fields” of a specific 4 16 64 256 width that line up in columns. Csets. right("Detroit". 6) right("Detroit". right(i ^ 4. Enough copies of s2 are concatenated on the left to make up the specified length. s2) produces a string of length i in which s1 is positioned at the right and s2 is used to pad out the remaining characters to the left. The padding string is truncated at the left if necessary. 10. For example. 8)) The do clause in the while loop above is not necessary. If s2 is omitted. 7 49 343 2401 8 64 512 4096 Positioning Strings 9 81 729 6561 10 100 1000 10000 The function right(s1. "+") right("Detroit". left and right. i. and truncation (if necessary) is done at the right. however. s2) is similar to right(s1. left. "+∗") produces "+Detroit++". 6) produces "Detroi". the left of center. is reversed: s1 is placed at the left. 4 Chap. For example. which prints out a table of the first four powers of the integers from 1 to 10. or in the 6 36 216 1296 center. 8). Therefore. 10. s2) centers s1 in a string of length i. Therefore. padding is done on the right. produces "Detroit+++" and If the length of s1 is greater than i. "+") left("Detroit". The resulting string is always of size i. s2) except that the position For example. 5). The function left(s1. 52 Characters. it is placed to The value of s2 usually is a one-character string.

since each vowel appears twice. Tabular Data map("mad hatter". "+") Tab characters are useful for separating fields and displaying them in an aligned fashion on devices such as computer terminals. the interval is 8 with the first tab stop at 9. There is an implicit tab stop at 1 to establish the interval between tab stops. 4 Chap. c) produces a string consisting of the initial substring of s with the omission of any trailing characters contained in c. other letters. The remaining tab stops are at i1. For the purposes of determining positions. That is. For example. i1. i2. repl("+∗+". For example. Duplicate characters in s2 provide a way to mask out unwanted tab character in s by one or more blanks. in) produces a string obtained by replacing runs map("mad hatter". "+++++") restarts the counting of positions. corresponding character in s3. i). printable characters have a width of 1. in. it is more s2 := &letters || "AEIOUaeiou" convenient and efficient to use repl(s. produces "m+d h+tter" and The function entab(s. A lone blank is never replaced by a tab character. plished by mapping every vowel into an asterisk and mapping all other letters into blanks. Characters of s1 that do not appear in s2 are not changed. The value of s3 is 52 blanks followed by 10 asterisks. The last 10 characters in s2 and s3 override the previous produces "+∗++∗++∗+". 4 Characters. replace a single blank that is part of longer run. 0) produces the empty string. and Strings 55 produces "etroit" and Mapping Characters center("Detroit". blanks are trimmed. in) produces a string obtained by replacing each s3 applies. and a newline or return character map("mad hatter". Other nonprintable characters have zero width. and Strings Chap. . If a character appears more than once in s2. the backspace character has a width of −1. if necessary. correspondences between the vowels and blanks. For example. i2. An easy way to do this is to set up a correspondence between every letter and Replicating Strings a blank and then append the correspondences for the vowels: When several copies of the same string are to be concatenated. "+ –") The function map(s1. s2. which produces the concatenation of i copies s3 := repl(" ". the rightmost correspondence with The function detab(s. s3) The function reverse(s) produces a string consisting of the characters of s in produces a string with asterisks in the positions of the vowels and blanks for all the reverse order. Consequently. …. Several characters in s2 may have the same corresponding character in s3. "12345") of consecutive blanks in s by tab characters. 9. reverse("string") Trimming Strings produces "gnirts". it trims off characters in c. "a". Csets. Tab stops are specified in the same way as characters. In this correspondence. For example. …. …. produces "m1d h1tt2r". If no tab stops are specified. If c is omitted. For example.54 Characters. are obtained by repeating the last interval. ∗&letters) || "∗∗∗∗∗∗∗∗∗∗" of s. marking the positions of vowels in a string can be accom- for entab(). "aeiou". Reversing Strings map(line. i2. "aeiou". s2. Additional tab stops. The expression repl(s. For example. Csets. s2 is a string consisting of all letters followed by the vowels. s3) produces a string resulting from a character mapping of s1 in which each character of s1 that appears in s2 is replaced by the produces "+Detroit–". 3) 62 characters in all. but a tab character may produces "m+d h+tt+r". The function trim(s. i1.

The which produces the first three characters of text. This is another example of the design philosophy of Icon: If an operation cannot be performed. those between positions 1 and 4. Nonpositive position specifications. as are "leo" and "e". Csets. in which a range specification enclosed in brackets gives the positions that bound the desired substring. where i and j are the bounding positions. procedure main() SUBSTRINGS while line := read() do { line := line[1:61] # truncate Since a string is a sequence of characters. trim("Betelgeuse". Similarly. Note that this is a substring of two characters. Expressions containing such ambiguous failure should be avoided. For writes the first 60 characters of line. "Co". is not a substring of "Cleo". rather than to the right. "Cl" is a } substring of "Cleo". line[1:4] and line[4:1] are equivalent. A substring is simply a portion of another string. 4 Characters. The applied to strings that are the values of identifiers. does not work properly in place of the two lines in the previous procedure. only the bounding positions are significant. Note that this expression may fail for two reasons: if read() fails because there is no more input. and Strings 57 trim("Betelgeuse ") which assigns a substring of a line of input to s. 4 Chap. Positive and nonpositive specifications can be mixed. Note that Subscripting Strings write(line[1:61]) A substring is produced by a subscripting expression. as in leftmost position need not be given first. Therefore. no output for such lines. The range specification i+:j specifies a substring starting at i of length j. and Strings Chap. while a line that is not long enough. it can be specified by the position before it. any subsequence or substring is also a write(line) string. For example. produces the substring of text between 2 and the size of s. For example. since this One form of range specification is i:j. Any string is a substring of end itself. 56 Characters. For subscripting expression fails if a line is less than 60 characters long. line[–1:0] is the last character of line. 'aeiou') The following program illustrates the use of substrings to copy the input file to the output file. In this case the failure occurs because the write(line[1+:60]) specified substring does not exist. it does not produce a result. truncating long output lines to 60 characters. produces just "Betelgeus". because the characters are between the specified positions. Csets. There would be example. text[1:4] Range specifications also can be given by a position and an offset from that position. Expressions can be used to provide the bounds in range specifications. Range specifications usually are The two positions in a range specification can be given in either order. as in write(line[2]) s := read()[2:10] . also can be used "Cleo"[1:3] in range specifications. write(line[61–:60]) text[2:∗s] If a substring consists of only a single character. the subscripting expression fails. since they can be the source of subtle programming errors. not three. or if read() produces produces "Betelgeuse". produces "Cl". The empty string is a substring of every string. however. characters to the left of i. described in Chapter 3. as does example. any expression whose value is a string can be subscripted. If offset can be negative: i −:j specifies a substring starting at i but consisting of the j the value of text is less than three characters long. since "C" and "o" do not occur consecutively in "Cleo". Therefore. For example.

For example. word[–1] := "" Character Generation deletes the last character of word so that its value becomes "to". but not to old. assigns the last character of line to last. assignment can be made to ?s to replace a Assignment can be made to a subscripted variable to change the substring randomly selected character of s. ?"HT" last := line[–1] produces the string "H" or "T" with approximately equal probability. Note that an The expression !s generates the one-character substrings of s in order from first assignment that changes a substring may change the length of a string. If s is empty. In an expression such as "Cleo"[1] := "K" every !s := expr is erroneous. . For example. Csets. and Strings 59 writes the second character of line and is equivalent to Randomly Selected Characters write(line[2+:1]) The operation ?s produces a randomly selected one-character substring of s provided that s is not empty. the result can be confusing. changing a substring in one does If s is a string-valued variable. the expression !s produces a variable. If s is a string-valued variable. one per line. For example. 4 Chap. For example. For example. line := read() !s := "" old := line line[2+:3] := "" is equivalent to the value of old is not changed by the assignment to line[2+:3]. Similarly. but the position in s is incremented repeatedly until the end of the string is reached. This expression is equivalent to is shorthand for every write(s[1 to ∗s]) word := word[1] || "o" || word[3:0] If two variables have the same string value. If the assignment changes the length of s. Assignment can be made to a subscripting expression to change the value of a string only if the range specification is applied to a variable. Csets. since a literal value cannot be changed. every write(!s) word[2] := "o" writes the characters of s. 4 Characters. Similarly. if the value of word is "two". the value of s is changed with each assignment. to change a substring is a just shorthand notation for concatenation. A new value is s[1] := "" assigned to line. in does. corresponding to the range specification. Therefore. changes the value of word to "too".58 Characters. just as s[i] not change the value of the other. ?s fails. and deletes the first character in the value of s. ?s := "" word[2] := "o" deletes a randomly selected character of s. Assignment to last. and Strings Chap. For example. left to right. For example.

For example. The operation ∗c produces the while line := read() do number of characters in c. and digits: &ucase. "The theory is fallacious". restrict the range in which the analysis is done. 'uoiea'. occurs as a substring of s2. and produces 7. Built-in Csets upto('aeiou'. 11) Icon provides keywords for commonly needed csets. the range-restriction arguments can be given either writes out all the digits in text. and Strings Chap. This conversion applies to csets and strings. The intersection the input file. the set of all 256 characters. upto(c. Csets. 60 Characters. string analysis functions are not restricted to string scanning. 5. "The theory is fallacious"[5:11]) text ? { is 3. while tab(upto(&digits)) do An omitted value of i defaults to 1. } Like range specifications. Cset Literals The analysis functions can be applied to a specific string by adding that string as an additional argument. 'aeiou'. all the letters. &lcase. 4 Characters. characters are ignored. the subject and the position in it are irrelevant. –10) Operations on Csets restricts the range in s2 to the last 10 characters. &letters ++ &digits contains all the letters and digits. respectively. regardless of the form of the specification. s2. s) generates the position at which characters The order of the characters in a cset literal is not important. j) restricts the value to positions between i and j in s. find(s1. chars := chars ++ line return chars end . lowercase letters. Icon automatically converts values from one type to ~c complement another according to context. the following procedure produces a cset of all the characters that occur in For example. For example. s. one per line. For example. i. such as the uppercase letters. Consequently. as positive or nonpositive position specifications and can be given in either order. 4 Chap. The difference of two csets is a cset that contains all the characters in the first that are not procedure inset() in the second. An omitted value of j write(move(1)) defaults to 0 and restricts the value to positions between i and the end of the string. find(s1. Icon has four operations on csets: c1 ++ c2 union CONVERSION BETWEEN CSETS AND STRINGS c1 ∗∗ c2 intersection c1 – – c2 difference As described in Chapter 1. Therefore. and upto(c. upto('aeiou'. and Strings 61 CSETS STRING ANALYSIS As illustrated earlier. For example. the set of the first 128 characters in ASCII. 0. For example. ~&digits is equivalent to &cset – – &digits. of two csets is a cset that contains all the characters that appear in both csets. The complement of a cset contains all the characters that are not in it. s2) generates the positions where s1 A cset can be written literally by using single quotes to enclose the characters. the beginning of s. &letters. the value produced by &digits. and 'aeiouaeiou' all produce All the string analysis functions also may have two additional arguments that the same cset. and duplicate in c occur in s. In such usages. example. and &ascii. Note that this is a position in s. Substrings are always found from left to right. For The union of two csets is a cset that contains all the characters in either of the two. For example. &cset – – &digits contains all the characters that are not chars := ' ' # empty cset to start digits. Other built-in csets are &cset. Csets.

while 36rcat represents 15. …. For example. where i is a base-10 integer that specifies the base for j. … ) concatenate an arbitrary number of strings converted to real numbers automatically in mixed-mode operations that involve deletec(s. s2. deletes(s1. 2r11 operation produces the value of its right argument. Such radix literals have the same precedence as the numerical comparison operations. 16ra represents 10. b. the expression through 36. 36 represents the of the numerical comparison operations.0 parentheses to specify desired grouping. 63 .700. s3) replace all occurrences of s2 in s1 by s3 machine integers. The base can be any value from 2 succeeds. Csets. the letters a. Then the characters in each line of input are added to chars. c) delete all occurrences of characters in c from s both integers and real numbers. Real numbers can be represented enation is used in combination with numerical computation. s2) delete all occurrences of s2 in s1 Integers in Icon can be arbitrarily large. The usual operations on integers and real numbers are provided. If concat. and Strings Chap. Integers are cat(s1. while 8r10 represents 8.941. A lexical comparison form i r j. Real (floating-point) numbers vary in range and precision from platform to platform.0. All the lexical comparison operations associate from left to right and have the Bases other than 10 can be used for integer literals. For example. Some of the most useful procedures in this module are: Numerical computation in Icon is similar to that in most programming languages. they are not restricted to the size of replace(s1. 62 Characters. 5 This procedure can be written more compactly using augmented assignment: procedure inset() chars := ' ' # empty cset to start while chars ++:= read() return chars Numerical Computation end and Bit Operations NOTES Library Resources The module strings contains many procedures for manipulating strings. 5 Numerical Computation and Bit Operations 63 The cset chars initially starts out empty. See Appendix A s1 << s2 << s3 for additional details of the syntax of numeric literals. succeeds and produces s3. i) rotate s by i characters floating-point values native to the computer on which Icon runs. They normally are represented by the double-precision rotate(s. In the union operation. s2. Syntactic Considerations NUMERIC LITERALS Concatenation associates from left to right. For example. provided s2 is strictly between s1 and s3 in lexical order. the value of line is a string that is automatically converted to a cset. provided that the comparison represents the integer 3. given literally by enclosing no characters in single quotes. Its precedence is higher than that Integers are represented literally in the usual way. z are used to specify “digits” in j that are larger than 9. are equivalent and represent the real number 2. For example.024. There are also bit operations on integers. 4 Chap. it is advisable to use literally using either decimal or exponent notation. but lower than that of addition. Therefore. 27e2 and 2700. integer 36 and 1024 represents the integer 1.

14159 and the result of produces the numeric value of N. angles are given in radians. 5 Numerical Computation and Bit Operations 65 ARITHMETIC 10 + 3. Division by zero and raising a negative real number to a real power are dtor(r) the radian equivalent of r given in degrees erroneous. floating-point arithmetic and produces a real number. Icon also provides the following functions for mathematical calculations: The function abs(N) produces the absolute value of N. that is. The operation +N is 13. The default for r2 in atan() is 1.14159 Icon has two prefix (unary) operations for numerical computation. For example. Such errors cause program execution to terminate with a diagnostic rtod(r) the degree equivalent of r given in radians message. r2) arc tangent of r1 / r2 10 % –3 In all cases. the result of . For example. N1 > N2 greater than N1 ~= N2 not equal to –7 / 2 produces −3. For example. For example. The following functions convert between radians and degrees: produces 1. r2) logarithm of r1 to the base r2 Any numerical computation that involves a real number is performed using The default for r2 is e.0 relative is –3.0.5. The infix (binary) operations for numerical computation are as follows: –7 / 2. the value is truncated toward N1 >= N2 greater than or equal to 0. abs(–7 / 2) sqrt(r) square root of r exp(r) e raised to the power r produces 3. 5 Chap. but atan(r1. cos(r) cosine of r tan(r) tangent of r –10 % 3 asin(r) arc sine of r acos(r) arc cosine of r produces −1. MATHEMATICAL COMPUTATIONS The operation Icon provides the standard trigonometric functions: N1 % N2 sin(r) sine of r produces the remainder of N1 divided by N2 with the sign of N1. while −N produces the negative of N. log(r1. 64 Numerical Computation and Bit Operations Chap. expression operation precedence associativity N1 ^ N2 exponentiation 3 right to left N1 % N2 remaindering 2 left to right NUMERICAL COMPARISON N1 / N2 division 2 left to right N1 ∗ N2 multiplication 2 left to right Icon’s numerical comparison operations are N1 – N2 subtraction 1 left to right N1 < N2 less than N1 + N2 addition 1 left to right N1 <= N2 less than or equal to N1 = N2 equal to In integer division the remainder is discarded.

icom(1) RANDOM NUMBERS produces −2. j) and ixor(i. Library Resources The same pseudo-random sequence is used for all random operations. 66 Numerical Computation and Bit Operations Chap. For example. can be used: ior(4. j) produce the bitwise inclusive and exclusive places where only integers that are small enough to be represented as native integers or of i and j. For example. and vacated bit positions are filled with zeros. Integers that are larger iand(4. the expression ishift(2. the operation ?s described in Chapter 4 uses the same sequence as ?i. Icon uses integers native to the platform on which it runs. produces 4. The operation ?i produces a pseudo-random number. This sequence is the same from one program execution to another. of i is 0. For example. 3. but there are a few The functions ior(i. For example. The function iand(i. Pseudo-random numbers are produced by a linear congruence relation start. If j is negative. 6) i to j by k seq(i. ishift(2.61803… &pi ratio of circumference to diameter of a circle. can be changed by assigning an integer value to &random. 2. If j is positive. respectively. If the value of i is a positive integer i. j) produces the bitwise and of i and j. Large integers are supported in all arithmetic computations. 3) if ?2 = 1 then "H" else "T" produces 16. 1. NOTES &random := 0 resets the seed to its initial value.0 ≤ r < 1.71828… produces 2. 5) than native integers are represented by blocks of data that Icon manages in a way that is transparent in writing and running Icon programs. These native integers are at least 32 bits long and may be longer. the shift is to the left. &phi golden ratio. magnitude of integers in Icon. If the value The function ishift(i. i is shifted to the right with sign extension. 5 Chap. Internally.14159… The function icom(i) produces the bitwise complement of i. formatting numbers and performing simple numeric computations. while integer-valued keywords . For example. j) shifts i by j positions. 5 Numerical Computation and Bit Operations 67 Keywords provide values of frequently used mathematical constants: ixor(4.0. All these operations As mentioned in the beginning of this chapter. the value produced by ?i is a real number r in the range 0. BIT OPERATIONS Large Integers Icon has five functions that operate on integers at the bit level. the value produced by ?i is an integer j in the range 1 ≤ j ≤ i. j) produces 6. there is no limitation on the produce integers. For The library module numbers contains a large collection of procedures for example. while produces the string "H" or "T" with approximately equal probability. –3) ing with an initial seed of 0. The seed produces 0. For example. 6) &e base of the natural logarithms. allowing programs to be tested in a reproducible environment.

For example. inclusive. 5 Numerical Computation and Bit Operations 69 It is also worth knowing that large integer literals in a program such as Comparison operations associate from left to right. . Consequently. –N + 3 groups as (–N) + 3 The comparison operations all have the same precedence. All infix arithmetic operations have precedence higher than that of assign- ment. 5 Chap. such literals should not be placed in loops or other places in which groups as they are evaluated frequently. (1 <= N) <= 10 Syntactic Considerations and succeeds if the value of N is between 1 and 10. Therefore. Consequently. which is lower than that of any numerical computation operation. 174359213645100235 1 <= N <= 10 are converted to actual large integers when evaluated during program execution.68 Numerical Computation and Bit Operations Chap. but higher than that of assignment. N := N + 1 groups as N := (N + 1) Prefix operations have higher precedence than infix operations. For example. which allows compound comparisons to be written in a natural way. N1 > N2 + 1 groups as N1 > (N2 + 1) while N1 := N2 > 10 groups as N1 := (N2 > 10) Note that this expression assigns the value 10 to N1 if the comparison succeeds.

fieldn) where name is the name of the record and field1. fieldn are the field names associated with the record. Similarly. like procedures. sets.) The declaration for a record with n fields has the form record name(field1. are declared and are global to the entire program. salary) 71 . 6 Structures 71 6 Structures Structures are collections of values. An example of a record declaration is record complex(rpart. Records. Different kinds of structures have different access methods and organizations. Icon has four kinds of structures: records. field2. age. Chap. lists. …. ssn. ipart) Such a record declaration might be used to represent complex numbers with real and imaginary parts. field2. the record declaration record employee(name. RECORDS Records are fixed in size and their values are referenced by field names. (A record declaration cannot appear within a procedure declaration. The syntax of record names and field names is the same as the syntax for identifiers (see Appendix A). and tables. ….

In the other role.5 to the ipart field of origin. ["/". An instance of a record is created by a record constructor function correspond- ing to the record name and with values in positions corresponding to the field oracles := ["Delphi". The first value is a string. origin. social security number. they can be manipulated by stack and queue access functions and hence grow and shrink. In one role. while powers := [i. the value of assigns a list containing three strings and one integer to city. "Arizona". 6 Chap. Lists also can be created by the function LISTS Lists in Icon have two roles. x) that can be subscripted by position.rpart The values in a list may be of any type. ["c"]. they are one-dimensional arrays (vectors) list(i. i ^ 2.5 which adds 2.0. 0. 700000. and so on. "123–45–6789". "c" "d" every !R := 0 assigns 0 to every field of R. ["d"]]] origin.ipart +:= 6. The size of a record is produced by the same operation that is used to get the size of a string. assigns an employee record to clerk.0. "Claros"] names. A list can be created by placing brackets around a list of values. "Heracles". For example.0) in assigns a complex record with zero real and imaginary parts to origin. For example. ∗origin produces 2. "Pima"] example.0. as origin := complex(0. The values can be given by expressions. List Creation and salary are attributes of interest. The tree corresponding to expression can be Records can be referenced (subscripted) by field number or field name. field. For example.0. and "+" origin["rpart"] := 1.00) which assigns a list of four integers to powers.0 assigns a list of three values to expression. The values in a list do not have to be of the same type.0 which sets the rpart of origin to 1. i ^ 4] clerk := employee("John Doe". 6 Structures 73 might be used to represent an employee whose name. 36. while the second and third values are other lists. is 0. Fields of records are referenced by expressions of the form name . Field references are variables. and values can be assigned to the corresponding fields. expression := ["+". 72 Structures Chap. assigns a list of three strings to oracles. as in visualized as: origin[2] +:= 2. in which the first value in the list is associated with the contents of a node and subsequent values represent subtrees. The operation ?R produces a randomly selected "a" "/" reference to a field of R. The operation !R generates the fields of R from first to last. For example. 35000. Therefore. For example. For city := ["Tucson". . Such a list can be used to represent a tree increments the imaginary part of origin by 6. For example. ["a"]. age. i ^ 3.

For of lists. An empty list.0 assigns to vector a list of 100 values. Assignment can be made to !L to change the values of the elements. For example. that is.0 to every element of vector. x) L := list(i) changes the second value in city to 701.74 Structures Chap. but a list of lists can be used to simulate a multi- dimensional array. "Branchidae"] Lists are one dimensional. if the subscript is out of range. 0) # initial zero counts while line := read() do write(oracles[2]) line ? { while tab(upto(&letters)) do { writes Heracles. right(wordlen[i]. ∗vector produces 100. since the subscript is out of range for word lengths greater than 20. x) List subscripting fails if the position specified does not correspond to a value in the list. "Heracles". wordlen := list(MaxLen. each of which is 0. After the A list reference is a variable. ["Delphi". Note that any word that is which may be specified positively or nonpositively. 2). word := tab(many(&letters)) wordlen[∗word] +:= 1 every i := 1 to ∗vector do } write(vector[i]) } writes all the values in the list vector. illustrates a typical use list is produced by the same operation that is used for strings and records. 6 Structures 75 which creates a list of i values. while ∗[ ] produces 0. example. j. longer than 20 characters is not tabulated. Similarly. For example. input has been processed. It can be changed by assignment to its position. the results are written out. is created by [ ] or list(0). the values in a list end can be written without specific reference to positions: For example. every !L := list(j. return L The operation !L generates the elements of L. Note that positions are numbered starting at 1. 6 Chap. 0.0. value is x: city[2] +:= 1000 procedure array(i. For example vector := list(100.0) every !vector := 1. each of which has the value of x. Since positions can be computed in the every i := 1 to ∗wordlen do subscripting expressions. Consequently. $define MaxLen 20 List Referencing procedure main() The values in a list can be referenced (subscripted) by position.000. so that the list becomes fails. which contains no values. 5)) end every write(vector[1 to ∗vector]) The values in wordlen accumulate counts of word lengths from 1 to 20. every write(!vector) . assigns 1. the expression oracles[–1] := "Branchidae" wordlen[∗word] +:= 1 changes the last value of oracles. For example. this loop can be written more compactly as write(right(i. The following procedure constructs an i-by-j array in which each Similarly. The size of a The following program. which tabulates word lengths.

wordlist := [ ] As for other infix operations. List be subscripted so that sections are like substrings. A list reference can itself A list section is a list composed of a sequence of values from another list. Assignment can be made to ?L to change the subscripted value. instead of being a part of it. tab(many(&letters))) } Note that both arguments in list concatenation must be lists. the second value is the second word. the value of written as city[3:5] board[2. 550000.0 If L is a list. while L[i : j] is a list consisting of the values between positions i and j in L. there is an augmented assignment operation for while line := read() do list concatenation operation. For ["Arizona". 8. The function put(L. L[i : j] is a list that is distinct from assigns 2. the first value in the list is the first word. For the value of city given in the preceding references the value in “column” 4 of “row” 2 of board. except that they are new lists that are distinct from the list from which they are obtained. . There is one other important distinction between subscripting lists and strings: ?vector := 2. One use of put() is to build a list whose size cannot be determined when the list is created. the following procedure produces a list of all which assigns a new list words in input: ["Tucson". 4] is the list The operation ?L produces a randomly selected reference to the list L. This expression also can be section. 6 Chap. Since put() adds values at the right end. L[i] refers to the ith value in the list. For example. x) adds the value of x to the right end of the list L. the words in the list are in the order that they appear in input.0 to a randomly selected element of vector. L. as in line ? { while tab(upto(&letters)) do city |||:= [1883] put(wordlist. return wordlist city |||:= 1883 end is erroneous. When the elements of a list are viewed from left to right. 1883] procedure words() to city. much as substrings are produced by range specifications applied to strings. An example is is the left end of a list and L[∗L] or L[–1] is the right end of a list. List sections are board[2][4] produced by range specifications applied to lists. ?L fails. List Concatenation Queue and Stack Access to Lists Lists can be concatenated in a manner similar to the concatenation of strings. "Arizona". "Pima"] example. In particular. 0) List Sections assigns to board an 8-by-8 array in which each value is 0. Queue and stack access functions provide ways to add and remove values The list concatenation operation has three vertical bars to distinguish it from string from the ends of lists. If L is empty. increasing city := city ||| [1883] the size of L by 1. "Pima". L[1] concatenation. 6 Structures 77 board := array(8.76 Structures Chap. and assignment cannot be made to it to change L. An empty list is an identity with respect to list concatenation. That is. and so on.

but fails otherwise. x) and push(L. as a result of For example. The functions put(L. if any(&ucase) then write(word) } end SETS When the execution of this program is complete. evaluated. and so on. The creates a set that contains the distinct elements of the list L. "abc" and 3. x)) The functions put() and push() can have additional trailing arguments to add several values to a list in one call. "source". x) set(L) adds x to the right end of L. get(L). 2. get(L) fails. and 3. put(wordlist. "the". 6 Chap. For example. if the expression set(["abc". put(L. The function pull(L) removes a value from the right end of L. There are several operations on sets. 6 Structures 79 Values are removed from a list by the operation. "an") . The function The functions put() and get() provide a queue access method for lists. normally associated with sets in the mathematical sense. tab(many(&letters))) set([1. x) adds x to the left end of L and pop(L) removes a value from the left end of L. the former element L[1] is L[2]. Sets in Icon have many of the properties of get() removes a value from it. function push(L. 2. "any") letter: "any" is the first element of wordlist. The effects of the queue and stack access function on subscripting while word := get(wlist) do generally are not a problem. in the procedure words() given previously is replaced by Any specific value can occur only once in a set. The four succeeds and produces x if x is a member of the set S. For example. since queue and stack access usually are not used in word ? { combination with positional access. For example. member(S1.78 Structures Chap. the values are pushed empty. For example. so push() and pull() also provide a queue access method. and get(L) removes a value from the left end of L. Each time get(L) is appends these values to wordlist. procedure main() Since the queue and stack access functions add and remove elements from lists. tab(many(&letters))) creates a set with two members. The function Note that get(L) and pop(L) both remove a value from the left end of L. For functions together provide an access method for double-ended queues. the list wlist is empty. x). If L is When push() is used to add values to the left end of a list. For example. For example. 3. Two functions provide a corresponding stack access method for lists. 3]) put(wordlist. or deques. the following program uses the procedure words() to produce a list of words and then writes out only those words that begin with an uppercase push(wordlist. it removes a value from the left end of L and produces this value. succeeds if x is a member of both S1 and S2. x) for queue and stack access methods. an empty set is created. since each call A set is an unordered collection of values. x) produce L. "many". "a". If the argument to set() is omitted. The two names for the same function are provided to accommodate the usual terminology member(S. push(wordlist. example. 3. 1]) the list that is produced has the words in the opposite order from their order in input: creates a set with only three members: 1. the first word in the list is the last one in input. after push(L. wlist := words() they affect subsequent subscripting. member(S2. in the order they are given.

3. 3]) ++ set([2. The value associated with a key can be changed. and difference of S1 and S2. or “subscripts”. and ?S produces a randomly selected member of S. a set containing all the different words in the input file: Several operations that apply to lists also apply to sets. 3. The function Table Creation and Referencing delete(S. x) set([1. except that the keys. Tables resemble lists. 2. For example. but lookup and insertion end are taken care of automatically. Tables are much like return wordset the symbol tables used in compilers and similar software. x) A table is created by the function deletes the member x from the set S and produces S. then The operations words["The"] := 1 S1 ++ S2 assigns the value 1 to the key "The" in words. In each case. respectively. x) and delete(S. Table references are allows their use in loops in which failure may occur for other reasons. There is no automatic type conversion between csets and sets. 6 Chap. variables and are similar to list references in appearance. where a pair consists of a key and a corresponding } value. 2. S1 ∗∗ S2 S1 – – S2 write(words["The"]) create the union. while insert(S. 4]) inserts x into the set S and returns S. tab(many(&letters))) A table is a collection of pairs. 6 Structures 81 The function produces the cset 'abcdeiou'. The operation !S generates procedure diffwords() the members of S but in no predictable order.80 Structures Chap. These pairs are called elements. table(x) The functions insert(S. Augmented assignment is particularly useful for tables. whether or not x is in S. the following procedure produces produces a set that contains 1. The expression 'aeiou' ++ 'abcde' words["The"] +:= 1 . if words is a table created by S := set() while insert(S. For example. read()) words := table(0) builds a set that consists of the (distinct) lines from the input file. For example. need not be integers but can be values of any type. the result of the operation depends on the words["The"] := 2 types of the arguments. writes 1. and 4. ∗S produces the size of S. wordset := set() while line := read() do line ? { TABLES while tab(upto(&letters)) do insert(wordset. For example. Subsequently. intersection. the result is a new set. as in Note that these operations apply both to sets and csets. x) succeed. This where x is the default value for new elements in the table.

For example. Assignment can be made to ?T to change the value of the element. The effect is as if The operation ?T produces a randomly selected reference to the table T. The functions member(). 0) line ? { temp := index while tab(upto(&letters)) do temp[1] := 1 wordcount[tab(many(&letters))] +:= 1 } The assignment of the value of index to temp does not copy the 50 values pointed to return wordcount by the value of index. Consider also ?T +:= 1 cycle := ["x"] put(cycle. Instead. had been evaluated. which is equivalent to T[x] := y. cycle) increments the value of a randomly selected element in T. the following be visualized as follows: expression writes all the keys and their corresponding values in the table T: every x := key(T) do write(x. When a table is first created. inserts an element with key x and value y into table T. and delete() apply to tables as well as sets. Therefore. If x is words["way"] +:= 1 not a key in T. Assign- ment copies the reference (pointer) but not the collection of values to which it points. 6 Structures 83 increments the value associated with "The".82 Structures Chap. it is empty and has a size of zero. y). For example. if a table is used to count values. x. 6 Chap. ":". delete() succeeds in either case. If there already is a key x in T. The function member(T. This can the keys in T. adds "way" to words and increases the size of words by 1. insert(). the following procedure produces a table of the number of times Structures are created during program execution as illustrated by previous ex- each different word occurs in the input file. Therefore. On the other hand. The function delete(T. The operation ∗T produces the size of T (the number of elements in it). Consider while line := read() do index := list(50. procedure countwords() There are several consequences of these properties of structures that may not be wordcount := table(0) immediately obvious. x) succeeds if x is a key in the table T but fails otherwise. x) removes the element with key value x from T. An omitted third argument defaults to the null value. table does not change. An element is added to a table only when an assignment is made to a new key. A structure value is a reference (pointer) to a collection of values. T[x]) . PROPERTIES OF STRUCTURES As illustrated above. if "way" has not been assigned a value in words. no operation is performed. Every time a Testing and Changing Table Elements value is assigned to a new key. The order of generation is not predictable. while key(T) generates These expressions construct a loop in which cycle contains its own value. the assignment of 1 to temp[1] changes the contents of the list that end temp and index share as their value. the expression The function insert(T. a useful default value is 0. The operation !T generates the values of elements in T. For example. Note that it is always possible to get from a key to its corresponding value. If T is index[1] := 1 empty. amples. Note that insert() has three arguments when used with tables but only two when used with produces the default value of 0. ?T fails. but "way" is not added to the table and the size of the sets. the size of the table increases by 1. its corresponding words["way"] value is changed. index and temp both reference the same collection of values.

0)) expression[3. Consequently. 6 Chap. the effect As noted earlier. Similarly. i) lreverse(L) reverse L in the style of reverse(s) –(x. 2. and conversely. 4. and tables. structures: lists. Subscripted subscripts can be used to any to the procedure for constructing two-dimensional arrays that is given earlier in this level as in chapter. the result of an expression such as A subscripting expression can be subscripted as in L1 := L2 := list(i.y. The lists module contains many procedures that operate on lists in a fashion similar to the built-in repertoire of string operations.y) The sets module extends the built-in repertoire with procedures such as seteq(S1. L3) map elements of L1 in the style of map(s1.z Library Resources where y and z are field names. S2) test inclusion of S1 in S2 .y lmap(L1. 1] The remarks above apply to all types of structures.y). L2.z insert(S. S) groups as NOTES (x. 84 Structures Chap. As a result. This is an exception to the general rule that prefix operations have higher precedence than infix operations. The Icon program library contains three modules specifically related to The field reference operation has higher precedence than any other operation. i) replicate L in the style of repl(s. Some examples are –x. as in The field references associate from left to right. including the prefix operations. S := set() x. 6 Structures 85 The tables module provides a variety of procedures such as cycle "x" keylist(T) list of keys in T tbldflt(T) default value for T vallist(T) list of values in T Syntactic Considerations Since assignment does not copy structures. 2] is to assign the same list of five values to each of the three values in L. sets. a set can be a member of (reference) itself. assignment to a position in L2 changes the value of that position in L1. subscripted subscripts can be abbreviated by placing a list of of subscripts in one pair of brackets. For example. s2. Compare this which is equivalent to the example above. S2) test equivalence of S1 and S2 setl(S1. list(5. Subsequently. as in L := list(3. expression[3. s3) groups as lrep(L. 0) expression[3][2] is to assign the same list to both L1 and L2.

Most aspects of expression evaluation are described in Chapter 2 and are illustrated by examples in subsequent chapters. For example. 7 Expression Evaluation 87 7 Expression Evaluation The way that Icon evaluates expressions is one of the most important aspects of the language. arguments are evaluated from left to right. This chapter describes a few more advanced aspects of expression evaluation and explores in more depth the interac- tion between generators and goal-directed evaluation. If these expressions produce results. It gives Icon much of its power and provides many interesting ways of programming that are not available in most other programming languages. Chap. BACKTRACKING Control Backtracking In function calls and operations (as opposed to control structures). the comparison operation is performed. It is easier to follow the order of evaluation if such expressions are written in postfix form with the operator following its argu- ments: 87 . in expr1 < expr2 the order of evaluation is expr1 then expr2.

(x!. g2 is text ? { resumed. Note that it may be advisable to compose expressions in ways if text contains a comma.'))) The left-to-right expression evaluation and last-in/first-out resumption of } suspended generators results in what is called “cross-product evaluation with depth-first search”. despite the conjunction and resulting control backtracking. combinations of values from the generators. For example. and then the expressed very simply.') +1) & write(move(1))) | write(tab(upto('. it is better to use its last character. if g1 does not produce another result. That g1 ← g2 ← last suspended generator is. However. it is (j := (i < find(s))) removed from the chain of suspended generators and g1 is resumed: } g1 ← last suspended generator the assignment of 10 to i is not undone even if i < find(s) fails. Conse- if find(s2) > find(s1) then write("condition satisfied") . the suspension from tab() is resumed and it restores the position to the beginning of the resumption. This is called data backtracking.') + 1) than to use is evaluated in conjunction with write(move(1)). they undo the change they made to the position. the entire expression fails. any subsequent values for find(s2) are also.88 Expression Evaluation Chap. On the other hand. 7 Expression Evaluation 89 (expr1. If they are resumed because of subsequent failure. just as it was when !x produced interfering with another. g1. y!) < values caused by expression evaluation are not undone during control backtrack- ing. since find() produces values position of text up to a period is written (if any). and (3) generation can be limited as shown later. !y is evaluated again. they follows: suspend when they produce a result. and nothing is written. the character after it is written. (2) most situations in which cross- product evaluation is used do not involve large “search spaces” (the problem is written in postfix form. in The arrow from the suspended generator for !y. Of course it is possible for such searches to be very time comparison operation. expr2. If g2 produces another result. If the comparison operation fails. y!) < Data Backtracking Suppose both expressions produce results and suspend. if g2 does not produce a result. This can be depicted as Although the matching functions tab() and move() are not generators. g2. the move(1) fails. they restore the former position in the subject before themselves failing. This allows complex searches to be In this form. evaluation is strictly left to right: expr1. the situation is as it was before and the (i := 10) & comparison is performed again. this becomes rarely seen in practice). ↑ (x!. 7 Chap. while otherwise the initial that take advantage of this form of search. ↑ ↑ Only a few Icon expressions perform data backtracking. Since if find(s1) < find(s2) then write("condition satisfied") tab(upto('. shows the order for resumption. in its first result. For example. For example. y!) < The reason that matching functions perform data backtracking for the position in the subject is so that alternative matches can be specified without the failure of one If g1 produces another result. If text contains only one comma as in order of increasing magnitude. Consider the following example: consuming. Three things diminish this potential problem: (1) the search is done internally and hence more efficiently than if it had to be written at the source- !x < !y language level with loops and local variables. back to the suspended generator for !x. text ? { (tab(upto('. This is not proper Icon syntax and is used here only to help explain the order of Cross-product evaluation of several generators potentially tries all possible evaluation. Most changes in (x!. expr2) < since if a value for find(s1) is less than a value for find(s2).

while expr1 do expr2 Such unlimited backtracking has several undesirable effects. Consequently. Consequently. For example. compound must be kept until program execution terminates. For example. the composition of sequential portions of a sions. If tab() had Expressions are bounded in specific syntactic contexts. in A few consequences of bounding (and the lack of it) deserve attention. …. find(s) is not resumed. If there were no limits on backtracking. Since expr2 and expr3 in if-then-else are not bounded. However. 90 Expression Evaluation Chap. a bounded expression cannot generate a sequence of results. however. For example. expr2. if expr1 fails. <–>. in bounded expressions occur are the natural ones for control flow. it would not be what is meant by if-then-else. and it is restored to the value it had prior to the scanning expression. an assignment expression such as i := 10 does not perform data backtracking. which is like :=: except that if expr1 then expr2 else expr3 the assignments are reversed if it is resumed. suspend expr1 do expr2 resulting in backtracking to previously evaluated portions of the expression. in subject. its effect is irreversible. execution. the not performed data backtracking. in it are discarded. so the alternative tab(upto('. There is.')) starts at the beginning of the subject. When backtracking is not desired. if find(s) then expr1 else expr2 As mentioned earlier. In most cases of sequential execution. find(s) should if i < j then (i to j) else (j to i) not be resumed. expr1 is evaluated. way. a reversible if find(s) produces a result but expr1 fails. The places that form of assignment. If an expression is bounded and produces a result. provided the expression on the line is complete and a new expression begins on the It is therefore impossible to backtrack into a bounded expression. indicated by <– instead of := . This obviously requires space that expressions provide the primary means of avoiding backtracking in sequential in most cases is unneeded. underlined: text ? { (i <– 10) & case expr of { (j := (i < find(s))) expr1 : expr2 } expr3 : expr4 … } the assignment of 10 to i is reversed if i < find(s) fails. While there might be a use for such behavior. exprn } is that there usually are places in a program beyond which backtracking is inappro- priate. Since all Another problem with unlimited backtracking is that suspended generators expressions in a compound expression except the last one are bounded. The most serious { expr1. These are shown below. failure would cause control to backtrack further and until expr1 do expr2 further toward the first expression in a program. when an expression is evaluated it is logically complete and backtracking into it is neither intended nor desired.')) would have inevitably failed. 7 Expression Evaluation 91 quently the alternative tab(upto('. i := find(s1) write(i) j := find(s2) . every expr1 do expr2 There is also a reversible exchange operation. not expr repeat expr BOUNDED EXPRESSIONS return expr Failure within an expression causes the resumption of suspended generators. An example of the usefulness of this is if find(s) produces a result. 7 Chap. Icon handles the problem of limiting backtracking by using bounded expres. the position would have been left at the end of the control expression in if-then-else is bounded. all suspended generators program is facilitated by the fact that semicolons are added at the ends of lines. Put another next line. they can generate sequences of if find(s) then expr1 else expr2 results.

in the expressions produce a result. Otherwise. it sometimes is useful to explicitly limit an expression to a specific number of results. those lines are not complete. If any of the expressions fails. provided both line1 and line2 semicolons are not added at the ends of the first two lines. For example. …. every write(upto(&lcase. expr2. expr2) if tab(upto('. line1). expr2. the mutual-evaluation expression fails. If all the expressions produce results. there is no ambiguity. Note that bounded expressions prevent data backtracking in string scanning by preventing control backtracking. If the value of expr is an integer i. 92 Expression Evaluation Chap. The expression As execution goes from one line to the next. The effect is exactly the same as in a compound conjunction. contain a blank. line2)) i := find(s1). however. provided both line1 and line2 write(i). especially if the expressions are themselves complex. upto(' '. 7 Expression Evaluation 93 is equivalent to i := (upto(' '. but a result Thus. If the value of expr is a function or procedure. line) \ 3) . The value of expr can be negative. assigns to i the position of the first blank in line2. line1). line2)) j := find(s2) assigns to i the position of the first space in line1. the tab() expression is bounded. where the value of expr is the integer i. and the outcome of the expression is the outcome of the call. the limitation control structure. the mutual evaluation expression fails. the result of mutual evaluation example. exprn. denoted by expr \ i (expr1. suspended generators are discarded and backtracking to preceding lines is impossible. This can be done by This notation is cumbersome. the value of i := find(s1) & write(i) & i := 1(upto(' '. regardless of whether or not expr1 and expr2 produce results. is the result of the last expression. For example. exprn just like the evaluation of the arguments in evaluated. If the value of expr is out of range. conjunction can be used to bind several lines together produces the result of expri. expr (expr1. For example. 7 Chap. the function or procedure is called with MUTUAL EVALUATION the arguments. the result is the result of expri. j := find(s2). the mutual-evaluation expres- sion fails. in 3(expr1. exprn) which limits expr to at most i results (the value of i is computed before expr is which evaluates expr1. it is natural to write separate (bounded) expressions on separate lines. provided that all without bounding the expressions. If the mutual success of several expressions is needed. find(s1) is resumed. an exception to the otherwise left-to-right evaluation of expressions). …. in which case the result is selected from right to left in the manner of nonpositive position specifications. tab() is not resumed and the former position is not restored. Consequently. An alternative is mutual evaluation. since the expressions on contain a space.') + 1) then write(move(1)) always fails. …. so that if move() fails. Although mutual evaluation has the same syntax as a function call. For a function call. exprn) On the other hand. as in LIMITING GENERATION expr1 & expr2 & … & exprn While a bounded expression is limited to at most one result. other than the last one is desired. however. Sometimes a number of expressions need to be mutually evaluated. upto(' '. For example. if find(s1) produces a result but find(s2) fails. expr2. conjunction can be com- pounded. For example.

every write(|(0 to 7) \ 128) Consider the following procedure. Since tab() suspended to allow reached. 2. Another example is (–1)(expr1. the sequence for } end |read() The problem in this formulation is that when the procedure is resumed after consists of the lines of the input file. …. –1(expr1. and the while loop continues to the next word. the sequence for |expr suspend tab(many(&letters)) terminates at that point. … . expr2. For example. If the sequence for expr is empty. 1. provide insight and dispel misconceptions. which is intended to generate the words in its argument writes the octal digits 16 times. Note that limitation to one result corresponds to a bounded expression. expr2. The repeated avoid unexpected grouping. upto() produces this same position again. 94 Expression Evaluation Chap. … . 7 Chap. the suspend expression Testing Expressions Interactively can be limited as follows: As mentioned in the Notes section of Chapter 2. 2. for data backtracking. 3. text ? { Furthermore. expr2. care needs to be taken to It sometimes is useful to generate a sequence of results repeatedly. … . but its sequence subse- while tab(upto(&letters)) do quently becomes empty during the evaluation of |expr. This procedure just generates NOTES the first word in text endlessly! In order to prevent the unwanted data backtracking. 1. procedure words(text) An exception to endless generation for repeated alternation occurs if expr fails. exprn) |expr groups as repeatedly generates the sequence of results for expr. This problem can be avoided by using paren- theses: which generates the sequence 1. terminating when the end of the input file is generating one word. Icon’s expression evaluation suspend tab(many(&letters)) \ 1 mechanism is powerful but may be difficult to understand initially. A simple example is –(1(expr1. Such sequences never terminate of their own accord and normally are used in situations where they are not resumed endlessly. 7 Expression Evaluation 95 writes at most the first three positions at which lowercase letters occur in line. but since the position is now back to where it was (at a letter). Syntactic Considerations REPEATED ALTERNATION In using mutual evaluation to select an expression. The while loop continues. suspend resumes its argument. 3. it fails. Running qei (or writing small programs) can In this case. For example. This form of limitation is particularly useful in preventing unwanted backtracking. it is resumed and restores the scanning position to its former value. then the sequence for |expr is empty. . … . exprn) |(1 to 3) which generates the endless sequence 1. exprn)) |1 which probably is not the intention. if expr has a non-empty sequence initially. tab() is not resumed. That is espe- cially true of material in this chapter. For example alternation control structure.

Icon has no block structure. 8 Procedures 97 8 Procedures Procedures contain expressions that are evaluated when the program is run. Both procedures and functions are “first-class” values that can be assigned to variables. Functions are essentially procedures that are built into the Icon system. passed as arguments in procedure calls. which is optional. procedures cannot be placed inside procedures. The arrangement of the expressions in a program into procedures specifies the organi- zation of the program. PROCEDURE DECLARATIONS A procedure declaration has the form procedure name (parameter-list) local-declarations initial-clause procedure-body end The parameter list. Chap. consists of identifiers separated by commas: 97 . Most values are accessed via identifiers. Scope determines the identifiers a procedure can access. and so forth. Icon uses lexical scoping. Functions and procedures are very similar in Icon.

If the previous parameters consume all the arguments. identifier. "e"] and the result returned is "abcde". "d". the list is empty. s2) Identifiers can be made global and accessible to all procedures in a program by local count. for return count example.98 Procedures Chap. "c". This list consists initial expr of the arguments not assigned to previous parameters. it is local to the procedure. procedure exor(s1. The body of the procedure consists of a sequence of expressions. } Global identifiers can be used to share values among procedures. the null value is used for the remaining ones. s2. which have the form count := 0 global identifier-list while line := read() do line ? { Global declarations are on a par with procedure declarations. SCOPE Representative procedure declarations appear in preceding chapters but The identifiers in the parameter list and the identifiers in the local declarations of a without declarations for local identifiers. not global. In this form of … declaration. the parameters have the following values: declarations at the beginning of the procedure declaration. Such identifiers are called dynamic local identifiers. Local declarations have the form s1 "a" s2 "b" local identifier-list rest ["c". If there are not enough arguments for where expr is an expression that is evaluated the first time the procedure is called. } A declaration of a global identifier need not appear before the appearance of the else if find(s2) then count +:= 1 identifier in a procedure. procedures p1() and p2() both must increment the same counter. the last parameter always is a list. which also is optional. Different procedure declarations can have parameters with the same names. "d". end Other identifiers can be declared to be local to a procedure in optional local If called as cat("a". If an identifier that is declared global also if not find(s2) then count +:= 1 appears in a parameter list or local declaration. 8 Procedures 99 identifier. An example is: counter +:= 1 … end . The initial clause. has the form In this form of declaration. parameter still is an empty list. the previous parameters. rest[ ]) result := s1 || s2 These identifiers are local to the procedure and are not accessible elsewhere in the every result ||:= !rest program. … procedure cat(s1. line global declarations. "b". but the last Uses of the initial clause are mentioned later. 8 Chap. Suppose. the arguments are passed to the last parameter in a list. Then the following format could be used: end global counter A procedure can be declared to have a variable number of arguments by procedure p1() appending [ ] to the last (or only) parameter in the parameter list. and they may not if find(s1) then { appear inside procedure declarations. "e"). These expressions are evaluated when the procedure is called. A typical procedure with local declara- procedure are local to calls of that procedure and are accessible only to expressions tions is in the body of that procedure. but parameters with the same names in different procedures have no return result connection with each other.

unnecessary computation can be avoided by making chars a static identifier and The names of record types also are global. a static identifier can provide memory for a procedure. they apply to the entire program and are not affected by scope declara- tions. Record field names are not computing its value only once the first time that alphan() is called: identifiers. there are as many arguments as there are parameters in the end procedure declaration. It is the Note that the value assigned to chars is computed every time alphan() is called. procedure alphan() local line Identifiers that are not declared to be global are local to the procedure in which static chars they occur.". This default scope interpretation saves writing but may lead to errors. This value of the identifier that names the procedure. expr2. can cause an undeclared identifier that otherwise would be local to line ? { be interpreted as global. procedure alphan() exor("Mr. exprn) generates the strings and another that writes them. The procedure itself is a value. 8 Procedures 101 procedure p2() while line := read() do … line ? { counter +:= 1 if tab(upto(chars)) then suspend tab(many(chars)) … } end end A procedure name is a global identifier. It is good practice to declare all local identifiers explicitly. The values of the expressions are chars := &letters ++ &digits assigned to the identifiers in the parameter list (s1 and s2 in this case). For example. Evaluation then starts at the beginning of the body of the procedure for exor(). Procedure Calls Static identifiers are useful when a procedure that is called many times uses a value that must be computed but is always the same. ….") local line. whether or not they are explicitly declared to be local in that procedure.100 Procedures Chap. 8 Chap. For example. An example is: where the value of expr is the procedure to be called and expr1. static identifier-list A static local identifier does not cease to exist when the procedure in which it is PROCEDURE INVOCATION declared returns. "Mrs. Such an identifier retains its value for subsequent calls of that procedure. if tab(upto(chars)) then suspend tab(many(chars)) Variables for dynamic local identifiers come into existence when a procedure } is called and cease to exist when the procedure returns. Consider a program that writes Procedures are invoked by procedure calls. every write(alphan()) Normally. Local identifiers can be made static by using the declaration Keywords have global scope and their values are not affected by procedure calls. which have the form the first string of letters and digits of each line of the input file. …. perhaps unrelated to the procedure containing an undeclared while line := read() do local identifier. Therefore. expr2. they are only accessible end during the duration of the procedure call. . chars is a call of the procedure exor() given previously. exprn are procedure main() expressions that provide the arguments. This program can be adapted to other uses more easily if it is divided into two procedures: one that expr (expr1. initial chars := &letters ++ &digits a global declaration.

the fields of records. "e") assigns the procedure for write to print. local. which is equivalent to return &fail. pointers to aggregates of values. expr2 is evaluated when the suspend. Therefore. Procedures are known and accessed by these global identifiers — their “names”. was made. they may be assigned to variables. In this case. the null value is returned. it can be the value of an expression. and some procedure suspends again. is the function that is applied to s. a procedure plist[2](c. in write(s). passed as arguments. Procedures are expr1 ! expr2 the initial values of global identifiers. For example. The procedure that is applied in a call is just the “zeroth” argument. is equivalent to print := write select("a". In this sense. "d". however. the VARIABLES AND DEREFERENCING procedure call can be resumed to continue evaluation. that since structures in Icon are for each value generated by expr1. it is suspend expr1 do expr2 evaluated before the other arguments. Procedures as Values A procedure or function also can be called with a list or record that contains its arguments. On the other hand. the keywords. If it produces another result. . any. returns from the procedure call in which it occurs. the declared proce- Evaluation of the expression dure value replaces the built-in one. the procedure call fails. "b". An implicit fail expression is provided at the end of the procedure body. returns from the procedure call and produces the value of expr1 but leaves the call in suspension with the values of dynamic local variables intact. Roughly speaking. 8 Procedures 103 Arguments are transmitted by value. the elements of lists ing procedure is resumed. select ! ["a". The term procedure is used here for both declared procedures and built-in procedures. If expr is omitted. the value of write or record containing the arguments. Notice. Consequently. If it is present. s) destruction of all dynamic local identifiers for that call. many] The fail expression. "b". The return and fail expressions cause return from a procedure call and any(c. "c". and static). Therefore. the value of the global identifier where the value of expr1 is the procedure or function to be called and expr2 is a list write is the function that writes strings. expr1 is resumed. Next. The outcome of expr becomes the Although the procedure that is applied in a procedure call usually is produced outcome of the procedure call. several kinds of variables: identifiers (global. a variable is anything to which a value can be assigned. There are The do clause is optional. suspend is very similar to every. there is no call-by-reference or other difference is that suspend causes the procedure in which it occurs to generate a value method of argument transmission. "e"] Since procedures are values. "c". structures are effectively passed by reference.102 Procedures Chap. For example. 8 Chap. which is then inaccessible. s) call that returns by flowing off the end of the procedure body fails. the and tables. If expr fails. and evaluation continues at the place where the call by an identifier. Consequently. as illustrated in previous examples. and print(s) subsequently performs the same Returning from a Procedure operation as write(s). causes a procedure to constructs a list of procedures and return and fail explicitly. "d". and so forth. Similarly. subscripted string-valued variables. A return expression always returns. It is good practice to avoid using names for declared procedures that have the same names as built-in return expr ones. plist := [upto. This form of call is As mentioned earlier. It is important to provide an explicit return expression at the end of such a procedure body unless is equivalent to failure is intended. if a procedure is declared with the name write. functions are built-in procedures.

Other variables — global variables. which then is written. as in local i. This process is called dereferencing. 8 Chap. the variable in the selected clause is not dereferenced and 0 is assigned to i or j. which produces the of line followed by the newly read value. Consequently.expr. The dereferencing operation can be applied to any expression. line := read()) return (if i > j then i else j) In this expression a new value is assigned to line when the second argument. The Fibonacci numbers provide a classic example: can be assigned to it. the value is returned. Consider the following procedure. it is dereferenced only if it is is evaluated. in have been evaluated. largest value in the list L: Argument expressions with such side effects generally should be avoided. For example. f (i) = 1 i = 1. to prevent unexpected results from procedure maxel(L) side effects. occurs implicitly. Derefer- encing. For example. which produces the value of expr. it is not dereferenced and a value themselves. not just one that depending on which has the larger prior value. For example. in return . it is not necessary to know whether or not an If the argument of a return expression is a local variable. the value of maxel(L) := 0 the variable is obtained automatically. max j := 1 write(. line := read()) max := L[1] every i := 2 to ∗L do if max <:= L[i] then j := i NOTES return L[j] Recursive Calls end It is common in mathematics to define functions recursively in terms of Since the result that is returned is a list element.line. 8 Procedures 105 When an expression produces a variable and its value is needed. dereferencing is not done until all arguments which they are declared.L[j] (if i > j then i else j) := 0 the result returned is the value of the list element and an attempt to assign to it is erroneous. Consider procedure max(i. and two copies of the newly read line are written. end line := read() the result returned is the value of i or j. Variables are dereferenced only when a value is needed. The possibility of such an assignment can be prevented by use of the explicit write(line) dereferencing operation . produces a variable. but explicit dereferencing can be used. The first argument is not dereferenced until the value of line is changed local or static. since local variables are accessible only to the procedure in In a function or procedure call. both arguments have the subscripted structures. by the evaluation of the second argument. and subscripted global strings — are returned as variables same value. 2 f (i) = f (i – 1) + f (i – 2) i>2 f (i) undefined otherwise . j. not the variable. At this time. if necessary. like type conversion. it is dereferenced and expression produces a variable in order to apply the dereferencing operation to it. When a variable is returned from a procedure. if the return expression in the previous procedure is changed to the variable line is dereferenced to produce its value. in replaces the maximum value in L by 0.104 Procedures Chap. keywords that are variables. For example. For example. j) write(line. not the former value and may be assigned a value.

static variables can be used in A static identifier can be used to provide the necessary memory. For example. j) = a ( i – 1. 1980). if expr is omitted. fib is a global identifier return i + j whose value is the procedure itself. j > 0 a ( i. 3. Consider the combination with an initial clause to perform a computation only once in order to following reformulation of fib(i): provide a value needed in many calls of the same procedure. One method for avoiding redundant computation in recursive procedures is Static Variables and Initial Clauses to provide a mechanism whereby the values of previous computations are remem- bered (Bird. j ) undefined otherwise returns the null value and expr is never evaluated. if the value In some cases. especially when it depends on the compu- tation of previous values. As shown in an example earlier in this chapter. as in: procedure fib(i) procedure alphan() static fibmem local line local j static chars initial { initial chars := &letters ++ digits fibmem := table(0) … fibmem[1] := fibmem[2] := 1 } if (j := fibmem[i]) > 0 then return j else return fibmem[i] := fib(i – 1) + fib(i – 2) end . A table with default value 0 is assigned to the static identifier fibmem when the procedure is called the first time. Note that 0 is not a possible value in the Fibonacci Since a procedure can call itself. fibmem[i] is greater than zero and is returned. These values then can be looked up instead of being recomputed. procedure fib(i) Note that the computation still is recursive. 5. j = 0 expr a ( i. j ≥ 0 return a ( i. Since expr is optional. Redundant computations often can be avoided by finding an alternative The expr following return is optional. 8 Chap. 8 Procedures 107 The sequence of Fibonacci numbers for i = 1. to compute fib(5).106 Procedures Chap. 2. … . The values for 1 and 2 are placed in this table.1 ) i > 0. The computation of fib(4) also requires the computation of fib(3). 13. else return fib(i – 1) + fib(i – 2) Syntactic Considerations end The precedence of return is lower than that of any infix operation. For example. This is useful in procedures that do not have any other value to return and corresponds to the initial null value of identifiers. so Recursive calls rely on the fact that the identifier for the procedure name is global. the use of recursion groups as for computation can be very inefficient. returned. j – 1)) i > 0. the expression must begin on the same line as the The classic example is Ackermann’s function (Manna. and so on. if the desired scribed mechanically into a procedure that computes the Fibonacci numbers: value has already been computed. While a recursive definition may be elegant and concise. Otherwise the desired value is computed and stored in the table before returning. 2. For example. 1. j ) = a ( i – 1. iterative solutions can be difficult or impractical to formulate. In general. but no value is computed recursively if i = (1 | 2) then return 1 more than once. the null value is iterative solution (see the exercises at the end of this chapter). of an expression is to be returned. j) = j + 1 i = 0. this mathematical definition can be tran- sequence. it is necessary to compute return (i + j) fib(4) and fib(3). a ( i. within the procedure body for fib(). 3. … is 1. 1974): return. 8. a (i.

chars is not assigned a value Co-Expressions and an error results in most situations. the results of an expression can be produced only by iteration or goal-directed evaluation. Since the initial clause is only evaluated on the first call. CO-EXPRESSION OPERATIONS Co-Expression Creation A co-expression is a data object that contains a reference to an expression and an environment for the evaluation of that expression. Instead. there is no mechanism for explicitly resuming an expression to get a result.108 Procedures Chap. Furthermore. A co-expression is created by the control structure create expr The create expression does not evaluate expr. 8 Chap. A co-expression “captures” an expression so that it can be explicitly resumed at any time and place. the results produced by an expression are limited to the place where that expression appears in the program. Co-expressions overcome these limitations. passed as an 109 . the results produced by an expression are strictly constrained. Consequently. as in procedure alphan() local line 9 initial chars := &letters ++ digits … In this case the procedure works correctly the first time it is called. it produces a co-expression that references expr. This co-expression can be assigned to a variable. but in subsequent calls the variable chars. not being static. 9 Co-Expressions 109 A common mistake is to forget the static declaration. is local by default and has the null value. both in location and in the sequence of program evaluation. In normal expression evaluation.

110 Co-Expressions Chap. 9 Chap. 9 Co-Expressions 111

argument to a procedure, returned from a procedure, and in general handled like third := @articles
any other first-class value. A co-expression contains not only a reference to its
argument expression, but also a copy of the dynamic local variables for the assigns "the" to third. If article is activated again, the activation fails because there are
procedure in which the create appears. These copied variables have the same values no more results for the expression that is resumed.
as the corresponding dynamic local variables have at the time the create expression
The activation operation itself produces at most one result, but it fails when all
is evaluated. This frees expr from the place in the program where it appears and
results of the co-expression have been produced. Consequently,
provides it with an environment of its own.
An example is while write(@locs1)

procedure writepos(s1, s2) writes out all the positions at which s1 occurs in the subject and the loop terminates
when find(s1) has no more results and @locs1 fails. Note that this expression
locs1 := create find(s1)
produces the same results as
locs2 := create find(s2)

end every write(find(s1))

Here the values assigned to locs1 and locs2 are co-expressions corresponding to the In general, in the absence of side effects
expressions find(s1) and find(s2), respectively.
Activating Co-Expressions
generates the same results as the expression referenced by C. Activation may occur
Control is transferred to a co-expression by activating it with the operation @C. at any time and place, however, while producing results by iteration is confined to
At this point, execution continues in the expression referenced by C. When this the site at which the expression occurs.
expression produces a result, control is returned to the activating expression and the
An important aspect of activation is that it produces at most one result.
result that is produced becomes the result of the activation expression. For example,
Therefore, the results of a generator can be produced one at a time, where and when
they are needed. For example, the results of generators can be intermingled, as in
articles := create("a" | "an" | "the")
while write(@locs1, " ", @locs2)
which writes the locations of s1 and s2 in the subject, side-by-side in columns. Since
activation fails when there are no more results, the loop terminates when one of the
generators runs out of results.
transfers control to the expression The results produced by a co-expression are dereferenced according to the
same rules that apply to procedures. Specifically, if the result is a local variable in the
"a" | "an" | "the" co-expression, it is dereferenced.

which produces "a" and returns control to the activation expression, which then Refreshing Co-Expressions
writes that result.
Since activation produces a result for a co-expression, it has the side effect of
If the co-expression is activated again, control is transferred to the place in its
changing the “state” of the co-expression, and effectively consumes a result, much
expression where it last produced a result and execution continues there. Thus,
in the way that reading a line of a file consumes that line. Sometimes it is useful to
subsequent to the activation above,
“start a co-expression over”. Although there is no way to reset the state of a co-
expression to its initial value at the time of its creation, the operation ^C produces
second := @articles
a “refreshed” copy of a co-expression C. The term “refresh” is somewhat of a
assigns "an" to second and

112 Co-Expressions Chap. 9 Chap. 9 Co-Expressions 113

misnomer, since it sounds like C is refreshed; in fact, it does not change C, but instead The results produced by successive activations of seq1 are 2, 4, 8, … , while the
produces a new co-expression. Typical usage is results produced by seq2 are 6, 12, 24, … . Then, for

C := ^C seq3 := ^seq1

Number of Values Produced the results produced by seq3 are 2, 4, 8, … , since the initial value of i in seq1 is 1 and
it is not affected by the assignment of 3 to i after seq1 is created — the two variables
The “size” of a co-expression, given by ∗C, is the number of results it has are distinct.
produced. Each successful activation of a co-expression increments its size (which
starts at 0). For example,
if ∗C = 0 then write(@C)
As mentioned earlier, co-expressions are useful in situations in which the produc-
writes a result for C, provided it has not yet produced a result. Of course, @C fails tion of the results of a generator needs to be controlled, instead of occurring
if there are no results at all. Similarly, automatically as the result of goal-directed evaluation or iteration. Since most of the
utility of co-expressions comes from generators, most co-expression applications
while @C depend on the use of generators.
Labels and Tags
writes the number of results for the expression referenced by C. Such usage
obviously is risky, since an expression may have an infinite number of results. In some situations, a sequence of labels or tags is needed. For example, an
assembler may need a source of unique labels for referencing the code it produces,
Co-Expression Environments while a procedure that traverses a graph may need tags to name nodes.
A generator, such as
As mentioned earlier, a co-expression is created with copies of the dynamic
local identifiers for the procedure in which the create expression occurs. These "L" || seq()
copies have the values of the corresponding local variables at the time the create
expression is evaluated. This aspect of co-expression creation has several implica- is a convenient way of formulating a sequence of labels. However, the need for a new
tions. label may occur at different times and places in the program and a single generator
Since every co-expression has its own copies of dynamic local variables, two such as the one above cannot be used. One solution to this problem is to avoid
co-expressions can share a variable only if it is global or static. Failure to recognize generators and use a procedure such as
that every co-expression has its own copy of its local variables can lead to program-
ming mistakes, since the names of the variables in different co-expressions created procedure label()
in the same procedure are the same, making the variables appear to be the same. static i

When a new co-expression is created by ^C, new copies of the dynamic local initial i := 0
variables are made, but with the values they had at the time that C was originally return "L" || (i +:= 1)
created. Consider, for example,
local i
Consequently, every call of label() produces a new label.
i := 1
seq1 := create |(i ∗:= 2) The use of such a procedure gives up much of the power of expression
evaluation in Icon, since it encodes, at the source level, the computation that a
i := 3 generator does internally and automatically. To use a generator, a co-expression
seq2 := create |(i ∗:= 2)

114 Co-Expressions Chap. 9 Chap. 9 Co-Expressions 115

such as 100 64 144 "d"

label := create ("L" || seq()) 251 FB 373 "\xfb"
252 FC 374 "\xfc"
suffices. Here, every evaluation of @label produces a new label. 253 FD 375 "\xfd"
254 FE 376 "\xfe"
Parallel Evaluation 255 FF 377 "\xff"

One of the common paradigms that motivates co-expression usage is the Another example of parallel evaluation occurs when the results produced by
generation of results from generators in parallel. Consider, for example, producing a generator are to be assigned to a sequence of variables. Suppose the first three
a tabulation showing the decimal, hexadecimal, and octal values for all characters, results for find(s) are to be assigned to i, j, and k, respectively. This can be done as
along with their images. The values for each column are easily produced by follows:
loc := create find(s)
0 to 255
every (i | j | k) := @loc
!"0123456789ABCDEF" || !"0123456789ABCDEF"
Of course, if find(s) has fewer than three results, not all of the assignments are made.
(0 to 3) || (0 to 7) || (0 to 7)
In order to produce a tabulation, however, the results of these generators are needed
in parallel. This cannot be done by simple expression evaluation. The solution is to Control structures are provided so that the flow of control during program execu-
create a co-expression for each generator and to activate these co-expressions in tion can be modified depending on the results produced by expressions. In Icon,
parallel: most control structures depend on success or failure. For example, the outcome of

decimal := create (0 to 255) if expr1 then expr2 else expr3
hex := create (!"0123456789ABCDEF" || !"0123456789ABCDEF")
octal := create ((0 to 3) || (0 to 7) || (0 to 7)) depends on whether or not expr1 succeeds or fails.
character := create image(!&cset) Icon’s built-in control structures are designed to handle the situations that
arise most often in programming. There are many possible control structures in
Then an expression such as addition to the ones that Icon provides (parallel evaluation is perhaps the most
while write(right(@decimal, 10), " \t ", right(@hex, 10), " \t ",
right(@octal, 10), " \t ", right(@character, 12)) Co-expressions make it possible to extend Icon’s built-in repertoire of control
structures. Consider a simple example of parallel evaluation:
can be used to produce the tabulation:
procedure parallel(C1, C2)
0 00 000 "\x00" local x
1 01 001 "\x01" repeat {
2 02 002 "\x02" if x := @C1 then suspend x else fail
3 03 003 "\x03" if x := @C2 then suspend x else fail
4 04 004 "\x04" }

97 61 141 "a" end
98 62 142 "b"
99 63 143 "c"

116 Co-Expressions Chap. 9 Chap. 9 Co-Expressions 117

where C1 and C2 are co-expressions. For example, the results for Another example of the use of programmer-defined control structures is a
procedure that generalizes alternation to an arbitrary number of expressions:
parallel(create !&lcase, create !&ucase)
procedure Alt(L) # called as Alt{expr1, expr2, …, exprn}
are "a", "A", "b", "B", … "z", and "Z". In this case, both co-expressions have the same local C
number of results. In general, parallel(C1, C2) terminates when either C1 or C2 runs
every C := !L do
out of results.
suspend |@C
This formulation of parallel evaluation is cumbersome, since the user must
explicitly create co-expressions for each invocation of parallel(). Icon provides a
form of procedure invocation in which arguments are passed as a list of co-
Some operations on sequences of results are more useful if applied in parallel,
expressions. This form of invocation is denoted by braces instead of parentheses, so
rather than on the cross product of results. An example is
procedure Add(L) # called as Add{expr1, expr2}
p{expr1, expr2, …, exprn}
suspend I(@L[1] + @L[2])
is equivalent to
p([create expr1, create expr2, …, create exprn])
String invocation often is useful in programmer-defined control operations. An
example is a procedure that “reduces” a sequence by applying a binary operation to
Thus, p() is called with a single argument, so that an arbitrary number of co-
successive results:
expressions can be given.
Using this facility, parallel evaluation can be formulated as follows: procedure Reduce(L) # called as Reduce{op, expr}
local op, opnds, result
procedure Parallel(L) # called as Parallel{expr1, expr2}
op := @L[1] | fail # get the operator
local x
opnds := L[2] # get the co–expression for the arguments
repeat {
result := @opnds | fail
if x := @L[1] then suspend x else fail
if x := @L[2] then suspend x else fail while result := op(result, @opnds)
return result
For example, the results for Parallel{!&lcase, !&ucase} are "a", "A", "b", "B" … "z", and
For example, the result of Reduce{"+", 1 to 10} is 55.
Another application for programmer-defined control structures is in the
It is easy to extend parallel evaluation to an arbitrary number of arguments:
production of a string representation of a sequence of results:
procedure Parallel(L) # called as Parallel{expr1, expr2, ..., exprn}
$define Limit 10
local x, C
procedure Seqimage(L) # called as Seqimage{expr, i}
local seq, result, i
every C := !L do
if x := @C then suspend x else fail seq := ""
end i := @L[2] | Limit # limit on number of results

5. or returning control to activation 4 of co–expression C1 it implicitly by producing a result. Despite the appearance of dissimilarity between activation 5 of co–expression C2 these two methods for transferring control. expression C2 and a string used for identification. Execution continues in note(). "co–expression C2") C2 := create note(C1. for Built-In Co-Expressions example. Thus. C1 := create note(C2. tag) taking place. there is another call of note(). 6. 9 Chap. "co–expression C1") @&source @C1 “returns” to the activating co-expression. 118 Co-Expressions Chap.. This is illustrated by the use of co-expressions as coroutines. activation 2 of co–expression C2 activation 2 of co–expression C1 Transfer of Control Among Co-Expressions activation 3 of co–expression C2 activation 3 of co–expression C1 As illustrated earlier. 9 Co-Expressions 119 while result := image(@L[1]) do { local i if ∗L[1] > i then { i := 0 seq ||:= ". and activation 1 of co–expression C1 Dahl. and C2 is activated. It writes a line of output and activates C1. the following program: There are three built-in co-expressions that facilitate transfer of control: global C1. .. the procedure note() is called with two arguments: the co- For example. C2 &source. This continues endlessly and neither procedure call ever returns. 3. . As a result. sions is not hierarchical. 4. Consider. the result produced by Seqimage{1 to 8} is "{1. tag) else seq ||:= ". activation 5 of co–expression C1 It is important to understand that transferring control from one co-expression activation 6 of co–expression C2 to another co-expression by either method changes the place in the program where activation 6 of co–expression C1 … execution is taking place and changes the environment in which expressions are evaluated. Dijkstra. and the output produced is Although co-expressions are motivated by the need to control the results produced by generators. a co-expression can transfer control to another co. Unlike procedure calls. A general description of coroutine activation 1 of co–expression C2 programming is beyond the scope of this book. " || result @C } } return "{" || seq[3:0] || "}" | "{}" end end When C1 is activated. procedure main() The value of &source is the co-expression that activated the currently active co- expression. 8}". For example. Control then transfers back and forth between the two procedure calls. see Knuth (1968). end The value of &current is the co-expression in which execution is currently procedure note(C. 2. however. and &main. A line of output is produced. i +:= 1. At this point." break repeat { } write("activation ". control is transferred OTHER FEATURES OF CO-EXPRESSIONS to the first call of note() at the point it activated C2. " of ". and Hoare (1972). they also can be used as coroutines. as in @C. &current. transfer of control among co-expres. 7. they really are symmetric. Marlin (1980). activation 4 of co–expression C2 expression by two means: activating it explicitly.

producing the words from the lines. the most useful coroutine applications generally are quite lengthy”. while line := @lines do line ? while tab(upto(&letters)) do If program execution is taking place in any co-expression. while read() @ words since main() may have called another procedure from which the activation of a co- expression took place. . This co-expression could be used to assure return of control to the co-expression that was current when words := create word() process() was called. Note that this location need not be in the procedure main() itself. This co-expression corresponds to the invocation of the main procedure @writer that initiates program execution. benefit from the organization that coroutines allow. In fact. writer procedure main() passes the current co-expression to the procedure process(). and writing out the words. On subsequent activations. which can be viewed as end @(create main()) procedure word() The co-expression &main is the first co-expression that is created in every program. and writes out these words on separate lines. breaks them up into words. the transmitted result Marlin (1980) remarks “ … the choice of an example program is … difficult … . The becomes the result of the expression that activated the current co-expression. 9 Chap. simple examples of coroutines which illustrate the importance On the first activation of a co-expression. The use of transmission is illustrated by the following program. not as a recommended programming technique. Co-expressions are used to isolate the tasks: reading lines. lines := create reader() writer := create output() The value of &main is the co-expression for the invocation of the main procedure. programming methodology is intended for programming-in-the-large”. since there is nothing in the problem that requires coroutine control flow or the generation of results at arbitrary times or places. end Transmission procedure output() while write(@words) A result can be transmitted to a co-expression when it is activated. Knuth (1968) says “It is rather difficult to find short. which reads in lines from standard input. tab(many(&letters)) @ writer @&main end returns control to the co-expression for the procedure main() at the point it activated procedure reader() a co-expression.120 Co-Expressions Chap. and since there is nothing to receive it. so that every activation actually transmits a result to the co-expression that is being Coroutine programming generally is appropriate only in large programs that activated. the transmitted result is discarded. Transmis- sion is done by the operation @&main end expr @ C Note that output() activates main() to terminate program execution. where C is activated and the result of expr is transmitted to it. lines. @C is just an abbreviation for This example is designed to illustrate transmission. The problem above can be solved more simply by using &null @ C generators and procedure calls. 9 Co-Expressions 121 process(&current) global words. of the idea.

called MT-Icon. record declarations add new “programmer-defined” types. The function type(x) produces the string name of the type of x. For co–expression list set example. Icon has a large repertoire of types. cset null string file procedure table articles := create "a" | "an" | "the" integer real window groups as Files and windows are described in Chapters 11 and 12. 10 Data Types 123 NOTES Library Resources 10 The Icon program library has two modules that contain programmer-defined control operations: pdco procedures for various control operations pdae procedures for programmer-defined argument- evaluation methods Data Types Multi-Thread Icon There is a version of Icon. the value of type("Hello world") is "string". In addition. especially in program debugging. Sometimes it is useful. 1996). 9 Chap. twelve in all: The reserved word create has lower precedence than any operator symbol. to be able to determine the type of a value. Control is passed between programs using co-expression activation. they improve the readability of TYPE DETERMINATION create expressions. Syntactic Considerations As illustrated in the previous chapters. For example. 123 . that supports the execution of several programs in the same execution space. if type(i) == "integer" then write("okay") writes okay if the value of i is an integer. Similarly. This version of Icon also provides instrumentation that allows program activity to be monitored (Griswold and Jeffery. articles := create ("a" | "an" | "the") Although parentheses usually are unnecessary. 122 Co-Expressions Chap. See Jeffery (1993).

then the value of Implicit Type Conversion type(origin) Implicit type conversion occurs in contexts where the type of a value is is "complex". converted to the type expected by the comparison. the value of example. For example. Therefore.5 and "16ra" can be converted to 10. 0. not the string "20" to i. cset integer real string In some situations. Similarly. Note real u u = u that the converted value is assigned to N.500" cannot be converted to integers. but "a1500" and "1. converted to numeric types. When a real number is converted to an integer. For example. 10 Data Types 125 Functions. cset = ? ? u N := +s integer u = ? u is a way of converting a string that looks like a number to an actual number. 10 Chap. Since real numbers are limited in magnitude. different from the type expected by an operation. and strings can be converted to values of other types. Leading and trailing blanks are ignored in strings that are is "procedure". A record declaration adds a type to the built-in repertoire of Icon. . The symbol u indicates a conversion that is always possible.0. the characters are put in lexical order. "1500" can be converted to the integer 1500. line) type in type out the string "aeiou" is automatically converted to a cset. For A string can be converted to a numeric type only if it “looks like a number”. but the value of s remains unchanged. 124 Data Types Chap. For example. integers. For example. For example. have type procedure. which are simply built-in procedures. The = indicates i := (j > "20") that nothing needs to be done to convert a value to its own type. and origin := complex(0. a comparison operation produces the value of its right argument. conversion of &lcase to a string produces "abcdefghijklmnopqrstuvwxyz". real numbers. If a complex record is assigned to origin. implicit conversion can be used to convert a value to a desired type. The possible type conversions are given in the following table. assigns the integer 20. the strings that can be converted the declaration to real numbers are correspondingly limited. For example. depending on the value. it is first converted to a string. adds the type complex. record complex(rpart. as in When a cset is converted to a numeric type. provided the comparison succeeds. while ? indicates a conversion that may or may not be possible. in TYPE CONVERSION write(∗line) Csets. Signs and radix literals are allowed in conversion type(write) of strings to numeric types. For example. "–2. Type conversions take two forms: implicit and explicit. the integer produced by ∗line is converted to a string in order to be written. string u ? ? = Implicit type conversion sometimes can have unexpected effects.0) then string-to-numeric conversion is performed. ipart) When csets are converted to strings. in i := upto("aeiou". any fractional part is discarded in the conversion. no rounding occurs.5" can be converted to –2.

causes program termination with a diagnostic message. but Assignment is indifferent to the null value. is erroneous. except for those for functions and procedures. useful for converting a value that may represent either an integer or a real number. if no value has been assigned to i. An implicit type conversion that cannot be performed is an error and causes program execution to terminate with a diagnostic message. For example. evaluation of the expression Explicit Type Conversion j := i + 10 Explicit conversion is performed by functions whose names correspond to the desired types. For example. Therefore. THE NULL VALUE N +:= "a" The null value is a single. For example. There are two operations that succeed or fail.5") x := &null produces 10. The operation s := string(cset(s)) /x . converts x to a string and assigns that string value to s. 10 Chap. This prevents the accidental use of an uninitialized identifier in a T. For example. Consequently. depending on whether or not an tation that otherwise would be difficult. integer(x). have the null value initially. assigns the null value to x. and real(x). Similarly. since this expression attempts to add 1 to the null value. Most other uses of the null value or for the keys in tables. Where a cset is expected. 10 Data Types 127 Unnecessary type conversion can be a source of inefficiency. words := table() conversion functions are cset(x). The null value. in an expression such as If an explicit type conversion cannot be performed. is also Implicit type conversion is not performed for comparing values in case clauses used to specify default values in many functions. words["The"] +:= 1 numeric("10. unique value of type null. program fails. upto("aeiou") numeric("a") the argument is converted from a string to a cset every time the expression is evaluated. literal or some other cset-valued expression that does not require conversion. this problem can go unnoticed. expression has the null value. Since there is no eliminates duplicate characters of s and puts the remaining characters in lexical direct evidence of implicit type conversion.5") is erroneous. For example.126 Data Types Chap. care should be taken s := string(x) to specify appropriate initial values for structures. produces 10. If this expression occurs in a loop that is evaluated frequently. The function numeric(x) converts strings to their corresponding numeric values if possible. For example. example. the type conversion function fails. This function is creates a table in which the default value is null. usually provided as the result of an omitted argument. Since the null value cannot be used in most computations. The other explicit type. Identifiers. integer("10. For order. it is important to use a cset value without risking program termination. T[1] and T["1"] reference different elements in are erroneous.5. Explicit type conversion therefore can be used to test the convertibility of a execution speed may suffer. computation. Explicit conversion sometimes can be used as a way of performing a compu. For example.

x ~=== y As in all operations. For example. but it fails if x produces the null value. if the value of x is the integer 1. and contents. For other types. succeeds. 0) succeeds if the key "the" in T has been assigned a nonnull value. This operation is useful for determining if a variable has ("ab" || "cd") == ("a" || "bcd") been initialized. but it fails if x has any (1 – 1) = (2 – 2) other value. succeeds. even though they are equivalent in size The control structure not expr produces the null value if expr fails. assignment can be made to the result of such an operation. Therefore. value comparison succeeds if the values are the same. real numbers. /x := 0 There is also a general value-comparison operation assigns 0 to x if x has the null value. 10 Chap. Lists can be equivalent without being identical. 0) COMPARING VALUES vector1 := vector vector === vector1 Five of the twelve built-in data types in Icon — csets. Value comparison is used implicitly in case expressions and table references. as in Unlike string comparison. even though the value is If the argument of one of these operations is a variable and the operation computed in different ways. This means that the comparison succeeds because assignment does not copy structures and the two equivalent values of these types are indistinguishable. computed. succeeds because both arguments have the same value. but it plays an important role in Icon. 0) === list(10. This value is the same. value comparison succeeds only if the values are then identical. in Whether or not two numbers are the same can be determined by a numerical comparison operation. integers. so that Numerical and string comparisons are restricted to specific data types. regardless of how it is computed. \T["the"] list(10. the arguments of these operations can be expressions. this expression fails. . The uniqueness of csets and strings is not a necessary consequence of their inherent properties. The operation The property of uniqueness is natural for numbers and is essential for numeri- \x cal computation. For example. al- though type conversions are performed automatically. while x === y \x := 0 which compares arbitrary values x and y. 10 Data Types 129 succeeds and produces the null value if x has the null value. succeeds and produces the value of x if that value is not the null value. regardless of how they are computed. However. and the null value — have the property of having “unique” values. regardless of how they are arguments have identical values. For example. if a table is created with the null default value. value comparison fails if x and y do not have the same type: No implicit type conversion is performed. Therefore. For the types that have unique T := table() values. otherwise. because the two arguments have the same value. 128 Data Types Chap. strings. For example. fails because the two lists are not identical. the operation produces the variable. there is just one distinguishable integer 0. as well as the converse operation assigns 0 to x if x does not have the null value. For example. in vector := list(10.

copy(x) simply produces the value of x. and records. Therefore. 130 Data Types Chap. (See Notes in T[&lcase] Chapter 5. values in the copy are the same as in the original list (copying is “one level”). .1. the time required to convert a large integer to a string (and hence cset) and the time to convert a string to a large integer are proportional to the reference different values in the table T. It takes about 123 times as long to convert this number to a string as and it does to compute it. Only the list itself is copied. in L1 := [ ] L2 := [L1] L3 := copy(L2) L3[1] === L2[1] the comparison succeeds. Similarly. and records. For lists. but square of the number of digits. For values other than lists. T["abcdefghijklmnopqrstuvwxyz"] Large Integers and Conversion between integers and strings and csets is supported for both native integers and integers too large to represented as native integers. a new copy of x is made. COPYING VALUES Any value can be copied by copy(x). 10 Data Types 131 case x of { "Hello" === copy("Hello") "1": expr … succeeds.) However. T[string(&lcase)] Since writing a large integer requires its conversion to a string. care should be taken not do this unnecessarily. reference the same value. since string values are unique. } the first case clause is not selected. sets. L1. no actual copy is made. sets. tables. since both L2[1] and L3[1] are the same list. This copy is distinct from x. since the types of the values compared are NOTES different. this can be an important consideration. 0) vector === copy(vector) the comparison fails. in vector := list(10. which has 378. as of this writing the largest known prime is 2 1257787 .632 digits. For example. 10 Chap. For example. T["abcdefghijklmnopqrstuvwxyz"] For example. Copying a co-expression does not produce a refreshed copy of it. tables. For very large integers.

This allows a program to use any input and output files without having to incorporate the names of the files in the text of the program. they are the default in case no specific files are given. 11 Input and Output 133 11 Input and Output FILES All reading and writing in earlier examples use standard input and standard output. Chap. standard error output is used for error messages. standard input usually comes from the user’s console and standard output usually is written to this console. These standard files are implicit in reading and writing operations. so that such messages are not mixed up with normal output. In an interactive system. By convention. 133 . Values of type file are used to reference actual files of data that are external to the program. There are three predefined values of type file: &input standard input &output standard output &errout standard error output The values of these keywords cannot be changed. On most systems standard input and standard output can be connected to specific files when the Icon program is run.

open() fails. 11 Chap. s2) opens the file named s1 Since open() may fail for a variety of reasons. These line terminators are discarded by read(f) and are not included in the strings it produces. Some files may be protected to prevent them from being modified.txt for reading and assigns the resulting file to intext. the first standard input is assumed. line terminators separate the lines. If f is omitted. This has the effect of physically complet- "r" open for reading ing output for f. "r" is assumed. be used to terminate a loop in which the read occurs. the sometimes it is necessary to use other files. The function flush(f) flushes any accumulated output for f.txt") modes and pipes are described later in this chapter.txt") The options given in s2 specify how the file is to be used. For example. The omission of the second argument with the subsequent default to "r" is common When there is no more data in a file. Other options are: If several files are used. time a value of type file is created in the program and connected with the actual file that is to be read or written. in which case from specific files or write to specific files. open() fails. How files are named is a property of the operating system under which Icon runs.and lowercase procedure main() letters are equivalent in option specifications. opens the file shaw. For example. it is good practice to close files when they are no longer "b" open for reading and writing (bidirectional) needed. As with read(). If this is not possible (there may be various file is reached. All open files are closed automatically when program execution "c" create and open for writing terminates. With the "p" option. A file that is opened for writing may or may not already exist.txt")) then stop("cannot open shaw. however. The "c" and "a" options have no effect on pipes. The function open(s1. For example. If the file does exist. line terminators are discarded. If it does not exist. new output is appended to the end of the old data. as illustrated in earlier examples. even if it is not expected. while write(read(intext)) If the option is omitted. behaves like a file that is both written and read. The translated and untranslated intext := open("shaw. a The operation !f generates the lines from the file f. A file that has been closed can be opened again. it is good practice to check for according to options given in s2 and produces a value of type file that can be used possible failure. 11 Input and Output 135 While many programs can be written using just standard input and output. although some options are common to all operating systems. some programs must read previous contents of the file are destroyed unless the "a" option is used. end intext := open("shaw. open() fails if an attempt is made to open such The name of a file is specified when it is opened for reading or writing. such as flushing output buffers. This end-of-file condition can practice in Icon programming. the argument is passed to an operating-system shell for execution. Upper. since most operating systems allow only a limited number of files to be open "a" open for writing in append mode at the same time. not a property of Icon itself. .txt") In text files.txt") | stop("cannot open shaw. The intext := open("shaw. Not all operating following program copies shaw. For example.txt") two basic options for opening files are: The function close(f) closes the file f. Some options can be This also can be formulated as used in combination. These options inherently are somewhat dependent on the operating system. terminating when an end of new file with the name s1 is created.134 Input and Output Chap. as is illustrated in earlier examples. A file that is opened for reading must already exist. read() fails. at this a file for writing. "c" is implied. if not(intext := open("shaw. reasons. If a file is opened for writing but not for reading. depending on the environment). if it does not. An example is to reference the named file.txt") | stop("cannot open shaw.txt to standard output: systems support pipes. "t" open in translated mode "u" open in untranslated mode "p" open pipe INPUT The "b" option usually applies to interactive input and output at a terminal that The function read(f) reads the next line from the file referenced by f. and making the file inaccessible for "w" open for writing further input or output.

which simply writes a line consisting of the string s to standard output.txt") | stop("cannot open shaw.cpy: of lines. …. for example. as in is like write(). One line of a write(s1.txt to Sometimes it is useful to be able to read a fixed number of characters instead standard output and also copies it to shaw. it is more efficient to use write() with several arguments than to actually concatenate the strings in the program. is not a string. …. so s becomes a new line at the end The function of the file. xn may have various types. Therefore. The output file can be changed in midstream. is not a file and is not convertible to a string. The function write() automatically appends a line terminator. line terminators are not discarded and they write(line) appear in the string that is read. copies shaw. i) reads a string of i characters. s2. xn) is equivalent to where x1. 11 Input and Output 137 The most general case is every line := !&input do … write(x1. s2. sn. x2. When several strings are for a file copy: written in succession to form a single line. If xi is a file. standard input is assumed. sn) file can be built up using writes() several times.cpy". If outtext := open("shaw. …. In this case the value produced is shorter than i.cpy") f is omitted. a line terminator is appended whenever the file is changed. Similarly. . …. Therefore. i) intext := open("shaw. while line := read() do … it is converted to a string if possible and then written. although the the following program prompts the user for the names of the input and output files concatenation is done on the file. If the ith argument. s2) The function writes s1 to standard error output and s2 to standard output.txt") where f is the file that is read and i specifies how many characters are to be read. &output. end There is no limit to the length of a string that can be produced by read() or reads() except for the amount of memory needed to store it. s1. The } function reads() fails if there are no characters remaining in the file. …. x2. The function while line := read(intext) do { reads(f. 1 is assumed. There is one exception. line) remaining characters are read. xn) If the ith argument. If i is omitted. writes(x1. For example. Therefore. The following program. s2. xn) If there are several string arguments. This is done by procedure main() reads(f. xi. sn are written in sequence and a line terminator is appended to the computer terminal to enter input on the same visual line as the prompt. subsequent output is directed to that file. x2. prompting messages to users of interactive programs can be produced with writes() to allow the user at a then s1. the line consists of the concatenation of s1. A separate line is written to each file. The simplest value is treated like an empty string. If there are not i characters remaining. "w") | stop("cannot open shaw. OUTPUT write(&errout. program execution terminates with a diagnostic message. the null writes a line. write(x1. not in the Icon program. …. …. except that a line terminator is not appended to the end. only the write(outtext. x2. 136 Input and Output Chap. What write() does depends on the types of its arguments. end. case is write() write(s) writes an empty line (a line terminator) to standard output. xi. 11 Chap.

but whether or not it is viewed as consisting of lines. and using a line is read. Standard input. the sequence of characters up to the line terminator is returned and the reads() and writes() with files opened in the untranslated mode. "\n". irrelevant on systems for which the line terminator is the linefeed character. When a file is viewed as text. While this view of text and binary files fits situation applies to opening a file for reading. Note that "u" and "t" options are most situations well. in order to computer systems distinguish between text and binary files. 128 different characters have proved too Binary input and output usually are done using reads() and writes(). "w")) do Notice that except for the characters actually in the file. The characters. writes("specify output file: ") while not(outtext := open(read(). a line is a sequence of characters followed by a line terminator. to these conventions produces the correct results and avoids problems in most cases. lines are terminated by linefeed characters (hex 0A). It is not a physical or logical necessity. line3) last := write("The final value is ". It may be surprising to learn that a single There is no limit to the length of a string that can be written by write() or writes() "\n" works as a line terminator on MS-DOS also. of course. which can be represented literally by "\n". It is worth noting that some input/output systems treat characters other than line terminators in special ways. Consequently. On UNIX and the Amiga. discarded. the file must be opened in untranslated mode. line2. 11 Chap. not all computer systems use the same line terminator. count) writes three lines. On some computer systems. a line terminator is appended usual properties of files. write() and writes() produce the value of their last argument. text characters as being only those in the first half of the character set (that is. As long as line-oriented input/output while write(outtext. the data will be during input and output. lines are terminated by two characters: return/linefeed pairs while not(intext := open(read())) do (hex 0D/hex 0A). respecify: ") 0D). converting (in MS-DOS) the linefeed to a return/line feed pair. TEXT FILES AND BINARY FILES This translation is a property of the mode in which a file is opened. from being for text. on UNIX systems line terminators are linefeed characters. it also is common on ASCII-based systems to think of being careful to use the untranslated mode for binary data. the line terminator is not even composed of characters. and many systems use almost all of the 256 characters reads() prevents line terminators. For example. How a file is opened determines how it is treated character. Using few for modern applications. "\n". corrupted by translation. Other Normally a text file is not opened in untranslated mode. which may occur in binary data. follows from the line terminator is discarded. notably UNIX. However. And. while there is no such structure in binary files. do not differentiate at all between text and binary files. adhering to become part of the file. respecify: ") when reading and writing lines. In addition to writing. Conceptually. while binary files (such as executable programs) have no line structure default translated mode can be given explicitly with the "t" option. end As mentioned previously. since separating line terminators are provided. where line termina- assigns the value of count to last. there is no need to worry about line terminators. However. the important matter is not the characters that a file contains. This translation can be prevented by opening a file Text files are usually thought of as files composed of lines that contain printable in the untranslated mode. In addition. On the Macintosh. regardless of the nature of the line terminator: It is discarded on input and appended on output. When Using read() and write() with files opened in the translated mode. Otherwise. On these systems. a file is simply a sequence of characters. writes() prevents unwanted insertion of line terminators in binary it is thought of as consisting of lines. On MS- writes("specify input file: ") DOS and the Atari ST. Some computer systems. Suppose a pro- gram containing this expression is run on an MS-DOS system. as in open("run. For example. However. those with the high-order bit not set). read(intext)) is done on text files. reads() permits reading a binary file in fixed-sized pieces. in reality the distinction is not that clear. and standard error output are translated. using the "u" option. data. and the same and may contain nonprintable characters. lines are terminated by return characters (hex writes("cannot open input file. . and a file can be opened read or write a binary file on a system for which the line terminator is not the linefeed in either text or binary mode. 11 Input and Output 139 procedure main() Unfortunately.log". system that stands between Icon and the actual file translates line terminators automatically. write(line1. 138 Input and Output Chap. This is because the input/output except for the amount of file space needed for it. tors are pairs (represented literally as "\r\n"). This is another reason for For historical reasons. "uw"). When the line is written. The translated mode is the default. standard output. the effect is the same writes("cannot open output file.

not 0 as it is in some other random-access facilities. 11 Chap. The Icon form of position identification is used. . but not both. in which case if the file existed previously it is still known by its On systems that support pipes. Among possible causes of failure are a file currently open or a very powerful technique for using other programs during the execution of an Icon necessity to copy the file’s contents to rename it. the position of the first character of a file is 1. The function getche() is the same as getch() except that the character is one process to be the input of another process (“piped into it”). the behavior is system-dependent. 140 Input and Output Chap. i defaults to 1. pipes are indicated by the character | between processes. remove(s) fails if it is unsuccessful. "p") of f. which writes exists prior to the renaming. and how Icon’s input and output work with pipes. there are three keyboard functions. Subsequent attempts to open the file fail. lated mode on systems that have multi-character line terminators. how programs work when connected by pipes. As with other positions in Icon. In UNIX commands. read()) The function rename(s1. Opening for reading is the default. The use of pipes in Icon programs. but also the system’s command-line NOTES interpreter (“shell”). a nonpositive value of i can be used to reference a position relative to the end iconfiles := open("ls ∗. which allow the output of played. while write(read(iconfiles)) Random-access input and output may produce peculiar results in the trans- writes out the names of all files that end in . however. A pipe can be opened for reading ("pr") or writing ("pw"). These functions On systems that support pipes. Library Resources KEYBOARD FUNCTIONS The Icon program library module io provides several procedures that may be helpful for matters related to files and reading and writing data. 11 Input and Output 141 PIPES The function getch() waits until a character is entered from the keyboard and then produces the corresponding one-character string. The function where(f) produces the current character position in the file f. Seeking only the positions previously produced by where(f) minimizes this risk. The character is not dis- Some operating systems (notably UNIX) support pipes. requires not only an understanding of the programs that are used. displayed.icn". If the file is open. For example. seek(f. opening command strings as pipes provides a original name. An example of writing to a pipe is OPERATIONS ON FILES listprocs := open("grep procedure". There are two functions related to random-access input and output. The function kbhit() succeeds if a character is available for getch() or getche() but fails otherwise. and grep writes only the ones containing the string in its argument (dat in this example). If a file named s2 pipes the lines from standard input into the command grep procedure. The function seek(f. program. Consequently. s2) causes the file named s1 to be known subse- quently by the name s2. ls | grep dat is a command that pipes the output of ls into grep. On systems that support console input and output. while write(listprocs. s2) fails only those containing the substring "procedure". if unsuccessful. "pw") Files can be removed or renamed during program execution. The file named s1 is effectively removed. unless so that it is created anew. For example. rename(s1. The function remove(s) removes (deletes) the file named s. and the "r" can be omitted. the behavior of remove(s) is system dependent. The program ls writes the names RANDOM-ACCESS INPUT AND OUTPUT of the files in the current directory. assigns a pipe to iconfiles corresponding to the command line above.icn. i) fails if an error occurs. using the open option "p". i) seeks to character i in file f. a command string can be opened as a pipe by allow data in files to be accessed non-sequentially.

and Townsend. These facilities are too extensive to describe in detail here and are the subject of another book (Griswold. and so on. write text. 12 An Overview of Graphics 143 12 An Overview of Graphics Icon provides extensive facilities for creating and manipulating windows. WINDOW OPERATIONS AND ATTRIBUTES A window is a rectangular area of the screen on which a program can draw. accepting input from a mouse. This chapter provides an overview to show the nature of the facilities and indicate what can be done with them. displaying text in a variety of type faces and sizes. Jeffery. forthcoming). and receive input. Chap. A window usually has a frame provided by the graphics system: 143 . drawing various geometric shapes.

A line can be drawn between two points by DrawLine(x1. Windows have many other attributes. The function call Subsequent drawing is done in black. For example. WAttrib("fg=black") Windows can be opened and closed much in the manner of files. the foreground color can be changed to black by Consequently. "bg=light gray") which produces the window Locations in a window are measured in pixels (“picture elements”). Several drawing functions are available. The default foreground and background colors are black and white. Other colors can be specified by using the attributes fg and bg. the upper-left pixel has x-y coordinates (0. respectively.144 An Overview of Graphics Chap.300") DRAWING opens a 400×300 window like the one shown above. and the background color. 12 Chap. in which drawing and text are displayed.299). y2) .300" is an attribute of the window and describes its size. 12 An Overview of Graphics 145 The argument "size=400. y The attributes of a window can be changed after a window is opened by using the function WAttrib(). y1.0 x Any subsequent drawing is done in blue. x2. 300". Two important attributes are the foreground color. as in WOpen("size=500.0) and locations increase to the right (x-direction) and down (y-direction): 0. WOpen("size=400. which initially fills the window. The window shown above is 400 pixels wide and 300 pixels high. "fg=blue". the lower-right pixel in the window shown previously is numbered (399. which are small dots that can be illuminated and colored. In the window coordinate system.

12 An Overview of Graphics 147 where x1 and y1 give the coordinates of the first point and x2 and y2 give the coordinates of the second point. i ∗ YIncr. y. ?Range + Min) The function DrawRectangle(x. For example. y) produces Circles are drawn by DrawCircle(x. The following segment of code draws a sequence of circles with centers and radii chosen at random within a range: $define Width 400 $define Height 400 $define Range 35 $define Min 5 $define Iter 50 WOpen("size=" || Width || ". x. y. 12 Chap. h) draws a rectangle whose upper-left corner is at x and y. For example. r). whose width is w. Width. 299) every y := GridHeight to 299 by GridHeight do DrawLine(0. 0." || Height) every 1 to Iter do DrawCircle(?Width. 499.146 An Overview of Graphics Chap. ?Height. y. Height) produces . and whose height is h. $define GridWidth 20 $define GridHeight 10 every x := GridWidth to 499 by GridWidth do DrawLine(x. where x and y specify the center of the circle and r its radius. A typical result looks like this: $define XIncr 35 $define YIncr 15 $define Width 200 $define Height 100 $define Iter 8 every i := 1 to Iter do DrawRectangle(i ∗ XIncr. w.

polygons. For example. numbered (1. 12 Chap. The upper-left character is graphics system. ?Range + Min) which typically produces . TEXT Note that the portions of circles that fall outside the window are not drawn. FillCircle() draws a circle filled in the foreground color. ?Height.1). Closed figures can be filled with the background color as opposed to being The function WWrite(s) writes to the window. and smooth curves. 12 An Overview of Graphics 149 Other functions are provided for erasing portions of a window and drawing individual points. A variation on the previous example is WWrite(" Hello world") $define Width 500 produces the following result: $define Height 300 $define Range 25 $define Min 9 $define Iter 25 WOpen("size=" || Width || ". Drawing Text is written to a window much in the manner it is written to a file. anything that would be outside is “clipped” by the of text in a window is measured in rows and columns. For example. The position is confined to the window. drawn in outline as in the examples above.148 An Overview of Graphics Chap." || Height) every 1 to Iter do DrawCircle(?Width. ?Range + Min) every 1 to Iter do FillCircle(?Width. ?Height. arcs.

orange. advances the text position to the next line. and so forth. 12 Chap. The characteristics of text are determined by a font. yellow. For the window above. green. red. styles are bold. a size COLOR in pixels. WWrite() produces an “end-of-line” in a manner similar to write() and frame.bold") Helvetica is a “sans-serif” font without ornamentation and is used in this book for program material. purple. 12 An Overview of Graphics 151 Notice that this line is written below the last line and starts at the left edge of the The initial blank in the string written provides space so that the H does not touch the window. and its style characteristics. WWrite(" The subject of fonts is complex") produces where choices enclosed in brackets are optional and hue can be one of black. The font used for the image above is from a typeface called Times in a size of 12. allowing the use of system-dependent names. pink. italic. A single hyphen or space separates each word from its neighbor. blue. One of the advantages of using a window for text is that the size and characteristics of the text can be specified. The syntax of a color name is The font is specified by the font attribute. bold italic. violet.150 An Overview of Graphics Chap. or magenta. The style is plain (known as “roman”). white. "yellowish green". Examples are "brown". as in WAttrib("font=Helvetica. brown.12. Color names that are not recognized by Icon are passed to the graphics system for interpretation. cyan. . Other Colors are named by English phrases using a system loosely based on Berk (1982). gray. which consists of a type face that specifies its general appearance. and "moderate purple–gray".

Pixels are WAttrib("fg=" || ?colors) written a row at a time. and data WOpen("size=" || Width || "._ ~~~~B98788AE~~~~ ~~D865554446A~~~_ ~D856886544339~~ E8579BA9643323A~_ A569DECA7433215E 7569CDB86433211A_ 5579AA9643222108 4456776533221007_ 4444443332210007 4333333222100008_ 533322221100000A 822222111000003D_ D41111100000019~ ~A200000000018E~_ ~~A4000000028E~~ ~~~D9532248B~~~~" every 1 to Iter do DrawImage(?(Width – Margin). $define Width 400 $define Height 300 $define Iter 100 $define Margin 20 WOpen("size=" || Width || ". y. "light greenish blue".152 An Overview of Graphics Chap.palette. The following example uses DrawImage() to draw spheres randomly. left to right. spec) draws an arbitrarily complex figure in a rectangular area by giving a value to each pixel in the area. ?Range + Min) ity. $define Height 300 $define Range 25 Drawing Images $define Min 9 $define Iter 25 DrawImage(x. labeled 0-9 and A-F. ?Height. x and y specify the upper left corner colors := ["dark gray". "orange". sphere) . palette chooses the set of colors to be used. ?Height. The area is always rectangular. every 1 to Iter do { Each character of data corresponds to one pixel in the output image. ?(Height – Margin).data" where width gives the "pale purple". of the area. spec is a string of the form "width. ?Range + Min) the height of the area drawn. Transparent pixels are used for better appearance where the spheres overlap. 12 Chap. the length of the data } must be an integral multiple of the width.g16. The A typical result is palette g16 contains 16 equally spaced shades of “gray” from black to white. top to bottom." || Height) sphere := "16. every 1 to Iter do { The data characters are interpreted in paint-by-number fashion according to WAttrib("fg=" || ?colors) the selected palette. "medium brown". this time with colors. "light brown". The amount of data determines DrawCircle(?Width." || Height) specifies the pixel values. "vivid blue". Spaces and commas can be used as punctuation to aid readabil- FillCircle(?Width. 12 An Overview of Graphics 153 Here is another variation on drawing circles. "black"] width of the area to be drawn. The characters ~ and \377 specify transparent pixels that do not overwrite the } pixels on the canvas when the image is drawn. "light red". which are IMAGES shown in gray here: Icon provides facilities to draw arbitrarily complex images and to read and write $define Width 500 image files.

Con- versely. 1994). The function Event() produces the next event. The inset shows a magnified version of a single sphere. Icon supports GIF. Image Files Any rectangular portion of a window can be saved in an image file. A program can detect the event. 12 An Overview of Graphics 155 The result is shown below.154 An Overview of Graphics Chap.gif") which opens a window using the image file kano. image files can be read into a window. as in WOpen("image=kano.gif. Typing a character or clicking a mouse button with the mouse cursor in the window produces an event. For example. the CompuServe Graphics Interchange Format (Murray and vanRyper. and take different actions depending on the nature of the event. The result is: EVENTS A user of a program displaying a window can provide input to the program in a variety of ways. determine where in the window it occurred. The size of the window is set automatically to the size of the image. Additional image file formats are supported on some platforms. 12 Chap. An image can be loaded into a window when it is opened by using the image attribute with a file name as value. .

} Notice("Unable to find specified resource. The function Notice(s) produces a } dialog with the message s. the position in the window where the event occurred is automatically assigned to the keywords &x and &y. Other functions are provided for common situations. A three-button mouse is standard. These events are represented by keywords: &lpress left mouse press &ldrag left mouse drag &lrelease left mouse release &mpress middle mouse press &mdrag middle mouse drag The dialog remains and the program waits until the user dismisses it by clicking on &mrelease middle mouse release the Okay button. Here is a simple event loop that draws a rectangle whose upper-left corner is the location where a mouse button is pressed and whose lower-right corner is the location where it is released: repeat { case Event() of { &lpress | &mpress | &rpress: { x0 := &x # initial coordinates y0 := &y } &lrelease | &mrelease | &rrelease: { The suggested name is highlighted. Clicking on Cancel tells the program to cancel the request to open a file. select one } of several choices. which alerts the user to a situation such as an error and "b" : break requires the user to acknowledge the notice.drw") &rrelease right mouse release produces the dialog When an event is processed. “drag” is produced.") is an event loop that performs different operations depending on the characters a produces the dialog user types: a "c" produces a random circle. All other events are ignored. 12 An Overview of Graphics 157 repeat { DIALOGS case Event() of { "c" : random_circle() Dialogs are temporary windows that provide information to the user of a program "r" : random_rect() and in which the user can enter information that the program needs. with left. Consequently there are nine possible mouse events in all. &y – y0) on Okay dismisses the dialog and informs the program of the name of the file to break open. } Other forms of dialogs allow the user to enter text in several fields. a third kind of event.156 An Overview of Graphics Chap. For example. "points. A mouse also can be used to produce events. &x – x0. 12 Chap. an "r" a random rectangle. The simplest "q" : stop() dialog is the notice dialog. and a "q" terminates program execution. and select colors interactively. a "b" breaks out of the loop. middle. } . y0. and right buttons that can be pressed and released. such as &rpress right mouse press requesting the user to provide the name of a file to open. turn switches on or off. Clicking DrawRectangle(x0. If the mouse is moved while a button is depressed. &rdrag right mouse drag OpenDialog("Open:". each of which produces an event. The user can edit the name if desired. For example.

• sliders and scroll bars that allow a user to specify a numerical value by moving a “thumb”. including: • multiple windows • automatic redrawing of windows when hidden parts are exposed • hidden windows that do not appear on-screen until needed • textures for filling figures • “mutable” colors that allow all pixels of a given color to be changed to another color instantaneously • graphic contexts that can be shared between windows . This painting program provides an example of a visual interface: OTHER FEATURES Icon provides many other graphics features. Icon provides a program. • menus in which the user can select an item from among several choices. and configuring individual interface tools. positioning. and adding “decoration” such as lines to delineate areas. buttons. VIB (Townsend and Cameron. 158 An Overview of Graphics Chap. Other interface tools are illustrated in the next section. • text-entry fields in which the user can enter information. Interface Tools Icon provides several kinds of interface tools: • buttons with several kinds of functionality and in a variety of styles. identifying information. Building an Interface A visual interface consists of a window containing various interface tools. and sliders makes an application easier to use and more attractive. 12 An Overview of Graphics 159 VISUAL INTERFACES Interaction between a program and a user can be accomplished by mouse and keyboard events and by using dialogs as described in previous sections. A visual interface that organizes interaction using interface tools such as menus. 1996). The dialogs in the last section showed examples of buttons and text-entry fields. providing labels. 12 Chap. for building interfaces interactively: creating. and areas in which the program can display text or images.

13 Other Features 161 NOTES Library Resources 13 The Icon program library contains many procedures related to graphics. list. the function sort(X) produces a list with the values in sorted order. Sorting Records. Like any programming language with an extensive computational repertoire. There also are several programs. The module graphics contains links to all the procedures necessary for running pro- grams that use graphics. Examples are: Other Features binpack bin packing colorbook examining the colors for color names kaleido kaleidoscopic designs travels traveling-salesman problem vib visual interface builder vqueens n-queens problem (see Appendix I) The program gxplor allows graphics facilities to be tested interactively. Icon has several features that do not fit neatly into any category. Lists. ranging from useful applications to visual amusements. 12 Chap. SORTING STRUCTURES The values in a record. Some additional features for debugging are described in Chapter 16. the values are first sorted by type. and some features related to specific platforms are described in Appendix H. list. 160 An Overview of Graphics Chap. or table can be sorted to produce a list with the values in order. or set. set. If the list or set contains various types of values. The order of types in sorting is: the null value integers real numbers strings csets windows files 161 . and Sets If X is a record. These features are described in this chapter.

using the procedure countwords() given is not used for the names of procedures. which produces the function. i) produces a sorted list from the table T. 2) produces the binary multipli- cation operation. office := employee("Joan". suppose personnel records are given by Integers and real numbers are sorted in nondecreasing numerical order. the values are in the sorted order of the keys. For example. these lists are in the sorted order of the keys. values are sorted by time of creation. "coder".0. 4)) tables end record types Note that get() obtains a key first and then its corresponding value. consumed in the process. 3) lists sets while write(left(get(wlist). 12). "programmer". however. Similarly. "∗∗" value in the list is itself a list of two values: a key and its corresponding value. but it is not needed for anything else. while proc("∗". Operators. functions. sort([[ ]. proc("repl") produces the previously: function repl and proc("main") produces the main procedure. The default for i is 1. For example. names using the function proc(s. right(get(wlist). 1 is assumed. If i is 3 or 4. the following program prints a the number of arguments for operators. &letters. the values are in the sorted operator named s but fails if s is not the name of one. As described in Chapter 8. cubicle2. procedure. . office] [2. functions. and record constructors wlist := sort(countwords(). For example. the size of the sorted list is the same as the size of the table. "supervisor".162 Other Features Chap. &letters. 23000) cubicle2 := employee("Melissa". 2. If i is 2. 13 Chap. "bcd". 2. 3. 1. For example. and sets. 3. 35000) produces cubicle3 := employee("John". If i is 4. are values. and operator values can be obtained from their string in the list are alternating keys and corresponding values for the elements in the table. Within sortf(nook. 3) values of one structure type. The form of the result produced and the sorting order depends on the value of i. while record employee(name. produces a list of the records in nook sorted by salary. cubicle3. Operator values are not. "writer". i). lists. functions and procedures have string names. with the oldest first. If i is is the string name of the intersection operator. 'abc'. global identifiers. the lists are in the sorted order procedures. Sorting Tables STRING NAMES The function sort(T. 'bcd'] Then Procedures. If i is omitted. "abc". the size of the sorted list is twice the size of the table and the values Function. 56000) sort(["bcd". Each also have string names that resemble their syntactic appearance. List and record values in X are ordered by comparing the values of their ith [1. The list is For example. "abc".0]) Sorting by Field produces a new list with the values in the following order: The function sortf(X. 25000) nook := [cubicle1. and record constructors sort together by name. procedure. i) is like sort() except that it applies only to records. The value of i is used to specify order of the corresponding values. or If i is 3. salary) strings and csets are sorted in nondecreasing lexical order. like functions and 1. 13 Other Features 163 co-expressions procedure main() procedures. 'bcd']) cubicle1 := employee("Bert". For example. proc("∗". [ ]] fields. available as the values of of the corresponding values. 1) produces the unary size operation. 'abc'. This second argument count of word occurrences in the input file. Operators If i is 1 or 2. job. 2.

that accepts a variable end number of arguments. For example. j)) produces the difference of i1 and i2. Field references and conjunction also are not values and do not have write("∗∗∗ ". i2) write(mult(i. in names. If an attempt is made to call alert() by its string name. and operators can be invoked directly by using their string … names. explicitly referenced. unary operators (which have operator symbols in prefix The string names of prefix operators and infix operators consist of the operator position) are distinguished from binary operators (which have operator symbols in symbols as indicated previously. if the declaration Although some control structures. Procedures can be invoked by their string names in the same way as functions. For a declared procedure with a variable number of argu- ments.) This problem can be avoided by using the invocable declaration. Thus. 3) produces the operator for to-by. i) must be correct for the name of an operator. 13 Other Features 165 Since the value of an operator can be obtained in this way. it can be assigned to a variable. return The function args(p) produces the number of arguments expected by the procedure p. In string invocation. are represented by an infix syntax in the same fashion as operators. These opera- infix position) by the number of arguments given. 164 Other Features Chap. 13 Chap. "alert". args() produces –1 for a function. such as alternation.. since the default However. write(s) . as in "write"(s) invocable "alert" has the same effect as which tells Icon that alert() may be called using string invocation. For deleted. and hence does not prevent the removal of the procedure declaration. like write(). For example. tors and their string names are: operator string name "–"(i) s[i] "[ ]" computes the negative of i. operators can be invoked like procedures by using their string example. s. appears in a program. mult := proc("∗". args() produces the negative of the number of formal parameters. but proc("…") fails. its declaration is deleted. as in STRING INVOCATION messages := ["write". the Icon compiler removes declarations in a program that are not value of the second argument is 1." Procedures The value of i in proc(s. "stop"] Functions. they are not values and do not have procedure alert(s) string names. 2) "–"(i1. For Similarly. messages [2] ("no basis established") Functions and Operators a run-time error results because the procedure declaration for alert() has been A string name of a function can be used in place of the function itself.. writes the product of i and j. For example. s[i:j] "[:]" i to j by k ". proc("…". Some operators have special forms. " ∗∗∗") string names. and the operator can be called like a function or procedure. but there is no other appearance of the variable alert in the program. (The string literal "alert" is not an explicit reference to the procedure alert() example. procedures.

The keyword &collections generates four values: the total The function loadfunc(lib. and block Storage is allocated automatically during program execution as strings and other regions. Appendix F describes how these default settings can be changed.000 bytes. write(&collections) For example. manner. 13 Other Features 167 If several procedures may be called by string invocation. every put(coll. followed by the number caused by allocations returns a procedure. static allocation for co-expressions and operating-system uses All procedures can be declared to be invocable by 2. For example. For most implementations. bitcount := loadfunc("/icon/lib/bits. string. and so forth) invocable all The default initial sizes of Icon’s storage regions vary somewhat from imple- mentation to implementation. using a list to collect its results may be helpful. some of that space may be collectible. it reclaims space used by objects that are no longer in use (Griswold and Griswold. 166 Other Features". and the C functions must write("string: ". strings 3. "shutdown" 1. The first value is the total for all regions. coll[3]) be specifically tailored for use with Icon. writes the total number of garbage collections that have occurred. For these and block regions. The first value is not meaningful and is included This automatic management of storage normally is transparent to persons only for consistency with &regions. blocks for all other data objects (csets. the following procedure writes all the values with identifying labels: produces an Icon procedure bitcount(). and the amount of computer memory available to Icon programs varies from platform to platform. procedure notecol() bitcount(260) local coll coll := [ ] produces 2. The values produced by &storage give the space writing and running Icon programs. the default sizes for the The invocable declaration is needed only for procedures. 13 Chap. write("total: ". DYNAMIC LOADING Four keywords can be used to measure the utilization of storage during program execution. the beginning of program execution. For example. "bitcount") Since &collections is a generator. and block regions. The keyword &storage generates the amount of space currently occupied in the static. However. . not for built-in string and block regions are 500. functions and operators. string. For example. func) loads the C function func from the library lib and number of garbage collections to date. coll[2]) Dynamic loading is not supported on all platforms. &collections) write("static: ". and block regions respectively. their names can be Storage Regions given in a comma-separated list. Garbage collection occurs automatically when more space is of Icon. some understanding The keyword &allocated generates the total amount of space allocated since of how Icon manages storage may be useful. utilization of storage. needed. coll[4]) loading. The subsequent values are for the static. The value for the static region is not meaningful for most implementations objects are created. For more information about dynamic write("block: ". 1986). string. see Griswold and Townsend (1995). coll[1]) return end STORAGE MANAGEMENT The keyword &regions generates the sizes of the static. "warning". string. This procedure can be used to call the function in the usual in the static. Icon programs vary widely in their occupied. as in The storage that Icon allocates is divided into three parts: invocable "alert". lists. if the C function bitcount() counts the number of bits in the binary representation of an integer and is in /icon/lib/bits.

but no region is identified and i2 has no effect. garbage collection occurs automatically when there is Executing Commands not enough space available to satisfy an allocation request. to find out mand given by the string s as if it were entered on the command line.icn") default to zero. changes the directory to the one above the current one. the function system(s) executes the com- Sometimes it is useful to force a garbage collection — for example. such directory or the change cannot be made. depending on the platform and the specific program. The function system() is not Stacks available on all platforms. in conjunction in string scanning. This may happen. overflow detection is less effective in co. which is ample for most programs. The value returned by identified by integers: 1 for the static region. a garbage collection is done. than for the program itself.. default size for created co-expressions usually is 2. In command-line environments. In addition. 13 Other Features 169 Forcing Garbage Collection MISCELLANEOUS FACILITIES As mentioned earlier. unused space is reclaimed in all regions. the The problem with stack overflow often is more severe in co-expressions. An example is expressions. stack may be small and overflow may be a problem. Date and Time adjacent memory may be overwritten. The default size for the main evaluation stack usually is Environment Variables 10.000 words. for example.") expressions. but fails if the environment variable s is not set. If this happens. block region. For example. The function getenv(s) produces the value of the The system stack may overflow if there are too many simultaneously sus- environment variable s. The system stack contains calls of C functions (Icon is implemented in The function chdir(s) changes the current directory to s but fails if there is no C). Both i1 and i2 system("ls –l ∗. Thus. both are much smaller The value of &dateline is the date and time of day in a format that is easy to read. The evaluation stack may overflow in programs with deeply nested (or runaway) procedure calls. The Changing Directories evaluation stack contains intermediate results of computations and procedure call information. The system stack grows as a result of suspended expressions and during garbage collection.000 words. in UNIX The evaluation stack grows as a result of procedure calls and suspended chdir(". 13 Chap. An Icon program uses two stacks: an evaluation stack and a system stack. every co-expression has an evaluation stack and a system stack. getenv() always fails. The function fails if i bytes are not available in the region after with UNIX collection. This facility how much space is available for future allocation. system stack overflow may not be detected.icn. If i1 is 0. When a garbage collection occurs. and contributes to the count of garbage collections. The function collect(i1. resulting in program or system malfunction. write(getenv("TRACE")) The size of the system stack depends on the implementation. For pended expressions. is unlikely. the files whose names end in . with the space divided evenly between an evaluation stack and a system stack. Furthermore. 1996 is "1996/10/12". For example. i2) causes allows an Icon program to execute other programs and in particular to perform a garbage collection. Exit codes vary considerably. The system stack also may overflow if long chains of pointers are encountered during garbage collection. The value of &date for October 12. the system On platforms that do not support environment variables.168 Other Features Chap. lists. 2 for the string region. On a computer with a large amount of memory. in long form. For example. if there are many expressions example. so that collect() performs an “anonymous” collection and always succeeds. and 3 for the system(s) is the exit status returned by the command-line interpreter. See Appendix F for information about changing the size of the evaluation stack. Environment variables communicate information about the environment in which an Icon program executes. On personal computers with a limited amount of memory. The regions are platform-dependent operations that are not part of Icon itself. the system stack usually is very large and overflow prints the value of the environment variable TRACE. requesting i2 bytes of storage in region i1. provided it is set. Unfortunately. The value of &date is the current date in the form yyyy/mm/dd. .

cs. datetime procedures related to date and time Icon Identification sort enhanced sorting The value of &host identifies the computer on which Icon is running. xn) writes output in the manner of write() and then terminates program execution with an error exit code. An example is jupiter. If i is omitted. The most commonly needed ones are: The function delay(i) delays program execution for i milliseconds. programmer-specified termination. This produces a normal exit code for the process whether the main procedure returns or fails. or error. 1996 Program Termination The execution of an Icon program may be terminated for several reasons: completion. 13 Chap. scribed in this chapter. The format of the information varies from implementation to implementation. October 12. The value of &time is the elapsed CPU time in milliseconds. the normal exit code is produced. measured from the The Icon program library contains several modules related to features de- beginning of program execution. . The function stop(x1. For example. The normal way to terminate program execution is by return from the main procedure. Output is written to standard error output unless another file is specified. …. x2. is The value of &version is the version number and creation date of the Icon implementation.170 Other Features Chap.arizona.3. An example is Icon Version 9. the Library Resources value of &clock for 7:21 p.m. This function is useful for terminating program execution in situations where it is not convenient to return to the main procedure. 1996 7:21 am NOTES The value of &clock is the current time in the form hh:mm:ss. Execution of the function exit(i) causes an Icon program to terminate with exit code of i. October 15. 13 Other Features 171 Saturday.

as in hello. The Icon com- piler translates Icon programs into assembly language for the virtual machine and then converts the assembly language into virtual machine code. How Icon programs are run necessarily varies from platform to platform. Even for this environment. Compiling and running Icon programs is easy and it is not necessary to understand Icon’s virtual machine. 14 Running an Icon Program 173 14 Running an Icon Program The implementation of Icon is based on the concept of a virtual machine — an imaginary computer that executes instructions for Icon programs. Chap. it is run interactively through a visual interface. 173 . More information is found in subsequent chapters and the appendices.icn suffix is used by the Icon compiler to distinguish Icon source programs from other kinds of files. but knowing the nature of the implementation may help answer questions about what is going on in some situations. On others. On some platforms. the user manual for a specific platform is the best guide to running Icon.icn. BASICS The name of a file that contains an Icon source program must end with the suffix . This chapter describes the rudiments of running Icon programs. In any event. Icon is run from the command line. details depend on the platform. This implemen- tation method allows Icon to run on many different computer platforms.icn. The . This virtual ma- chine code is then “executed” on a real computer by an interpreter. This chapter describes how Icon is run in a command-line environment.

174 Running an Icon Program Chap.out as standard output.icn. Standard input typically is read from the keyboard.icn is assumed if none is given. The name of the icode file depends on the COMMAND-LINE ARGUMENTS platform on which Icon is run. icont args args Hello world icont hello –x writes compiles and executes hello. the console. Hello There are command-line options for icont. 14 Chap. Options must appear before file world names on the icont command line. most input and output is done using standard ENVIRONMENT VARIABLES input. the suffix is . For example. but without the suffix. 14 Running an Icon Program 175 The Icon compiler usually is named icont. The treatment of special characters.dat > hello. and standard error output.icn hello < hello. the name is the same as the name of the source file. To compile hello.icn. For example. as (The directions that the angular brackets point relative to the program name are suggestive of the direction of data flow. executing Icon program in the form of a list of strings.) icont hello The result is an executable icode file.exe. methods of embedding blanks in arguments. as in icont –s hello icont args –x Hello world suppresses informative messages that icont ordinarily produces. On these platforms. the icode file has the suffix . An Icon program can be compiled and run in a single step using the –x option following the program name.exe. procedure main(arguments) After compilation.icn replaced by . INPUT AND OUTPUT REDIRECTION In a command-line environment. This list is the argument to the such as MS-DOS. This program simply prints the arguments on the command line with which it executed. For example. the environment variable IPATH can be used to specify the location of library modules. For example. If graphics is in . When –x is used. while standard output and standard error output are written to Environment variables can be used to configure Icon and specify the location of files.dat as standard input and hello.cmd and so on. Thus. all that is Standard input and standard output can be redirected so that files can be used needed is in place of the keyboard. On some platforms. An icode file also is created. the arguments follow it. varies from platform to platform. so that this can be written more simply executes hello with hello. notably UNIX. as in hello. Other command- line options are described in Chapter 15 and Appendix E. Arguments are separated by blanks. and it can be executed subsequently without recompiling the source program. main procedure. the Arguments on the command line following an icode file name are available to the compilation of hello. suppose args.icn consists of For MicroSoft Windows.out The suffix . On other platforms. icont hello. and so forth.icn produces an icode file named hello. entering every write(!arguments) hello end runs the program. For example. standard output.

a factor of 2 or 3 is typical. getting programs into execution quickly. then 15 link graphics will find it. of course. 15 Libraries 177 /usr/icon/ipl/gprogs and IPATH has that value. compiler for the platform on which it is run. are specific to a particular program. User manuals are included with distributions link graphics of Icon. A module may contain one procedure or many. Other than those compiled for Icon’s virtual machine. If the location of a library module is known. it is necessary to know which ones are contained in a module or. See Appendix F for a listing of the environment variables Icon uses. the contents of machine. 176 Running an Icon Program Chap. what module contains the procedures required. the optimizing compiler is recommended only for short programs where execution speed is the paramount concern. See Appendix J. In addition to longer compilation time than the compiler for Icon’s virtual This chapter describes procedure libraries: how to use them. its complete path can be specified. 14 Chap. that produces native code for platforms on which it runs. USING PROCEDURE LIBRARIES User Manuals Procedure libraries are files that are prepared for linking with programs. conversely. Libraries NOTES The Icon Optimizing Compiler The compiler for the Icon virtual machine is fast. and how to create your own. They also are available on-line. Programs compiled for Icon’s virtual machine run fast enough for most purposes. the optimizing compiler requires a large amount of memory and a C some existing libraries. Walker (1991) and Griswold (1996). In order to link the procedures needed. A library module is added to a program by a link declaration such as The best source of information for running Icon on a particular platform is the user manual for Icon for that platform. procedures can be used in many programs. In the case of graphics. For these reasons. as shown in the chapter on Icon’s graphics facilities. it is enough to know that the module contains all the procedures needed to extend the built-in graphics repertoire. as in link "/usr/icon/ipl/gprocs/graphics" 177 . Programs compiled Procedures provide the primary method of extending Icon’s built-in computational by the optimizing compiler take much longer to get into execution but run faster repertoire. Many procedures. There also is an optimizing compiler for Icon.

The following two procedures illustrate how library procedures can make programming easier. For example. bound is set to "10. This is the main way in which information is passed to a program that is run from the command line. and points is set to "1000". sort sorting procedures strings string manipulation procedures Organization of the Icon Program Library tables table manipulation procedures The main directories in the Icon program library hierarchy are: Other Useful Procedures Among all the procedures in the Icon program library. The core modules for the basic part of the library are: The path to use for linking also can be specified by the environment variable convert type conversion and formatting procedures IPATH as described in the last chapter. one string basic graphics for each argument. The directories packs and gpacks contain plot lemniscate 10. The directories progs and plot is called as and gprogs contain complete programs. The initial character g indicates graphics material. documenta. if a program named plot begins with procedure main(args) shape := args[1] As indicated. points := args[3] … The source code for procedure modules is in the directories procs and gprocs. sets set manipulation procedures See Appendix J for instructions about obtaining the library.15 Chap. and in these there Of course. New material is added frequently and existing material is scan scanning procedures improved. 178 Libraries Chap.0 1000 large packages. procedures. shape is set to "lemniscate" . data. and provide defaults for omitted arguments. The directories procs and gprocs contain hundreds of files. The code for these procedures is given in Appendix I. there are a few that are particularly useful. procedures. VIB. As one might expect. command-line arguments can be used in any way one likes. A more sophisticated program might issue an error message for an inappropriate value. arguments are passed to the main procedure in the form of a list of strings. respectively. the hierarchy has two main parts: basic material and graphics bound := args[2] material. For example. What is described here is a snapshot as of the time this book was written. is in a subdirectory of gpacks. random procedures related to random numbers tion. the source code for graphics is in gprocs. . Core Modules convert the second and third arguments to real and integer. The use are thousands of procedures. data docs packs procs progs gdata gdocs gpacks gprocs gprogs Command-Line Options As described in Chapter 14. 15 Libraries 179 Note that quotation marks must enclose specifications that do not have the syntax applications. The use of IPATH is preferred for program datetime date and time procedures portability factors procedures related to factoring and prime numbers io procedures related to input and output lists list manipulation procedures THE ICON PROGRAM LIBRARY math procedures for mathematical computation numbers procedures for numerical computation and formatting The Icon program library is a large collection of programs. when Icon is run from the command line.0". Others provide commonly used facilities and are designated as “core” of identifiers. and support tools that is available to all Icon programmers. the visual interface builder. The library is records procedures to manipulate records constantly changing. Some procedures are useful only for specialized above has the disadvantages that the arguments must be in a fixed order and there is only a hint in a call of what they mean.

procedure main(args) leaving anything else for subsequent processing by the program.15 Chap. the options can carry identification and be given in any order. 15 Libraries 181 The standard format that is used by the Icon program library identifies options Here. leaving the shape := opt_tbl["s"] remaining values in the argument list. "s:b. this might take the form Using options(). Many other features are supported by options(). the command-line option –t turns on tracing in plot. An example is • If a command-line argument begins with an @. "–shape:–bound. opt_tbl := options(args. as in then might be called as link options plot –s lemniscate –b 10. however — the procedure options() in the Icon program points := \opt_tbl["p"] | 100 library takes care of almost everything. bound := \opt_tbl["b"] | 1. The most important ones are: If an option appears on the command line. the subsequent string is taken to be the name of a file that contains options. They must be preceded in the values are deleted from args. It returns a table with the option names as keys and with corresponding values from the command line. The program plot A test for a table value being null can be used to set defaults. opts) processes command-line options in the list args according … to the specifications given in the string opts. If such an option is given on the command line. "s:b. The flag ":" indicates the option value must be a string.180 Libraries Chap. leaving any remaining positional arguments for the option string by a – to distinguish them from single-character option names.0 –points 1000 number. the program plot might start as follows: link options link options procedure main(args) procedure main(args) opt_tbl := options(args. one per line. it is the null value. "s:b. The options and Multi-character option names are supported. bound := opt_tbl["b"] points := opt_tbl["p"] • options() normally terminates with a run-time error if an option value if \opt_tbl["t"] then &trace := –1 cannot be converted to the specified type or if there is an unrecognized … option on the command line. if \opt_tbl["t"] then &trace := –1 options(args. if any. Otherwise. and "+" indicates an integer. otherwise it is null.0 shape := opt_tbl["s"] points := opt_tbl["points"] | 100 bound := opt_tbl["b"] if \opt_tbl["t"] then &trace := –1 points := opt_tbl["p"] … … where a command-line call might be The option string consists of letters for the option names followed by a type flag. program to process.0 –p 1000 procedure main(args) In this form.0 That is not necessary.–points+–trace") shape := opt_tbl["shape"] | "circle" opt_tbl := options(args." indicates a real plot –shape lemniscate –bound 10. line. .p+") bound := opt_tbl["bound"] | 1. ". no type • Blanks between single-character option names and the corresponding flag is specified. An option that does not take a value also can be specified.p+t") shape := \opt_tbl["s"] | "circle" It is not difficult to write a preamble to a program to handle named options. its value in the table values are optional on the command line. link options • options() removes option names and their values from the argument list. opt_tbl := options(args. In this case. with a prefix – and follows the name by a value. by name. returned by options() is 1 (and hence nonnull). its value in the table is the result of • Options can appear in any order in the options string and on the command converting to the specified type.p+t") • The special argument – – terminates option processing. For the example above.

Only the elements argument apply apply a list of functions to an argument that are different from the predominant element are shown below the structure.182 Libraries Chap. x2.&null) source["filter"] := filter L2[3] := L1 L1[2] := L1 For this. For arithmetic complex perform complex arithmetic example. it shows L1[1] := L2 := list(2) that structure and so on.&null) link ximage L2[3] := L1 L1[2] := L1 Finding Procedures T1["filter"] := L2 Various listings and cross-references exist to help locate procedures in the Icon Several things about this output are worth noting. and if an element is itself a structure. most of the elements of … basis (L1) are 0. pointer loops present no problem. . …. For example. L1[1] := L2 := list(10. A section a name (tag). L1 := list(1) it shows the structure and its elements. File listings provide brief summaries of each library file. The result produced by ximage() resembles Icon code and L2[1] := L1 hence is easy for Icon programmers to understand. The argument pdae programmer-defined argument evaluation result is a compact but easily understood representation of structures. node2) To include options() in a program. The value of each structure is shown in the style of assignment as a structure-creation function with its predominant element. there is a procedure xdump(x1. …. xn) that applies It is easier to show what ximage() produces than it is to describe it. Suppose a ximage() to x1. source := table() xdump("The basis:".15 Chap. with the number following of a listing for procs looks like this: producing a unique identification. while most of the elements of filter (L2) are null. The first letter of the tag indicates its type. 15 Libraries 183 • If a third procedure-valued argument is supplied in a call of options(). node1) put(node2. the output is nicely formatted. For example. In addition to ximage(). x2. basis) basis := list(6. that node1 := [ ] procedure is called in case of an error instead of terminating execution node2 := [ ] . Indentation and newlines are L2[2] := L2 provided. put(node1.0) source["basis"] := basis L1[1] := L2 := list(10. write(ximage(source)) produces: to standard error output. so that if the result of ximage() is written.0) To include ximage() and xdump() in a program. node2) link options write(ximage(node1)) Structure Images produces The procedure ximage(x) produces a string that describes x. arguments reduce perform operation on list of arguments arguments sortff sortf with multiple field arguments Since every structure has a unique tag. T1 := table(&null) T1["basis"] := L1 := list(6. 0) filter := list(10) writes basis[1] := filter basis[2] := basis "The basis:" filter[3] := basis L1 := list(6. xn in succession and writes the results to standard error program contains the following lines of code: output. If x is a structure. put(node2. One is that each structure is given program library. keyword file description A table is shown with its default value.

A variety of indexes are available in addition to the ones described combinations lists:lcomb list combinations in this chapter. To prepare a procedure or collection of procedures called. it is conventional to base gettext gettext (simple text-base routines) refer to them as if they were a single file. combinations strings:comb character combinations … As an exercise in using the library.icn contains the desired procedures. each file itself contains detailed documentation about the procedures tion about the library.15 Chap.u1 and mylibe. mylibe.u1 and .u2. (Since the names are paired. it always looks in the current directory first. 15 Libraries 185 arithmetic rational arithmetic on rational numbers arrange colmize arrange data into columns icont –c mylibe array progary place program in a array arrays array n-dimensional arrays where mylibe. (Files for library modules normally do not contain a main atomic tclass classify values as atomic or composite backslash slshupto upto() with backslash escaping procedure that is necessary to make an executable program. A section of the index for procs looks like this: NOTES keyword file:procedure description … character strings:charcnt character count Library Path Searching character strings:comb character combinations character strings:compress character compression On most platforms the environment variable IPATH is a blank-separated list characters strings:csort lexically ordered characters of paths. the paths in IPATH are searched from left chars adjuncts:Strip remove chars from string to right. CREATING NEW LIBRARY MODULES It is easy to create a new library module. This pair base basename produce base name of file of files is called a library module. all that is needed is: . look in the progs directory for programs that can help: ibrow for browsing the library and ipldoc for printing summary informa- Finally.184 Libraries Chap. for example. these would be mylibe. such as characters strings:deletec delete characters characters strings:diffcnt number of different characters /usr/icon/ipl/procs /usr/icon/ipl/gprocs characters strings:ochars first appearance unique characters characters strings:replc replicate characters characters strings:schars lexical unique characters When Icon searches for the location of a library file specified in a link characters strings:selectp select characters declaration. The –c option tells the Icon ascii asciinam ASCII name of unprintable character compiler to stop after translating the file instead of going on to link it to make an ascii ebcdic convert between ASCII and EBCDIC executable program.) backslashes slashbal balanced scanning with backslashes The result of using the –c option is to produce two “ucode” files with suffixes balanced slashbal balanced scanning with backslashes . closure genrfncs:starseq closure sequence closure graphpak:closure transitive closure of graph More on Finding Things in the Library code evtmap:evtmap map event code name to event value coefficient math:binocoef binomial coefficient Using World Wide Web is by far the easiest way to locate things in the Icon collation strings:collate string collation program library. regardless of the value of characters strings:transpose transpose characters IPATH. mylibe can be linked in a program using link mylibe Procedure indexes provide information about specific procedures and the files in which they are located. In the example above. If the library file is not found there. See Appendix J for information about Icon on the Web. in it.) based ansi ANSI-based terminal control … Once the ucode files are created.u2.

linking is not performed. Errors During Compilation Syntactic errors in an Icon source program are detected during compilation. Each such error produces an explanatory message and the location at which the error was detected. 16 Errors and Diagnostic Facilities 187 16 Errors and Diagnostic Facilities Errors are an inevitable by-product of programming. Some of the features described in this chapter have applications other than debugging. linking. They are included here because they usually are used for diagnostic purposes. Since some errors cannot be detected until after the point at which the actual error occurred. as well as program malfunctions that Icon doesn’t detect. previous portions of the program should be examined if the problem at the specified location is not obvious. An error in compi- lation or linking prevents the production of an executable program. If an error is detected during compilation. ERRORS Errors may be detected during compilation. This chapter describes errors that are detected by Icon and the diagnostic facilities that can be used in detecting such errors. Chap. encounter errors during execution. A program that compiles and links may. of course. 187 . or program execution.

References to &errorvalue fail if there When a run-time error occurs. 101). a diagnostic message is produced with an error is no offending value associated with the error. Since some kinds of errors cause a cascade of apparent errors in subsequent program text. which could be procedure main() used to process potential run-time errors: i := max("a". The function errorclear() removes the indication of the last error. there may be the expression simply would have failed. &errornumber) procedure max(i. a traceback of procedure calls is given.1) from line 3 in max. but ucode ERROR CONVERSION files are not produced. by the offending expression. If the value of &error is zero (its initial value). For example.icn. rather than causing attempt to compile the program again. errors are treated as failure of expression evaluation and &error is decremented. followed A reference to any of these keywords fails if there has not been an error. errors cause program termination Errors During Linking as shown above. one source file are combined to form a single icode file. If the value of &error is nonzero.icn: references to the keywords above fail until another error occurs. a brief explanation. suppose the following program is contained in the file max. the value of &error is decremented and inconsistent redeclaration the values of three other keywords are set: This error prevents the production of an icode file. j) write(&errortext) if i > j then i else j write("offending value: ". • &errornumber is the number of the error (for example. "integer expected").icn write(s) | ErrorCheck() {"a" > 1} from line 9 in max. image(&errorvalue)) writes("\nDo you want to continue? (n)") end if map(read()) == ("y" | "yes") then return The execution of this program produces the following output: else exit(&errornumber) end Run–time error 102 File max. For example. and. numeric expected offending value: "a" &error := –1 Traceback: main() … max("a". number. two declarations for a procedure or a procedure declaration and a record declaration with the same name. and errors during program initialization. the offending value. Next. Such errors are detected by the linker and result in the error There are a few errors that cannot be converted to failure: arithmetic overflow message and underflow. termination of program execution. where in the program the error occurred. 1) procedure ErrorCheck() end write("\nRun-time error ".icn could be used to check for an error during writing. 16 Errors and Diagnostic Facilities 189 Compilation continues following the detection of a syntax error. When an error is converted to failure.188 Errors and Diagnostic Facilities Chap. if the value of &error Inconsistent declarations may not be evident until ucode files from more than had been nonzero when the expression i > j was executed in the previous example. Subsequent For example. stack overflow. while . • &errorvalue is the offending value. 16 Chap. Error conversion is illustrated by the following procedure. Line 9 For example. when possible. Run-Time Errors • &errortext is the error message (for example. it often is advisable to correct only the first error and Most run-time errors can be converted to expression failure.

4. write(image('Hello world')) A run-time error can be forced by the function runerr(i. For example. no offending value is printed. On the other hand. sets. For error text is printed. could be used to detect failure to sort a table into a list (for lack of adequate storage). This increases with each newly created list. For example. 190 Errors and Diagnostic Facilities Chap. 9. and each record type have number is not used by Icon itself. or window but fails otherwise.7 –150 image(complex) 2.0)) as the nearest power of 10. The value of x is given as the example. if necessary. such as the integer 1 and the string "1". Error number. otherwise no error text is printed. 0. write(image("Hello world")) . co- expression. 16 Errors and Diagnostic Facilities 191 (L := sort(T. while same. For example. produces a result such as "record complex_5(2)". but this is not helpful if the actual value is of interest. For example. separate serial-number sequences. The function image(x) provides a string representation of x for all types. If i is the number of a standard run-time error. program execution to terminate with error number i as if a corresponding run-time error had occurred. STRING IMAGES Although functions and procedures have the same type ("procedure"). The function serial(x) produces the serial number of x if x is a structure. values of record types Note that the image of real numbers may be in a different form from their literal have the same kind of string images that other structures have: representation in a program. Its image(main) value can be written. current size. The number after the underscore is the serial defined errors that are well outside the range of numbers used by Icon itself. It is advisable to use error numbers for programmer- produces a result such as "list_10(4)". although there is no way to differentiate among types whose written values are the produces "procedure main". tables. Integer values on the order of 1030 and larger are given in an approximate form image(complex(0. image(x) produces its string image with surrounding quotes and escape sequences. Its type can be determined by type(x). image([1. which starts at 1 for the first list created during program execution and number 500 has the predefined text "program malfunction" for use with runerr(). they are distinguished in string images. image(trim) If x is numeric. and 10. When debugging a program it often is useful to know what a value is. and a serial number are given for structures. 3)) | ErrorCheck() writes "Hello world" (with the quotes).37e+20 produces "record constructor complex". 16 Chap. If x is omitted. as for string and cset literals.0. provided it is of a type that can be converted to a string. image(126 ^ 137) produces "~10^288". image(x) produces a string showing that numerical value.37E20)) In the case of a record declaration such as writes record complex(rpart. 16]) This function makes it possible for library procedures to terminate in the same fashion as built-in operations. A call of runerr() is subject to conversion to failure like any other run-time error.7 | –150 | 2. Lists. If x is a string or cset. every write(image(30 | 10. Note that the characters in the image of a cset are in lexical order. ipart) 30 the record constructor is distinguished from functions. produces "function trim". offending value. the corresponding The data type. x). which causes writes ' Hdelorw'. Similarly.

icn : 11 | | | fib returned 1 fib.icn : 12 | | fib returned 3 fib. ing the procedure. or is resumed. For &trace := –1 example. The vertical bars indicate. the line number in that file.icn : 11 | | | | fib returned 1 writes out the current file name and the line number in it. if i = (1 | 2) then return 1 else return fib(i – 1) + fib(i – 2) PROGRAM INFORMATION end The values of the keywords &file and &line are. assuming &main has not been activated since its initial activation to start program execution. so the value assigned to &trace can be used to limit the amount of trace output. the trace output resulting from . Tracing is controlled by the value of the fib. the procedure called.icn : 12 | fib returned 5 error output each time a procedure is called. See Appendices E and F for other ways of enabling tracing.icn : 11 | | | fib returned 1 fib. and so on.icn : 7 main failed value of &trace is decremented by 1 each time a message is written.icn : 12 | | fib(3) Tracing is the main debugging tool in Icon.icn : 12 | | | | fib(2) fib.icn : 12 | | | | fib(1) consist of several parts that are compiled from different files. a diagnostic message is written to standard fib. For example.icn : 5 | fib(5) For example. fib. 16 Chap. but they allows tracing to continue indefinitely or until another value is assigned to &trace.icn : 12 | | | fib(2) fib. 192 Errors and Diagnostic Facilities Chap. returns. fib. the value returned. It starts at 1 for the initial call of the main procedure and increases and decreases as procedures &trace := –1 are called and return. write(fib(5)) image(&main) end procedure fib(i) produces "co–expression_1(1)".icn : 11 | | | fib returned 1 TRACING fib.icn : 12 | | fib returned 2 If the value of &trace is nonzero.icn : 12 | | | fib returned 2 fib. 16 Errors and Diagnostic Facilities 193 Some built-in values have string images consisting of the keyword that A diagnostic message produced by tracing shows the name of the file contain- produces the value.icn : 12 | | | fib(1) Tracing Procedures fib. Line ". the name of the file and The resulting trace output is: line number in that file for the currently executing expression. For example. &line) fib.icn : 12 | | fib(4) fib. procedure main() The image of a co-expression includes its serial number and the number of times it has been activated in parentheses. respectively. fib. ".icn : 11 | | | | fib returned 1 The value of the keyword &progname is the name of the executing program. fib.icn : 12 | | | fib(3) write("File ". by way of indentation. Values in trace messages are shown in a manner similar to image(). The fib. suspends. show more detail. &file.icn : 12 | | | fib(2) keyword &trace. On the other hand. fib.icn: produces "&null". The serial number for &main is 1. Suppose the following program is in the file fib. the level of image() procedure call. Note that a program may fib. The keyword &level also gives the current level of procedure call.

icn : 11 main failed Co-expression activation and return also is traced if the value of &trace is non- zero. co-expression_1 : &null @ co-expression_2 if ="stop" then break trace.icn : 9 | main. The function call display(1) includes only local identifiers in the currently while write(@lower.. @upper) active procedure. The form of co-expression tracing is illustrated by the following program: Displaying Variable Values procedure main() The function display(i. &trace := –1 starting at the current level. The output is written to the file f.icn : 6 | main. 4.icn.icn : 123 | build(list_5 = ["cone".icn : 6 | main. co-expression_1 : &null @ co-expression_2 write(linecount(intext)) trace.047197551]) trace..icn : 9 | main.dat") | stop("cannot open input file") trace. 1.icn : 7 | main.0. co-expression_2 failed to co-expression_1 Tracing Co-Expressions trace.1.icn : 9 | main. f) writes the image of the current co-expression. 0. the value of &trace is decremented for each THE VALUES OF VARIABLES trace message. 42.icn : 7 | main.3. co-expression_3 returned "C" to co-expression_1 while line := read(file) do … line ? { trace.icn : 7 | main. followed by the program’s global identifiers and their values. co-expression_1 : &null @ co-expression_2 procedure main() trace. " ".0.icn : 9 | main. &pi / 3] trace. co-expression_3 returned "A" to co-expression_1 trace. co-expression_1 : &null @ co-expression_3 trace. co-expression_2 returned "z" to co-expression_1 shape.4.0. co-expression_1 : &null @ co-expression_3 trace. lower := create !&lcase whose value is the current level of procedure. local lower.icn : 9 | main. co-expression_1 : &null @ co-expression_2 local count. co-expression_1 : &null @ co-expression_3 } trace. If this program is in the file trace. co-expression_1 : &null @ co-expression_2 trace. co-expression_3 returned "X" to co-expression_1 display() trace. line trace. the trace output is: An example of the output of display() is given by the following program: trace. trace. co-expression_1 : &null @ co-expression_2 . co-expression_3 returned "Y" to co-expression_1 has the form trace.icn : 7 | main. co-expression_2 returned "b" to co-expression_1 end trace.1.icn : 9 | main. As for procedure calls and returns.194 Errors and Diagnostic Facilities Chap. co-expression_1 : &null @ co-expression_3 trace..icn : 6 | main.icn : 9 | main.1. co-expression_3 returned "Z" to co-expression_1 Ellipses in trace messages indicate values omitted to prevent very long lines.42.0. co-expression_2 returned "c" to co-expression_1 count := 0 trace. co-expression_1 : &null @ co-expression_3 trace. co-expression_2 returned "y" to co-expression_1 build(shape) trace. co-expression_1 : &null @ co-expression_2 trace. upper followed by a list of local identifiers and their values in i levels of procedure calls. An omitted value of f defaults to upper := create !&ucase &errout.icn : 9 | main. co-expression_1 : &null @ co-expression_3 intext := open("build.icn : 9 | main. co-expression_2 returned "a" to co-expression_1 local intext trace..icn : 6 | main. co-expression_3 returned "B" to co-expression_1 procedure linecount(file) trace.icn : 6 | main.icn : 9 | main. 11. 16 Errors and Diagnostic Facilities 195 shape := ["cone".icn : 6 | main.icn : 7 | main. An omitted value of i defaults to &level. The function call display(&level) includes local identifiers for all procedure calls leading to the current procedure call.0.3.icn : 6 | main. while display(0) includes only end global identifiers.icn : 9 | main.icn : 9 | main.icn : 7 | main.2.11.icn : 9 | main. 16 Chap. co-expression_2 returned "x" to co-expression_1 else count +:= 1 trace.

dat) Termination dump: global identifiers: display = function display co-expression #1 (1) linecount = procedure linecount main local identifiers: main = procedure main line = "Icon Programming. word) program."Icon") from line 9 in dump.icn intext = file(build." open = function open word = "Icon" read = function read words = set_1(0) stop = function stop global identifiers: write = function write genword = procedure genword main = procedure main Post-Mortem Dumps many = function many put = function put If the keyword &dump has a nonzero value when program execution termi- read = function read nates.dat) Traceback: line = "stop" main() main local identifiers: put(set_1(0). 16 Errors and Diagnostic Facilities 197 return count } end end which produces the display output Typical output on termination is: Run–time error 108 co–expression_1(1) File dump. This is provided by name(v). Sometimes. procedure genword(s) For subscripted lists and tables. however.. 16 Chap. every write(!sort(words)) which produces a string name for the variable v. name(main) produces "main" and name(&subject) produces "&subject". For example.icn. it is useful to know the name of a variable. a listing of the values of set = function set variables in the style of display(1) is produced. an indication of the type and subscript is s?{ given. especially when debugging a put(words. Line 9 linecount local identifiers: list expected count = 39 offending value: set_1(0) file = file(build.. whether by normal termination or a run-time error. while tab(upto(&letters)) do { word := tab(many(&letters)) suspend word } . they are obvious every word := genword(line) do when reading a program.196 Errors and Diagnostic Facilities Chap. sort = function sort An example is tab = function tab upto = function upto procedure main() write = function write words := set() &dump := 1 VARIABLES AND NAMES while line := read() do Since references to variables usually are explicit in a program. end The names of identifiers and keywords are obvious.

For … example. An interac- Scope rules apply to variable(s). ":". j provided s is an identifier or a keyword that is a variable. x3. A consequence of using an approximation for very large integers is that writes the names and values of x1. . 16 Chap.0. i) … Using name() and variable() z := complex(2. it may be useful to suspect runaway recursion first and start by examining the end of the traceback. 3. image(variable(x))) very large integer. such as procedure. values of local identifiers. Runaway Recursion If a procedure calls itself endlessly. if the value of noun is "piano". the traceback may be produces "noun[2:3]".5) The use of name() and variable() are illustrated by writing out the names and name(z. It also is easy to change the identifiers in such an expression. Since Icon’s evaluation stack is large. and serial number are used in the name of a field reference. 198 Errors and Diagnostic Facilities Chap. could be provided in this procedure for each local identifier of interest. integer(image(i)) may fail.r) produces a result such as "complex_4. " is not a variable") NOTES allows the user to find the values of variables of interest. as mentioned in the Notes section of Chapter 10. and x5. contrary to what might be expected. it is possible to get a variable procedure encapsulate(term. field name. either directly or through a chain of calls to other procedures. x4. var. For example. As noted earlier in this chapter. then Diagnostic lines such as variable("summary") := 1 write("The value of term is: ". The function variable(s) produces the variable whose name is s.r". followed When this happens. If s is the name of a local variable in the current tive interface. This is done every x := name(x1 | x2 | x3 | x4 | x5) do because of the amount of time needed to produce a string for the exact value for a write(x. name(noun[2]) a traceback is produced. local i. the result is that local variable even if there is a global variable by the same name. term) assigns 1 to the global identifier summary. for very large integers the function image() produces a string showing the approximate value of the integer. On occasion. Images of Integers Some kinds of diagnostic output can be simplified by taking advantage of the fact that name() and variable() are inverses for identifiers. The record type. it may appear that the traceback is in a loop. hundreds of lines long and very voluminous if the calls have many complicated arguments. while var := read() do write("The value of ". Consider the following procedure declaration: For identifiers and keywords that are variables. the variable name is given. value) from its name. record complex(r. For example. image(variable(var))) | write(var. 16 Errors and Diagnostic Facilities 199 For subscripted string-valued variables. It fails otherwise. Icon’s evaluation stack eventually overflows. For example. if summary is a global identifier. in In the case of an extensive traceback. " is: ". x2. program execution terminates with a run-time error and by the subscript range.

many word puzzles depend on the intersection of two words in a common character. Given two words word1 and word2. 17 Programming with Generators 201 17 Programming with Generators Generators in combination with iteration and goal-directed evaluation allow com- plex computations to be expressed in a concise and natural manner. using the full capacity of generators requires new programming techniques and unconventional ways of approaching problems. the string value of word2 is automatically converted to a cset consisting of the possible characters at which an intersection in word1 can occur. Few programming languages have generators. word1) produces the position in word1 of one intersection. For example. In many cases they internalize computations that otherwise would require complicated loops. This chapter describes ways to use generators and provides several idioms for computations that are natural in Icon. NESTED ITERATION Many problems that require the production of all possible solutions can be formu- lated using nested iteration. While i gives the position of 201 . all the places that two words intersect may be of interest. In constructing or solving such puzzles. i := upto(word2. auxiliary identifiers. Consequently. Chap. and tedious comparisons. In this expression.

i)) write() For example. Goal-directed evaluation is commonly used in Icon for “small-scale” com- every write(right(word2[1 to j – 1]. i iterates over the positions in word1 at which there is a character solution to this problem involves generation of possible solutions: Goal-directed in word2. write() } The classical problem of this kind consists of placing eight queens on a chessboard so that no two queens are on the same column. word1) then { a j := upto(word1[i]. "boat") produces } b The effect is the same as for nested iteration because suspended generators are l ot t er y resumed in a last-in. j b o if i := upto(word2. The pair of b positions can be determined by lot t er y a if i := upto(word2. All intersections can be GOAL-DIRECTED EVALUATION AND SEARCHING produced by using nested iteration: Goal-directed evaluation is one of the more powerful programming techniques for every i := upto(word2. word1) t then j := upto(word1[i]. cross("lottery". i)) putation. "boat") are: previous partial solutions. t This approach produces at most one intersection. while j iterates over the positions in word2 at which this character occurs. word2) b This computation can be cast in terms of a procedure that locates the positions o and displays the intersection: a lot t er y procedure cross(word1. One solution to this problem is: . i)) formulated in terms of searches over “solution spaces”. word2) local i. word2)) do { return every write(right(word2[1 to j – 1]. 17 Chap. 17 Programming with Generators 203 such an intersection in word1. word1)) & (j := upto(word1[i]. word2) lot t er y every write(right(word2[1 to j – 1]. or diagonal. i)) tion: write() } every (i := upto(word2.202 Programming with Generators Chap. first-out manner. This is the same in a single iteration with a conjunction as it is in nested iterations. word2) do { values. word1) do solving problems that involve searching through many possible combinations of every j := upto(word1[i]. row. The real power of goal- write(word1) directed evaluation is evident in larger problems in which solutions are best every write(right(word2[j + 1 to ∗word2]. The In this procedure. i)) write(word1) end every write(right(word2[j + 1 to ∗word2]. such as finding common positions in two strings. evaluation to find mutually consistent solutions and data backtracking to reuse The results written for cross("lottery". i)) write(word1) This nested iteration can be reformulated using a single iteration and conjunc- every write(right(word2[j + 1 to ∗word2]. the position in word2 is needed also.

The natural place to put the first queen is in row one. however. eight instead of row four: The first queen can be placed in any row. When an attempt is made to place the sixth queen. The queens then can be placed plished by backtracking to the previously placed queen. since there are no other queens on the board yet. there are no free rows: . a natural approach to solving Some previously placed queen must be moved to another position. 17 Chap. however. since the first queen is on a diagonal through this position.204 Programming with Generators Chap. starting with the first queen in the first column. Row three is an acceptable place for the second queen. 17 Programming with Generators 205 Since there can be only one queen in a column. nor in row two. which can be placed in row consecutively. Continuing this process. since the first queen is in this row. This is accom- this problem is to associate a queen with each column. The second queen cannot be placed in row one. each successive queen is placed on the first free row.

with their left ends lower than their right ends: Now placement of the fifth queen is attempted again. Fifteen of the diagonals are downward facing. The geometrical representation of the chessboard as an eight-by-eight array is not particularly useful. the important matter is the occupancy of columns. A list provides a natural way of representing the rows: row := list(8. and diagonals. Instead. where row [i] is zero if there is no queen on it and nonzero otherwise. The columns are taken care of by the assignment of one queen to each column. Notice that it is not necessary to try all queens in all positions. a queen is moved only when its position cannot lead to a final solution. is now placed in row seven: 1972). as shown on the board at the beginning of this section. 0) . The other 15 diagonals are upward facing: This informal description of the placement process corresponds to the way that arguments are evaluated in Icon: left-to-right evaluation with last-in. A way of representing the chessboard and of determining free positions is needed. rows. however. the positions are finally adjusted so that all eight queens are placed. first-out resumption to obtain alternative results. however. and backtracking takes place to the fifth queen again. through backtracking. 17 Chap. One free rows for the fifth queen. Dijkstra. There are no more The diagonals are slightly more difficult. since there are 30 of them in all. which approach is to divide the diagonals into two groups (see Dahl. so backtracking takes place to the fourth queen. The solution of the eight-queens problem therefore can be formulated in terms of procedures that place the queens according to the method described. and Hoare. No row is free.206 Programming with Generators Chap. 17 Programming with Generators 207 Another attempt is now made to place the sixth queen. Eventually.

it suspends so that if it is resumed because the next queen cannot be placed. 0) In each case. q(8)) end procedure q(c) suspend place(1 to 8. down. 0) row := list(8. The expression The procedure q(c) corresponds to the queen on column c. 15863724 down. it is necessary to assure that row. row initial { up := list(15. c) places queen c on row r if that position is free.208 Programming with Generators Chap. q(4). the selects the correct downward facing diagonal. q(7). q(4). q(3). 17 Programming with Generators 209 row[r] <– down[r + c – 1] <– up[8 + r – c] <– r Reversible assignment is used so that the queen can be removed automatically during backtracking. 8+r–c The expression selects the correct upward facing diagonal. then suspend row[r] <– down[r + c – 1] <– up[8 + r – c] <– r In placing a queen c on row r. the row row[r] = down[r + c –1] = up[8 + r – c] = 0 positions are written: To place a queen. a nonzero value is assigned to the corresponding positions in row. since it records the row on which the queen is placed and can be used in displaying the resulting solution: All possible solutions can be obtained by iteration: . and up end for that position are zero. and up. 0) up := list(15. When all the queens are successfully placed. A queen c can be placed on row r if the write(q(1). q(7). q(3). If place(r. q(8)) following comparison succeeds: serves to place the queens. q(6). The procedure r+c–1 place(r. the diagonals can be represented by lists: down := list(15. c) # look for a row end procedure place(r. q(5). down. q(2). q(5). while queen is removed by reversing the assignment. q(6). c) static up. The row number is a convenient value to use. q(2). c) is successful. 0) down := list(15. The complete program is procedure main() write(q(1). 17 Chap. 0) } if row[r] = down[r + c –1] = up[8 + r – c] = 0 # place if free with zero or nonzero values assigned as they were for the rows.

the use of recursion in combination with generation is not as obvious. string scanning adds more to the In order to understand the sequence of results for this procedure. some of the ways that string scanning can be used are star("abc") not obvious. onto which are appended in succession "a". the Fibonacci numbers are generated by In computer processing. its apparent simplicity is deceptive. 1) using the following procedure: associativity rules and to use parentheses to group all arguments with their operators or to use some other similar representation. "ba". 18 See Appendix I for more general solutions to the n-queens problem. j) convenient to have operators appear before or after their arguments. For example. to have operations in prefix form or suffix form rather than the infix form that is easier for suspend i | fibseq(j. and so on. q(4). "a". i + j) human beings to read. … . Such a syntax is designed for human use. Furthermore. the results for "abc" would be "". 211 . it is more convenient to dispense with precedence and fibseq(1. The subsequent results consist of each result in the results for star("abc") followed by each character in "abc". The conversion of strings from one form to another provides end a good example of string scanning. q(2). q(6). q(5). 17 Chap. the results are "". Therefore. ARITHMETIC EXPRESSIONS each character in chars is appended to the first value in the results for star(chars). and arguments and with parentheses used for grouping. that is. q(3). produced by suspending with "". For example. "a". "c". Consider the problem of generating all the strings from a set of characters with Pattern Matching the strings produced in the order of their length. Rules of precedence and "c". it produces "a". A procedure that produces these results is procedure star(chars) suspend "" | (star(chars) || !chars) end Although string scanning involves only a few functions and operations. RECURSIVE GENERATORS Recursion is a powerful programming tool. 18 String Scanning and Pattern Matching 211 every write(q(1). This chapter explores string scanning. 210 Programming with Generators Chap. q(8)) There are 92 solutions in all. "b". recursively defined functions. Recursive generators also can be used to produce the sequences for many Icon’s syntax itself is typical in this respect. "b". associativity for operators are used to avoid excessive numbers of parentheses. When star(chars) is resumed for its Arithmetic expressions are usually written in infix form with operators between the second result. "b". While recursive procedure calls are String Scanning and widely used. Since !chars is repeatedly resumed for each value produced by star(chars). Furthermore. it often is procedure fibseq(i. Except for generators. consider power of Icon and influences programming techniques more than any other feature of the language. … . q(7). The first result is the empty string. "ac". "c". concentrating on examples and techniques that exploit its potential and lead to good programming style. "aa". although because of symmetries only 12 are unique. "ab".

The general ciative operator. Since there may be superfluous parentheses. and pos(−1) checks that this parenthesis is the last character / 2 left to right of the string being scanned. 1. syntactically correct). Precedence is used to select the correct operator. For example. since multiplication has higher precedence than subtraction. For example. There may be superfluous parentheses. y). not the subtraction. this process must form(tab(bal(op)). in "x–y–z" there are two ways the pattern could be applied. as indicated by the arrows beneath the operators. pos(–1)) } operator precedence associativity ^ 3 right to left As long as exp begins with a left parenthesis.212 String Scanning and Pattern Matching Chap. and hence y is an argument of the multiplication. move(1). the balanced string up to a right ∗ 2 left to right parenthesis is matched. Look for the operator of lowest precedence first and then for operators with increasingly higher precedence.^(n.∗(z. it is easiest to handle right- expression exp into prefix form. "(u+(v/(n^(e^2))))" A similar problem occurs in selecting among several operators of equal The prefix forms of these two expressions are: precedence. A procedure is: expr1 operator expr2 → operator (fix(expr1). tab(0)) be repeated. the scanning expression succeeds. op) The first problem is to remove any outer parentheses that may occur around return exp ? { the argument of fix(). tab(bal(')')). there are two rules: Note that the variables and constants have the same form in both infix and prefix notation. is equivalent to The correct pattern therefore is obtained by looking for the operators of lowest precedence first. 18 String Scanning and Pattern Matching 213 Some typical infix operators with their relative precedences and associativities while exp ?:= { are 2(="("." rightmost left-associative operator is the correct one. "x^e^2" is equivalent to "x^(e^2)". One approach is: } end .^(e. 18 Chap. The first occurrence of the pattern "u+v/n^e^2" is the correct one in this example. approach to the problem is recursive. The next step is to analyze exp to get the proper operator for the pattern For example. fix(expr2 )) procedure rassoc(exp. the transformation has the form associative operators. and the while loop continues with exp being scanned again. the fully parenthesized form of expr1 operator expr2 "x–y–z∗delta" This pattern may occur in an infix expression in many ways. On the other hand.2))))" is true of right-associative operators. the opposite "+(u /(v. with a procedure fix(exp) that converts an infix Since string scanning operates from left to right. Since subtraction is left-associative. Therefore. A typical problem is to convert infix expressions with the preceding operators into prefix form. In summary. in is "x–y∗2" "((x–y)–(z∗delta))" ↑↑ and the pattern occurs in two ways. If the right parenthesis is the last character of the string + 1 left to right being scanned. this expression is equivalent to "(x–y)–z" and the "–(–(x. The value produced by tab(bal(')')) – 1 left to right is assigned to exp. Locate the rightmost left-associative operator but the leftmost right-asso- otherwise are assumed to be well formed (that is. but the infix expressions 2.

18 String Scanning and Pattern Matching 215 where form(arg1. the initial null value of j is not changed. if it is an procedure rassoc(exp. 18 Chap. allowing end all operators in a class to be processed at the same time. move(1). return exp ? { The preceding program segment can be made considerably more concise by form(tab(bal(op)). op. an application of the fact that end ." || fix(arg2) || ")" alternatives. op. as shown previously: The rightmost left-associative operator can be located by iterating over the result sequence for the positions of all such operators to find the last one: procedure fix(exp) while exp ?:= { procedure lassoc(exp. move(1). and lassoc() fails. '+ –' | '∗/') | rassoc(exp. op) identifier or a constant. that is. arg2) and return op || "(" || fix(arg1) || ". This presumes. If bal(op) does not produce any result.'+ –' | '∗/') | rassoc(exp. Notice that the argument of lassoc() also contains two return op || "(" || fix(arg1) || ". op) local j if exp := lassoc(exp. tab(0)) end } The rest of the program for infix-to-prefix conversion is: end procedure main() The expression \j determines whether any value was assigned to j in the every loop. while write(fix(read())) tab(\j) fails. arg2) performs the necessary rearrangement of the strings The procedure to convert infix expressions into prefix form first removes outer produced by scanning. '^') then return exp form(tab(\j). which are evaluated from left to right. parentheses and then applies lassoc() and rassoc(). '∗/') then return exp every j := bal(op) else if exp := rassoc(exp. '+ –') then return exp return exp ? { else if exp := lassoc(exp.214 String Scanning and Pattern Matching Chap. op." || fix(arg2) || ")" p(expr1 | expr2) end are equivalent. The obvious approach is: procedure lassoc(exp. arg2) The argument of the return expression consists of the possible alternatives. pos(–1)) local j } return exp ? { return lassoc(exp. op. arg2) constructs the desired prefix expression: p(expr1) | p(expr2) procedure form(arg1. move(1). op) 2(="(". The final component of this expression returns exp unchanged if it contains no operators. Note that form(arg1. of course. that exp is well formed. end The procedures rassoc() and lassoc() must be applied in the correct order. tab(0)) else return exp } Note that the second arguments of lassoc() and rassoc() are character sets. '^') | exp procedure form(arg1. indicating that op does not occur in exp. tab(bal(')')). '^') | exp every j := bal(op) form(tab(\j). tab(0)) using goal-directed evaluation in the return expression: } end return lassoc(exp.

&pos:&pos := upto('. If expr does not produce a result. should be used instead of while the third rule assures that alternative matches start at the same place in the subject. the reversible assignment operation ways using string analysis functions. The expression A pattern is a powerful conceptual tool for describing the structure of strings. not. expr1 || expr2 The first rule assumes that matching expressions all apply to the same subject. The protocol for a matching expression expr is as follows: {s := move(1). 2. since the value it produces is not the substring between the old and new positions. The three rules are largely independent. Most pattern matching is done from left to 3.&pos:&pos <– upto('. suffix or fully parenthesized infix is a matching expression. since it does not produce the substring of the subject between the positions before tab(upto('. actual matching is done only by tab(i) and restores the previous position. practice to use matching expressions. is not a matching expression either. 18 Chap. but forms can be produced by rearranging the concatenation. The third rule includes the possibility that a matching expression may expr1 & expr2 change the position but later restore it if a subsequent match is unsuccessful. ated. Matching expressions In general. since. it produces the substring of the subject between the When using string scanning to do pattern matching. while the latter does For example.')] change the position in the subject and produce the substring of the subject between the old and new positions. On the other hand. conjunction may be used in place of concatenation. Evaluation of expr does not change the subject. If production of matched substrings is not important. to the time expr was evaluated. The operations for transforming infix to prefix forms in the preceding sections use patterns such as tab(upto('. in the range specification must be dereferenced before a new value is assigned to &pos. Matching expressions that extend the repertoire of matching functions provide a way of expressing more complicated matching operations. bounded expressions prevent restoration of the position. tab(upto('. This section develops a methodology for describing and implementing patterns &subject[. 18 String Scanning and Pattern Matching 217 Note that the prefix form is determined in form(). The functions tab(i) and move(i) are called matching functions because they &subject[.')) || move(1) . is not a matching expression even though it produces the matched substring.')) || move(–1) PATTERN MATCHING is not. since. so that must obey a protocol that allows them to be used like matching functions. it does not restore the Matching Expressions previous position. 216 String Scanning and Pattern Matching Chap. In such cases. While the value of i in tab(i) can be computed in many is a matching expression. since the former expression produces the matched substring. If expr succeeds. if it is resumed. however. if it is resumed. Both operations perform data backtracking. tab(upto('.')) & move(1) expr1 operator expr2 is not a matching expression.')] using string scanning.')) is evaluated and after move(1) is evalu- to describe the structure of the string and to identify its components. Similarly. it is generally good positions before and after its evaluation. The second rule is concerned with the values produced by matching expressions. s || tab(0)} 1. Note that in both cases the first occurrence of &pos move(i). it leaves the position where it was prior right.

&subject[.218 String Scanning and Pattern Matching Chap. "white". procedure lmatch(slist) suspend =!slist procedure tab(i) end suspend . second alternative matches whatever p() matches. Not only is this order of matches the string up to and including the last period in the subject. since the argument is called in the body of the procedure for arbno(). . concatenated with whatever arbno(p) matches: zero or more instances of whatever p() matches. As such. arbno(lmatch(["black". or "gray". As an example. end A similar procedure that matches the longest possible string first is then arbno(shades) matches strings that contain zero or more occurrences of procedure rarb() "black". "gray"]) be consecutive substrings. Note The first alternative. The that arb() may generate more than one value. "white". Therefore. For matching procedures. but also the value assigned to the parameter p is a string. "white". matches any string from the current position through the end of the subject. The value returned is dereferenced. change the subject. arb() || ="load" || arb() || ="r6" given matches any string that contains the substring "load" followed by the substring "r6". "gray"]) all the rules of protocol for matching expressions." the call of lmatch() is evaluated before arbno() is called. the empty string. procedure arbno(p) procedure arb() suspend "" | (p() || arbno(p)) suspend . not a procedure. For example. evaluation incorrect. The matching function move(i) can be written as a procedure in One advantage of using a matching procedure for high-level string processing an analogous manner. consider a procedure that does what the function tab(i) does. otherwise the result would be a variable to which a value could be assigned to matches "black".&subject[. "white". 18 Chap. suspend . An example of such a use is given by: example. 18 String Scanning and Pattern Matching 219 Matching Procedures Another example is a matching procedure that matches any one of several strings in a list: A matching procedure is a procedure that is a matching expression.&pos: &pos <– ((∗&subject + 1) to &pos by –1)] The argument of arbno() must be a matching procedure. "gray"])) rarb() || =". in For example.&pos:&pos <– i] end For example. "white".&subject[. it can be used as an argument to other Using this technique.&pos:&pos <– &pos to ∗&subject + 1] end end The procedure arbno(p) matches zero or more instances of whatever p() matches. procedure shades() "load" need not appear at the beginning of the subject. or "gray". For example. and "load" and "r6" need not suspend arb() || lmatch(["black". a variety of matching procedures can be written. Such a procedure is merely an encapsulation of a matching expression and satisfies lmatch(["black". It cannot be an end arbitrary matching expression. is that a procedure is a value. corresponds to zero matches of p().

Applica- parentheses. like element. strings. while other charac. Starting with the goal symbol X. These definitions can be expressed more formally in terms of a grammar as Recognizers follows. T can A pattern characterizes a set of strings — the strings that it matches. defined to be”. interest. For example. X goal Natural languages. y. 1. Note the similarity of this use of the 2. The symbol ::= stands for “is the specific strings. x is matched by ="x". Then a grammar corresponding to the preceding definitions is: Recognition is the process of determining whether or not a string belongs to a language and is the converse of derivation. x+(E∗T) second alternative for T x+(y∗T) second alternative for E A language for a simple class of arithmetic expressions can be described x+(y∗E) first alternative for T informally in terms of mutually recursive definitions: x+(y∗z) third alternative for E 1. x+E first alternative for T Patterns and the grammars for languages have a close relationship. The form of such matching procedures is given later. tion of all the rules in all possible ways produces all strings in the language. term. a language for terms defined by T. A term is an element or an element followed by a ∗ followed by a term. T. there is a straightforward and mechanical way of producing patterns that match the strings in the language: Uppercase letters are used here to denote nonterminal symbols. there is a direct mapping from the rules of the grammar to x+(T) first alternative for X patterns that match strings in the corresponding language. and a language for elements by . Since there are no more nonterminal symbols in this string. are called terminal symbols. 3. 3. For example. in which x+T first alternative for E the structure can be defined by precise and comparatively simple grammatical rules. and the vertical bar replaces “or”. For example. As in Words in italics. X is the goal in the examples that follow. An expression is a term or a term followed by a + followed by an expression. Nonterminal symbols are matched by matching procedures. T ::= E | E∗T E ::= x | y | z | (X) In the case of grammars like the preceding one. In the present context. respectively. 18 String Scanning and Pattern Matching 221 Note that arbno() is a recursive generator. are very complex. E+T first alternative for first instance of T however. A concatenation of symbols is matched by the concatenation of the match- Each nonterminal symbol defines its own language: a language for expres. The strings in a language (its “sentences”) are derived or of a sentence is: described according to grammatical rules. and E stand for expression. has lower precedence than concatenation. The concatenation of symbols replaces “followed by” in the informal definition. In fact. z or an expression enclosed in The alternatives in the preceding derivation were chosen at random. vertical bar to the alternation control structure in Icon. The grammatical rules T+X second alternative for X of such languages (their syntax) describe these languages only superficially. the GRAMMARS AND LANGUAGES symbol ::= in the grammar means that an instance of the nonterminal symbol on its left can be replaced by any one of the alternatives on the right. A set of strings be replaced by either E or E∗T. For some x+(X) fourth alternative for E kinds of grammars. Compare it to star() given in Chapter defined by E. Terminal symbols are matched by corresponding matching expressions for ters. including programming languages. 18 Chap. like x. the language defined by X. many interesting languages. describe sets of strings and are called nonterminal most interesting languages. Specific strings. this amounts to X ::= T | T+X matching the strings that are in a language and only those strings. a possible derivation is called a language. stand for themselves. x+(y∗z) is a sentence in 2. In a grammar. ing expressions for the individual symbols. For example. T+X is matched sions defined by X. the language for X contains an infinite number of symbols. and element. 220 String Scanning and Pattern Matching Chap. T+T first alternative for X there are many aspects of natural languages that defy precise description. including parentheses. the vertical bar X is matched by X(). There are. Let X. One nonterminal symbol is designated as a “goal” for the language of 17. such as English. In deriving the strings for the language defined by a nonterminal symbol. An element is one of the characters x.

This is a well-known context-sensitive lan- end guage. 1. The previous matching procedures have no arguments. which causes internal stack overflow and program termina- is: tion with an error message. and they cannot handle left recursion in the grammar. A matching procedure encapsulates the matching expression for the corre- suspend (X() || ="+" || T()) | T() sponding nonterminal symbol. aaabbbccc. this approach to recognizing strings is sometimes useful. which cannot be derived from any context-free grammar. For inefficient. It also provides insights into the relationship between grammars and pattern suspend T() | (T() || ="+" || X()) matching. 18 String Scanning and Pattern Matching 223 T() || ="+" || X() The kind of recognizer given here is called a top-down. recognizers can be constructed for classes of These rules can be used to convert any context-free grammar of the kind given languages that are more general than context-free ones. While there are more obvious ways of recognizing such strings than the procedure given above. aabbcc. . occurs when the definition of a nonterminal symbol has an alternative that begins with a nonterminal symbol leading back to itself. Alternatives are matched by the alternation of matching expressions. procedure X() Despite these problems. For example. end There are other possibilities. Recognizers of this kind have two problems: they are 4. abc. program The procedure for the nonterminal goal symbol is called within a scanning expression. it is representative of a general class of recognizers for context-sensitive languages. By adding arguments. the matching procedure for end X ::= T|T+X calls itself indefinitely. For example. Left recursion example. … . Consider.222 String Scanning and Pattern Matching Chap. … : the empty then write(" accepted") else write(" rejected") string. the previously directly into matching procedures. Since recognition requires that the entire string be matched. the scanning operation has the form while writes(line := read()) do if line ? { line ? { ABC("") & pos(0) X() & pos(0) } } then write(" accepted") else write(" rejected") A program to recognize strings in the language defined by X is: end procedure main() procedure ABC(s) while writes(line := read()) do suspend =s | (="a" || ABC("b" || s) || ="c") if line ? { end X() & pos(0) } This program matches sentences in the language an bn cn for n = 0. 18 Chap. not just an procedure main() initial substring of it. recursive-descent recognizer with backtracking. in a rule such as E|E∗T X ::= X+T|T is matched by the matching procedure E() | (E() || ="∗" || T()) procedure X() 5. for example.

T()] end end Since parsing procedures produce lists. X(). 18 String Scanning and Pattern Matching 225 Tracing provides insight into the matching process. It is relatively easy to convert matching procedures like those given previously into parsing procedures that produce a “parse tree” that retains the structure of the match. For example.icn: 13 | | | ABC("bb") abc. E().icn: 13 | | | | ABC suspended "bbb" abc.icn: 13 | ABC suspended "" abc. ="+".icn: 13 | | ABC suspended "aabbbcc" abc. The technique produces lists of matched strings rather than concatenations of matched strings. [ [ ["y"]. that shows the details of the parse. ")" ] ] ] ] end Such a list is more easily understood if it is drawn as a tree: procedure X() suspend ["X".icn: 13s | ABC suspended "aaabbbccc" Parsers The process of recognizing strings in a language has limited usefulness. Recognition produces only a “yes” or a “no”.icn: 5 | ABC("") abc. E()] | ["T". or a tree. [ ["z"] ] ] ]. the value produced for the string "x+(y∗z)" is procedure E() suspend ["E". X()] end . the trace output for the procedure ABC() is: abc. For the input line aaabbbccc. ="(". =!"xyz"] | ["E". "∗". "+". T()] | ["X".icn: 13 | | ABC("b") abc. ="∗". T().icn: 13 | | | | ABC("bbb") abc.icn: 5 | ABC resumed abc. =")"] [ [ ["x"] ]. the result is a list of lists.224 String Scanning and Pattern Matching Chap. X()] suspend ["T". ="+". the parsing procedures for the gram- mar in the preceding section are: procedure X() procedure T() suspend [ T()] | [ T(). With this addition. but no information is produced about how the string is matched or how its structure is related to the grammar. 18 Chap.icn: 13 | | | ABC suspended "abbbc" abc. [ [ [ "(". A matching procedure such as procedure X() suspend T() | (T() || ="+" || X()) end It may be useful to provide a tag as the first value in each list in order to identify can be rewritten as a parsing procedure: the nonterminal symbol.

although there may be many arcs directed out of a node. the arithmetic expression "(a/b)+(c–d)" has the prefix form "+(/(a. At most one arc can be directed into any node. Nodes that have no arcs directed out of them are leaves. One node. For example.d))" and corresponds to the tree 227 . graphs. and tables can be used for representing and manipulating trees. A value usually is associated with each node. and other structures.b). has no arcs directed into it. This chapter describes how records. 19 Using Structures 227 Note that the more compact formulation =!"xyz" 19 is used in place of the direct translation ="x" | ="y" | ="z" The tree produced for the preceding example is: Using Structures Icon provides the facilities that are needed for processing structures. such as the parse trees that were developed in Chapter 18. 18 Chap.–(c.226 String Scanning and Pattern Matching Chap. TREES A tree is a collection of nodes connected by directed arcs. the root. A common way to represent trees with strings corresponds to the way that arithmetic expressions are given in prefix form (see Chapter 18). lists. sets.

move(1) # skip paren When a tree is represented by a string. the parentheses and commas indicate R. ["c"]. since the structure of a tree is recursive.rptr := rtree(tab(bal(')'))) # right subtree represented with structures. inode2) Of course. rptr) ments to fields: where the lptr and rptr fields contain pointers to the left and right subtrees. In that representation.'))) # left subtree the structural relationships. The two branches of the selection expression differentiate between interior and leaf leaves are represented by strings. For interior nodes. nodes. with concatenation replacing assign- record node(value.value # leaf Using this representation. not lists. ["d"]]] return R In this representation each node of the tree is represented by a list.lptr := rtree(tab(bal('. leaf1. the tree shown above can be constructed as follows: else return rtree.228 Using Structures Chap. ["/". A procedure to convert the string representation of a tree to its corresponding record representation is: "a" "b" "c" "d" procedure rtree(stree) local R stree ? { As shown here.value || "(" || stree(rtree. The representation here is more general. different from the one used for parse trees in Chapter 18.rptr) || ")" leaf1 := node("a") end leaf2 := node("b") leaf3 := node("c") This formulation assumes that if one pointer from a node is null the other one is also. ["b"]].lptr then return rtree.lptr) || ". leaf3. if R := node(tab(upto('('))) then { # new node That is. information read into a program and written out of a program consists of strings. 19 Using Structures 229 leaf4 := node("d") inode1 := node("/". While such a representation of a tree is useful for processing data within a "/" "–" program. The first value in end each list is the value that is associated with the node. this tree could be constructed in a single large expression. trees usually are drawn with the root at the top. there are two arcs out of all nodes except the leaves. leaf2) "+" inode2 := node("–". . procedures are needed to convert between the string and record representations of trees.19 Chap. but it is move(1) # skip comma awkward to process for many purposes. lptr. ["–". nodes: Conversion from the record representation of a tree to the corresponding string representation is similar in structure. ["a"]. leaf4) root := node("+". as in } else R := node(tab(0)) # leaf } ["+". This is a binary tree. and subsequent values in a list correspond to arcs to other nodes. Note A more structured way of representing a binary tree is to use records for the that the fields lptr and rptr have null values for leaf nodes." || stree(rtree. inode1. There are several ways that a tree can be R. Consequently. procedure stree(rtree) respectively. The string representation of a tree is compact. A procedure to do this is naturally recursive. rtree() is called recursively to construct the subtrees. Note that this representation is somewhat This formulation assumes that the string representation of the tree is well-formed. if /rtree. A natural method uses lists.

If they are. Here it is more convenient to check that each pointer is non-null. The root node itself is produced first. if they are equivalent. the values and subtrees are checked for suspend visit(\(rtree. The recursion terminates for equivalent trees when null-valued pointers (for leaf nodes) are compared. conforming to the convention for built-in comparison opera- tions. while result of common subexpression elimination. A directed acyclic graph.lptr then write(R. If this fails. For example. is a graph in which there are no loops leading from every write(stree(visit(rtree))) a node back to itself. followed by the nodes for its subtrees. The operation R1 === R2 "/" "–" does not determine whether or not two trees are equivalent. continue equivalence. for example. that is. 19 Using Structures 231 For some purposes it is useful to be able to visit all the nodes (subtrees) of a tree.value) example. as the writes all the subtrees in rtree. If all subtrees are the end same. if R1 and R2 are the same record (see Chapter 10). or dag.rptr)) # not leaf. R2.lptr | rtree. but only if they are identical.rtpr. A procedure to compare two trees for equivalence is procedure rtreeq(R1. A rooted dag is like a tree except that there may be several arcs directed into any node other than the root. that is. For every write(visit(rtree). the infix expression writes the values of all nodes in the tree.value & # check values and subtrees rtreeq(R1. else fail This can be done easily with a recursive generator: end procedure visit(rtree) The first test checks whether R1 and R2 are identical.lptr. (a/b)+((a/b)–b) every R := visit(rtree) do has the tree if /R.19 Chap. Similarly. where a subtree that is the same as another is eliminated and the two arcs are directed to one of the subtrees. calling rtreeq() recursively. it is not necessary suspend rtree to check anything else. Rooted dags occur.value === R2. "+" Sometimes it is necessary to know whether or not two trees have the same structure and the same node values.230 Using Structures Chap. R2 is returned.lptr) & "a" "b" rtreeq(R1.R2) "a" "b" "/" "b" if R1 === R2 then return R2 # identical subtrees else if /(R1 | R2) then fail # only one is null else if { R1. DAGS The procedure visit(rtree) can be used in a variety of ways. R2. Note that this procedure reflects the recursive definition of a tree.value) writes the values of all leaves in rtree.rptr) } then return R2 .

Similarly. done) # right subdag A := set() } B := set() else R := node(tab(0)) # leaf C := set() } D := set() insert(A. The table cannot be constructed in an initial clause for the same reason.rptr := rdag(tab(bal(')')). GRAPHS "a" "b" In general. rtreeq() works properly on dags. done is local to the processing of a particular tree. C) end insert(B. independent uses of rdag() might interfere with each other. it is easier to construct the dag in the first place. The procedure visit() works on dags.232 Using Structures Chap.done) local R D B /done := table() # new table if R := \done[stree] then return R # return part already done stree ? { if R := node(tab(upto('('))) then { # new node One way to build the corresponding structure is to represent each node in the move(1) # skip paren graph by a set. as in: Instead of converting a tree to a dag. although nodes with more than one arc into them are visited once for each arc. Then the values in the set are pointers — arcs to the nodes to which R. The technique used here is to tabulate the parts of the structure that have been A built already and to direct arcs to them rather than constructing equivalent parts: C procedure rdag(stree. The method of handling the table of constructed parts deserves note. When rdag() is The important conceptual point is that a set is a collection of pointers to other called to construct a dag for stree.')). since no parts of sets. Since the table done is created at the “top-level” call of rdag() and subsequently passed as an "+" argument to recursive calls of rdag(). The recursive call of rdag() includes the table done as its second argument. If it were global instead. the newly constructed dag is added as the value corresponding to the key stree. B) insert(D. . Note that the tree-processing functions in the preceding section all work properly on rooted dags.lptr := rdag(tab(bal('. B) return done[stree] := R insert(A.19 Chap. Finally. "/" "–" effectively “unfolding” them. 19 Using Structures 233 Duplicate subtrees can be eliminated by converting this tree to a dag: passing the table of the parts that have been constructed. For example. Thus. The procedure stree() processes dags as well as trees. directed graphs have cycles and unconnected subgraphs. A slightly different visualization of the structures in the programming domain the dag have been constructed yet. This causes a dag to appear to be a tree. the second argument is omitted. the table is created on the initial call of illustrates this: rdag(). Its keys are strings and its values point to the corresponding nodes. the program structures for the graph shown above are: move(1) # skip comma R. done) # left subdag the node points. D) The table done keeps track of portions of the dag that already have been constructed.

arc(5. S) "A–>C" "B–>B" return S "D–>D" end One problem is associating labels for the nodes with corresponding program Note that a set also is used to keep track of nodes as they accumulate.234 Using Structures Chap. For example. values may be associated with arcs: Node := table() Node["A"] := A Node["B"] := B Node["C"] := C A Node["D"] := D 1. this might be: what more sophisticated representation of structures. the converse association may be needed. the set-of-sets approach is inadequate. Since any kind of value can be used as a key. the labels associated with nodes may be needed. B)) The ease of manipulating this representation of graphs is illustrated by a insert(D.5 C Consequently. the /S := set() (unweighted) form of the graph in the preceding section might be represented by strings such as: insert(S. The natural solution in Icon is to use a table in which the keys are the labels and the corresponding values are the corresponding sets. insert(B. arc(3.7.7 5. Written out expli- Several problems arise in computations on graphs that may require a some. Node["A"] produces the node (set) labeled A. Then the graph can be represented in a program as follows: insert(A. Such a table might 2. for example. S) Programs that manipulate graphs generally need to be able to read a representation local n1 of a graph in string form and write the results in string form.0. n1) | closure(n1. a table with the keys and 3. as in C record arc(value. n) every n1 := !n do "A–>B" member(S.19 Chap. in B writing out the results of a computation on a graph (such as the transitive closure of a node). citly for the graph above. arc(1. D)) procedure to compute the transitive closure of a node (the node and all nodes reachable from it by a succession of arcs): TWO-WAY TABLES procedure closure(n. D On the other hand. in constructing a graph from its string representation. For example. a record type can be used for arcs. 19 Using Structures 235 A In this case.0 corresponding values reversed can be used: . C)) values in the set.0 be used. arc(2.0. For example. However. an arc is represented by (a pointer to) a set and a node is represented by the insert(A. node) D B where the value field contains the value associated with the arc and the node field contains the set to which the arc points.5. structures. B)) Thus.

s3) normally is used to perform a character substitution label. Transpositions If the value of labels is a string of distinct characters (that is. and subscripting it with a node produces the corresponding The function map(s1. 237 . labels. then map(trans. containing no duplicates). and s1 varies. If s1 and s2 are considered to be parameters and s3 is allowed to vary. "aeiou". on s1 by replacing characters in s1 that occur in s2 by the characters of s3 that are in corresponding positions to those in s2. Subscripting it with a label produces the corresponding node. In this kind of use. "∗∗∗∗∗") which replaces all lowercase vowels in line by asterisks. s2. and the value of trans is a rearrangement.19 Chap. as in map(line. 20 Mappings and Labelings 237 Label := table() 20 Label[A] := "A" Label[B] := "B" Label[C] := "C" Label[D] := "D" It is not necessary to have two tables. of the value of labels. or transposition. some surprising results are possible. s2 and s3 are parameters that characterize the substitution. s3) produces the corresponding transposition of s3. the same table can be keyed with both the labels and the nodes (sets): Graph := table() Mappings and Labelings Graph["A"] := A Graph["B"] := B Graph["C"] := C Graph["D"] := D Graph[A] := "A" Graph[B] := "B" Graph[C] := "C" Graph[D] := "D" Such a ‘‘two-way’’ table keeps all the information needed to associate labels MAPPING TECHNIQUES with nodes and vice versa in one structure.236 Using Structures Chap. For example. Since the keys in a table need not all be of the same type. however.

it can be reversed by one application of map(). "123456". "123456". labels := string(&cset) Therefore. In many cases. as in expressions also could also be used for these purposes. In this case it is the rotation of s3 two characters to the right (or four to the left). max)) end The values chosen for labels and trans are two strings of reasonable size that are easy q u o t a s to write.238 Mappings and Labelings Chap. left(labels. the reversal of "quotas". "s". If the transposition produces the corresponding transposition from the other end of trans. s) 1 2 3 4 5 6 else return reverse(right(s. as mentioned earlier. Strings of all 256 characters are Any characters can be used for the labeling as long as there are no duplicates. s3) . produces the reversal of the value of s3. 20 Chap. of course. Subscripting is different. "123456". however. The expression right(trans. ∗s – max)) || map(trans. The reversal process is more efficient for longer values of labels and trans. Similarly. If s is not too long. The more important restriction is that the sizes of the second and third arguments must be the same. recursion simply provides a more compact solution for the purposes of illustration. s3) Piece-by-piece reversals of long strings can be done iteratively. the result produced is correspondingly different. that is. the transposition of longer strings can be performed piece by piece. since the specified transpo- sition. 20 Mappings and Labelings 239 map("654321". ∗s). left(s. ∗s) The value produced is "satouq". "123456". impractical to write out literally. but they can be computed by The maximum size of a transposition is limited to 256. labels. trans := "" every trans := !labels || trans map("654321". trans. the character "5" in the first is: argument is replaced by the character corresponding to the "5" in the second argument. max initial { 6 5 4 3 2 1 labels := "abcdefghijklmnopqrstuvwxyz" trans := "zyxwvutsrqponmlkjihgfedcba" max := ∗labels } if ∗s <= max then return map(right(trans. recursion is used. is the reversal of the labeling string. "quotas") Although there is a built-in function reverse(s). If s is too long to be reversed by one application of map(). "654321". The longest possible labeling is 256. map("561234". The expression left(labels. that is. ∗s). Suppose the value of s3 is "quotas" as in reverse(s1 || s2) == (reverse(s2) || reverse(s1)) map("654321". "123456". "a". s3) only can be used to reverse six-character strings. A procedure "6" in the second argument. and so on: procedure reverse(s) static labels. a corresponding procedure using Then the "6" in the first argument is replaced by the character corresponding to the mapping techniques provides a model for a variety of transpositions. ∗s) s a t o u q truncates s at the right and produces a labeling of the correct length. That is.

1976). If some characters in labels are omitted from trans. trans. max)) end When reverse() is called the first time. other kinds of positional transformations are possible (see Gimpel. The procedure to swap characters is the result. ∗s). very similar to reverse(). "123456". defined consistently when reverse() calls itself in its initial clause. and max must be This procedure only works properly if the size of s is even. s) } … else return swap(left(s. Mapping labels := "12" techniques have two advantages. starting with short labeling and transposition labels and trans are selected and in the handling of strings that are too long to be strings. right(s. It is reasonable to question the use of mapping techniques for transpositions The two strings of this kind. s3) labels cannot contain duplicate characters and trans must be a transposition of This transposition also can be characterized by labels. trans. they are fast. overcoming the initialization overhead for procedures.240 Mappings and Labelings Chap. For six-character For transpositions like strings. transposed by a single call of map(). Second. which is based on labels := "12" swap(s1 || s2) == (swap(s1) || swap(s2)) trans := "21" The complete procedure for swapping adjacent characters is: characterizes reversal. max labels := "12" initial { trans := "21" labels := "12" # short label max := ∗labels trans := "21" # short transposition trans := swap(string(&cset)) max := ∗labels labels := string(&cset) trans := reverse(string(&cset)) # long transposition max := ∗labels labels := string(&cset) # long label } max := ∗labels # new length if ∗s <= max then return map(left(trans. 20 Chap. For example. Note that labels. labels. 20 Mappings and Labelings 241 A more sophisticated approach is to obtain the longest labeling and transpo. labels. max procedure reverse(s) initial { static labels. mapping techniques also provide a clear characterization of the characterize the reversal of two-character strings. left(labels. ∗s – max)) || map(trans. this has the form map(trans. since the procedures are relatively complicated and many transposi- tions can be written concisely using more conventional techniques. The procedure reverse() can be modified to perform the bootstrapping in its initial clause: procedure swap(s) static labels. The two procedures differ in the way that substrings of sition strings by bootstrapping. For example. ∗s). First. The extension of this transposition transposition process. Consider a transposition in which every odd- numbered character is swapped with its even-numbered neighbor. s3) map("214365". . If these two constraints are relaxed. to the reversal of strings of arbitrary length depends on the way substrings of labels and trans are selected and on the handling of the case in which s is too long to be Positional Transformations transposed by a single call of map(). trans. especially when the same trans := "21" transposition is performed many times. the corresponding characters in s3 are omitted from which is the same labeling as used for reversal. labels := "12" trans := "21" The strings trans and labels do not have to be the same size. it calls itself to change short values of labels and trans to the longest possible values.

"a" might correspond to the ace of clubs. they need not be distinct. then only 256 different characters. One approach is: added to the result. suits) LABELINGS produces a string showing the suit of each card in deck. 13) || repl("H". the mapping map(deck. procedure shuffle(deck) map("Hh:Mm:Ss". their use for labeling objects is limited. "123". For instance. followed by the two. if the denomina- In the preceding sections. queen. and king. Suppose that in a “fresh” deck the first 13 characters are clubs. "12345678". "123". these characters are consider shuffling a deck of cards. the correspondence between characters and individual playing cards anything. 20 Mappings and Labelings 243 map("124578". If there are characters in trans that do not occur in labels. 242 Mappings and Labelings Chap. Characters can also be used to stand for objects. Since a standard deck of playing cards consists of 52 different cards. "HhMmSs". "03:56:42") deck := string(&letters) produces "035642". the second 13 are Characters in labels also can be duplicated in trans. Therefore. 13) || repl("D". For example. Similarly. Furthermore. and so on. but when they can be used they often allow a compact representation and efficient manipulation. Since there are and so on through the jack. 20 Chap. For example. s3) To illustrate the ease of performing computations on such a representation. "beeeeee". fresh. the implied correspon- produces the first and last characters of strings s3 of length seven. In cases like this. end map("be". s3) In order to display a shuffled deck or any hand of cards. 13) || repl("S". "Hh:Mm:Ss". An example is: and map("123321". denoms) . such as map("124578". deck[?i] :=: deck[i] If labels contains duplicate characters. s3. "12345678". used in the mapping map(deck. Consequently. labels that are more mnemonic make the intent clearer. s3) fresh := string(&letters) produces the three-character string s3 followed by its reversal. and so on. "n" to the ace of diamonds. s3) Manipulating Decks of Cards deletes the third and sixth characters of an eight-character string. 4) Two examples follow. denoms := repl("A23456789TJQK". characters are used as labels to identify positions of tions in each suit of a fresh deck are arranged with the ace first. characters in strings. 13) which produces " – ∗||∗ –" . the rightmost correspondences with return deck characters in s3 apply. "b" to the two of clubs. map("HhMmSs". An equivalent positional transformation is: is arbitrary. dence between characters and cards must be converted to a readable format. diamonds. "–∗|") suits := repl("C". "035642") local i every i := ∗deck to 2 by –1 do produces "03:56:42". it is a natural candidate for representation by characters. Then if map("123321". the labels that correspond to deleted characters can be In this string. fresh.

If the first 13 cards in a fresh deck are clubs. fresh. 20 Mappings and Labelings 245 produces a string showing the denomination of each card in deck. and so maps all clubs in hand into distinct characters and all other characters in hand into on. Any blanks are condensed into a single blank which. If the number of nodes fresh := string(&letters) in a graph is small and only the structural properties of graphs are of interest. 13) can be represented by labeling each node with a different character. clubs) where "ab" represents the arc from a to b. One way to extract all the cards of a given suit from a hand is to map all characters that are not in that suit into a single character. Consider the a b d problem of displaying a bridge hand in the conventional way. the graph write(map(deck. procedure disp(deck) Manipulating Graphs static fresh. corresponding clubs and diamonds are mapped into the same characters. in order } according to the direction of the arc. This blank is essentially “invisible”. 13) || repl("S". 39) can be represented by the string characterizes the clubs. suits. If hand contains characters from fresh. A blank provides a convenient representation for all cards in the suits that are not of interest. spaces. fresh. 4) node to another can be represented by the two characters for the nodes. suits)) # suits write(map(deck. 26) ∗g / 2 in a similar manner. fresh. 13) || repl("H". clubs))) . For example.244 Mappings and Labelings Chap. For example. Furthermore ∗cset(g) string(cset(map(hand. 20 Chap. procedure for displaying the cards with suits on one line and denominations below because of the order of the ASCII characters. is at the beginning of the resulting is: string. In many initial { cases. fresh. Characters that do not correspond to clubs are “filtered out”. An arc from one denoms := repl("A23456789TJQK". then in ASCII f clubs := "ABCDEFGHIJKLM" || repl(" ". a considerably more concise representation is possible. 13) || repl("D". Diamonds can be obtained by using Many computations are particularly simple if such a representation is used. A complete places the clubs in order. "bd" represents the arc from b to d. denoms Chapter 19 presented a general way of representing directed graphs. Since the same string is used to label the characters in both suits. denoms)) #denominations end A typical display might be: c e CDCHS S … 5 3 K T Q8 … While such a display is understandable. then g := "abbdbfcacbcedddf" map(hand. These and the number of nodes is given by characters correspond to the ranks of the card in the suit: Cards of the same rank in different suits are mapped into the same character. a graph suits := repl("C". it is not attractive. with each suit given separately. 13) || "ABCDEFGHIJKLM" || repl(" ". the number of arcs in a graph g is given by diamonds := repl(" ".

For example. nodes) local snodes snodes := ' ' # start with none Syntax graph ? repeat { if tab(any(nodes)) then snodes ++:= move(1) else move(2) | break # exit at end of string } return snodes end The successor of every odd-numbered character in graph that is contained in nodes The description of the syntax of Icon that follows uses an italic typeface to denote is added to snodes by the augmented assignment operation.246 Mappings and Labelings Chap. A Syntax 247 This representation assumes there is no isolated node that has no arc into it or out of it. so that expands the set of nodes that can be reached from it until no new nodes are added: ( expressionopt ) procedure closure(graph. snodes := nodes # start with given nodes Alternatives are denoted by vertical stacking. end a program is a sequence of one or more declarations. while snodes ~=== (nodes ++:= successors(graph. Note that at each step all the successors that can be reached from any node currently in the closure are added to the closure. The first step in determining transitive closure is to obtain the immediate successors of a set of nodes (those to which there is an arc from any of the nodes in the set): procedure successors(graph. 247 . syntactic classes. An optional symbol is denoted by the subscript opt. 20 App. nodes) local snodes denotes an optional expression that is enclosed in parentheses. such as program. In effect. a separate list of nodes is necessary. If such a node exists. and a sans serif typeface to denote literal program Transitive closure starts with the single node of interest and successively text. nodes)) do program: snodes := nodes # update if changed declaration declaration program return nodes defines a program to be a declaration or a declaration followed by a program. such as global. Computing transitive closure illustrates the methods of manipulating this A representation of directed graphs.

identifier [ ] identifier [ ] . proc-list field-list: field-name global-declaration: field-name . A App. expression-sequence identifier . 248 Syntax App. field-list global identifier-list expression-sequence: identifier-list: expressionopt identifier expressionopt . A Syntax 249 PROGRAMS locals: local-specification identifier-list . declaration: local-specification identifier-list . link-list invocation-expression mutual-evaluation-expression file-name: prefix-expression identifier infix-expression string-literal to-by-expression create-expression procedure-declaration: return-expression header localsopt initial-clauseopt expression-sequenceopt end break-expression next-expression header: case-expression procedure identifier ( parameter-listopt ) . invocable all invocable proc-list record-declaration: proc-list: record identifier ( field-listopt ) string-literal string-literal . identifier-list expression: link-declaration: parenthesized-expression link link-list compound-expression list-expression link-list: field-reference-expression file-name subscripting-expression file-name . locals global-declaration invocable-declaration local-specification: link-declaration local procedure-declaration static record-declaration initial-clause: invocable-declaration: initial expression . if-then-else-expression loop-expression parameter-list: identifier identifier-list keyword literal identifier-list .

case-list expression –: expression case-clause: invocation-expression: expression : expression expressionopt ( expression-list ) default : expression expressionopt { expression-list } if-then-else expression: mutual-evaluation-expression: if expression then expression else-clauseopt ( expression-list ) else-clause: prefix-expression else expression prefix-operator expression loop-expression: infix-expression repeat expression expression infix-operator expression while expression do-clauseopt until expression do-clauseopt to-by expression: every expression do-clauseopt expression to expression by-clauseopt by-clause: by expression . field-name next-expression: next subscripting-expression: expression [ expression-list ] case-expression: expression [ range-specification ] case expression of { case-list } range-specification: case-list: expression : expression case-clause expression +: expression case-clause .250 Syntax App. A App. A Syntax 251 parenthesized-expression: create-expression: ( expressionopt ) create expression compound-expression: return-expression { expression-sequence } return expressionopt suspend expressionopt do-clauseopt list-expression: fail [ expression-list ] do-clause: expression-list: do expression expressionopt expressionopt . expression-list break-expression: break expressionopt field-reference-expression: expression .

which may be followed quoted-literal by any number of letters. Keyword meanings are summarized in Appendix D. which are lowercase. The syntax for field names is the same as the syntax for identifiers. Upper. keywords. There are two categories of literals: Identifiers literal: numeric-literal An identifier must begin with a letter or an underscore. are: inclusive. A App. and digits. underscores. where &allocated &errorvalue &phi a stands for 10. Numeric literals. reserved Literals words. &collections &features &progname Real literals have two forms: &cset &file &random &current &host &regions real-literal: &date &input &source decimal-literal &dateline &lcase &storage exponent-literal &digits &letters &subject &dump &level &time decimal-literal: &e &line &trace &error &main &ucase digit-literal . digit-literal &errortext &output . 252 Syntax App. and so forth through z.and lowercase letters are distinct. The value of the digit literal specifies the radix and must be between 2 and 36. The reserved words are: Integer literals have two forms: break global record integer-literal: by if repeat digit-literal case initial return radix-literal create invocable static default link suspend Digit literals consist of one or more digits. The characters in digit specifications must &clock &fail &pos stand for values that are less than the radix. Upper. Radix literals allow the radix for digits to do local then be specified: else next to end not until radix-literal: every of while digit-literal radix-specification digit-specification fail procedure radix-specification: Keywords r R Keywords consist of an ampersand followed by one of a selected set of identifiers. and literals. in turn. Reserved words are all lowercase. are divided into two categories: numeric-literal: Reserved Words integer-literal real-literal Reserved words may not be used as identifiers or field names. The keywords. A Syntax 253 LANGUAGE ELEMENTS Note: Keywords related to graphics are not included in the list above. The digit specification consists of a sequence of digits and letters.and lowercase letters &ascii &errout &pi in digit specifications are equivalent. b stands for 11. digit-literalopt &errornumber &null &version digit-literalopt . The most elementary components of Icon expressions are identifiers.

and \xa is equivalent to \x0a. blanks and tabs serve as white space to separate tokens that double quote may not appear within the enclosing quotes unless it is escaped. Quoted literals are divided into two categories: If the character following a backslash is not one of those in the preceding list. \a stands for a. A single quote may not appear within the enclosing quotes unless it is escaped. Blanks and tabs can also be \e escape used as optional separators to improve the visual appearance of a program. accommodate the terminologies of different computer systems. …. quoted-literal: cset-literal string-literal PROGRAM LAYOUT A cset literal consists of a string of characters enclosed in single quotes. Specifically. since ifnot is interpreted as an identifier rather than two reserved words. Only enough digits need to be exponent-specification: given to specify the desired octal or hexadecimal number. The Icon compiler resolves such \" double quote potential ambiguities by taking the longest legal sequence of operator symbols to be \\ backslash a single token. A comment is considered to be white space by the Icon compiler. as concatenation or as alternation followed by \' single quote repeated alternation of the second expression. Upper. \^c control code A #.and lowercase hexadecimal digits. Escape sequences allow characters to be included in string literals that other- wise would be awkward or impossible to include. For + example. Program text that has no meaning in itself is collectively called “white space”. where d is an digit-literal exponent-specification signopt digit-literal octal digit 0. For example. A Except in quoted literals. Escape White Space sequences are described below. otherwise could be construed as a single token. \b backspace Blanks and tabs otherwise have no significance. 7. A string literal consists of a string of characters enclosed in double quotes. \43 E specifies the ASCII character #. …. A App. 1. Blanks \f formfeed or tabs are necessary to separate infix operators from prefix operators in situations \l linefeed that are ambiguous. where d is a hexadecimal digit 0. 1. \^A stands for control-A. A blank between the \ddd octal code two bars would cause the expression to be interpreted as alternation followed by \xdd hexadecimal code repeated alternation. For example. introduces a comment. the backslash is ignored. a. . … f. such as a and A. The escape sequences and the characters that they stand for are: is syntactically erroneous. \^c stands for the character corre- – sponding to the five low-order bits of c. blanks and tabs \d delete can appear between a prefix operator and its argument. A Syntax 255 exponent-literal: The sequence \ddd stands for the character with octal code ddd. both are included to end of the line. For example. For example. provided the characters e that follow cannot be interpreted as part of the escape sequence. \n newline \r return expr1||expr2 \t horizontal tab \v vertical tab might be interpreted in two ways.254 Syntax App. An escape sequence consists of a ifnot expr1 then expr2 backslash followed by one or more characters that have special meanings. are equivalent. The sequence \xdd stands for the character with hexadecimal decimal-literal exponent-specification signopt digit-literal code dd. which terminates at the The linefeed and newline characters are the same in ASCII. so this example is interpreted as concatenation. Therefore. sign: The control code sequence \^c stands for the ASCII character control-c. except in a quoted literal.

… ) The compiler does not insert a semicolon at the end of the first line. / expr \ expr Identifiers can be arbitrarily long. lines separate groups. In the case of an infix operation. expr2. Associativity determines whether operations x := 1. Those that associate to the right are marked in splitting an expression between two lines. A App. Precedence determines how different operators. || expr2 – expr . However. y := 2. … ] expr1 [ expr2 : expr3 ] expr1 || expr1 [ expr2 +: expr3 ] expr2 expr1 [ expr2 –: expr3 ] expr ( expr1. care must be taken Most infix operators are left-associative. If a ~ expr quoted literal is continued in this way.256 Syntax App. expr2. Therefore. expr2. operator should be placed at the end of the first line. the as such. However. expr2. in ___________________________________ expr1 not expr || expr2 | expr ! expr a semicolon is inserted at the end of the first line. Because the compiler inserts semicolons at the ends of lines where possible. but they must be contained on one line. expr3. cons := "abcdfghjklmnopqrstvwxyz" x := 1 y := 2 z := 0 PRECEDENCE AND ASSOCIATIVITY is equivalent to Icon has many operators. but it automati- cally inserts a semicolon at the end of a line if an expression ends on that line and the is equivalent to next line begins with another expression. ^ expr ___________________________________ . z := 0 group to the left or to the right. The list that follows gives operators by precedence from highest to lowest. Here || is two prefix repeated alternation operators. expr is syntactically correct. group with their arguments. … ] expr. in com- bination. … } expression at the end of that line is not complete. not the beginning of the second. it Operators with the same precedence are grouped together. A Syntax 257 Semicolons and Line Breaks cons := "abcdfghjklmno_ pqrstvwxyz" The Icon compiler generally is indifferent to program layout. ( expr ) { expr1. A = expr quoted literal can be continued from one line to the next by placing an underscore ? expr after the last character of the literal on a line and omitting the closing quote. the underscore as well as any white space at @ expr the beginning of the next line are ignored. … } expr1 || expr2 [ expr1. usually is not necessary to use semicolons explicitly. since ∗ expr + expr expr1. Therefore. since the expr { expr1. f should be split as expr1 [ expr2. For example.

expr3 : expr4. … } expr1 ++ expr2 create expr expr1 – – expr2 every expr1 do expr2 ___________________________________ fail if expr1 then expr2 else expr3 expr1 || expr2 next expr1 ||| expr2 repeat expr ___________________________________ return expr expr1 < expr2 suspend expr1 do expr2 expr1 <= expr2 until expr1 do expr2 expr1 = expr2 while expr1 do expr2 expr1 >= expr2 expr1 > expr2 expr1 ~= expr2 expr1 << expr2 expr1 <<= expr2 expr1 == expr2 expr1 >>= expr2 expr1 >> expr2 expr1 ~== expr2 expr1 === expr2 expr1 ~=== expr2 ___________________________________ expr1 | expr2 ___________________________________ expr1 to expr2 by expr3 ___________________________________ . A App.258 Syntax App. A Syntax 259 expr1 \ expr2 expr1 := expr2 (right associative) expr1 @ expr2 expr1 <– expr2 (right associative) expr1 ! expr2 expr1 :=: expr2 (right associative) ___________________________________ expr1 <–> expr2 (right associative) expr1 op:= expr2 (right associative) expr1 ∧ expr2 (right associative) ___________________________________ ___________________________________ expr1 ∗ expr2 expr1 ? expr2 expr1 / expr2 ___________________________________ expr1 % expr2 expr1 & expr2 expr1 ∗∗ expr2 ___________________________________ ___________________________________ expr1 + expr2 break expr expr1 – expr2 case expr of { expr1 : expr2.

B Characters 261 B Characters Characters serve two purposes: the representation of text using glyphs and control operations. 261 . One standard set of glyphs. A collection of glyphs is called a font. is defined by ISO8859-1 (ISO. using different glyphs or associating them with different character codes. This set is used on most UNIX worksta- tions. digits. This allows the use of characters from various languages. and common punctuation marks is based on the 7-bit ASCII character set (American National Standards Institute. as well as various symbols. 1986) that assigns glyphs and other interpretations to the first 128 characters. For textual material. App. Thousands of different fonts are available for various computer platforms. Various computer platforms extend ASCII in different ways. Many sets of glyphs are used for purposes ranging from textual material to pictograms and printer’s ornaments. GLYPHS The glyphs assigned to character codes associate meaning with the codes. It is now common to assign glyphs to the 128 remaining characters. which includes ASCII as a subset. 1987) and is called Latin-1. on most computer platforms the underlying interpreta- tion for letters.

columns one through three show the decimal. 044 054 2c 045 055 2d 046 056 2e dec. there is the EBCDIC character set (Ralston and Reilly. 1993) used on 032 040 20 033 041 21 IBM mainframes. Finally. the last 042 052 2a two columns show the Macintosh versions of symbols and printer ornaments 043 053 2b (“dingbats”). 1991) dec. 039 047 27 and hexadecimal values for codes. Finally. The most commonly used one is shown in the table in this 036 044 24 appendix. Several different versions of 035 043 23 EBCDIC are in use. B App. The Latin-1 encoding is shown in column four. 037 045 25 038 046 26 In the table that follows. The seventh column shows ECS. and the eighth EBCDIC. oct. Latin-1 Macintosh Windows ECS EBCDIC symbols dingbats is used by MS-DOS in the absence of other fonts. called ECS (“extended character set”) (Microsoft. 040 050 28 Columns five and six show typical text fonts for the Macintosh and Microsoft 041 051 29 Windows. and common punctuation 034 042 22 marks to different character codes than ASCII does. Latin-1 Macintosh Windows ECS EBCDIC symbols dingbats 047 057 2f 048 060 30 000 000 00 049 061 31 001 001 01 b 050 062 32 002 002 02 a 051 063 33 003 003 03 c 052 064 34 004 004 04 d 053 065 35 005 005 05 e 054 066 36 006 006 06 f 055 067 37 007 007 07 g 056 070 38 008 010 08 h 057 071 39 009 011 09 i 058 072 3a 010 012 0a j 059 073 3b 011 013 0b k 060 074 3c 012 014 0c l 061 075 3d 013 015 0d m 062 076 3e 014 016 0e n 063 077 3f 015 017 0f o 064 100 40 016 020 10 p 065 101 41 017 021 11 q 066 102 42 018 022 12 r 067 103 43 019 023 13 s 068 104 44 020 024 14 t 069 105 45 021 025 15 u 070 106 46 022 026 16 v 071 107 47 023 027 17 w 072 110 48 024 030 18 x 073 111 49 025 031 19 y 074 112 4a 026 032 1a z 075 113 4b 027 033 1b { 076 114 4c 028 034 1c | 077 115 4d 029 035 1d } 078 116 4e 030 036 1e ~ 079 117 4f 031 037 1f 0 . digits. B Characters 263 Another set of glyphs. It assigns glyphs for letters. octal. hex. hex. 262 Characters App. oct.

264 Characters App. B Characters 265 dec. oct. Latin-1 Macintosh Windows ECS EBCDIC symbols dingbats dec. oct. B App. hex. hex. Latin-1 Macintosh Windows ECS EBCDIC symbols dingbats 080 120 50 128 200 80 081 121 51 129 201 81 082 122 52 130 202 82 083 123 53 131 203 83 084 124 54 132 204 84 085 125 55 133 205 85 086 126 56 134 206 86 087 127 57 135 207 87 088 130 58 136 210 88 089 131 59 137 211 89 090 132 5a 138 212 8a 091 133 5b 139 213 8b 092 134 5c 140 214 8c 093 135 5d 141 215 8d 094 136 5e 142 216 8e 095 137 5f 143 217 8f 096 140 60 144 220 90 097 141 61 145 221 91 098 142 62 146 222 92 099 143 63 147 223 93 100 144 64 148 224 94 101 145 65 149 225 95 102 146 66 150 226 96 103 147 67 151 227 97 104 150 68 152 230 98 105 151 69 153 231 99 106 152 6a 154 232 9a 107 153 6b 155 233 9b 108 154 6c 156 234 9c 109 155 6d 157 235 9d 110 156 6e 158 236 9e 111 157 6f 159 237 9f 112 160 70 160 240 a0 113 161 71 161 241 a1 114 162 72 162 242 a2 115 163 73 163 243 a3 116 164 74 164 244 a4 117 165 75 165 245 a5 118 166 76 166 246 a6 119 167 77 167 247 a7 120 170 78 168 250 a8 121 171 79 169 251 a9 122 172 7a 170 252 aa 123 173 7b 171 253 ab 124 174 7c 172 254 ac 125 175 7d 173 255 ad 126 176 7e 174 256 ae 127 177 7f 175 257 af .

hex. 266 Characters App. hex. B Characters 267 dec. Latin-1 Macintosh Windows ECS EBCDIC symbols dingbats 176 260 b0 224 340 e0 177 261 b1 225 341 e1 178 262 b2 226 342 e2 179 263 b3 227 343 e3 180 264 b4 228 344 e4 181 265 b5 229 345 e5 182 266 b6 230 346 e6 183 267 b7 231 347 e7 184 270 b8 232 350 e8 185 271 b9 233 351 e9 186 272 ba 234 352 ea 187 273 bb 235 353 eb 188 274 bc 236 354 ec 189 275 bd 237 355 ed 190 276 be 238 356 ee 191 277 bf 239 357 ef 192 300 c0 240 360 f0 193 301 c1 241 361 f1 194 302 c2 242 362 f2 195 303 c3 243 363 f3 196 304 c4 244 364 f4 197 305 c5 245 365 f5 198 306 c6 246 366 f6 199 307 c7 247 367 f7 200 310 c8 248 370 f8 201 311 c9 249 371 f9 202 312 ca 250 372 fa 203 313 cb 251 373 fb 204 314 cc 252 374 fc 205 315 cd 253 375 fd 206 316 ce 254 376 fe 207 317 cf 255 377 ff 208 320 d0 209 321 d1 210 322 d2 211 323 d3 212 324 d4 213 325 d5 214 326 d6 215 327 d7 216 330 d8 217 331 d9 218 332 da 219 333 db 220 334 dc 221 335 dd 222 336 de 223 337 df . oct. Latin-1 Macintosh Windows ECS EBCDIC symbols dingbats dec. B App. oct.

such as backspacing and tabbing. 268 Characters App. 016 020 10 control-p 017 021 11 control-q A source line is a preprocessor directive if its first non-white-space character 018 022 12 control-r is a $ and if that $ is not followed by another punctuation character. 031 037 1f control-_ INCLUDE DIRECTIVES An include directive has the form $include filename 269 . as in Icon 024 030 18 control-x proper. The general form 019 023 13 control-s of a preprocessor directive is 020 024 14 control-t 021 025 15 control-u $directive arguments # comment 022 026 16 control-v 023 027 17 control-w White space separates tokens when needed. or expression boundaries. 029 035 1d control-] Preprocessor directives can appear anywhere in an Icon source file without 030 036 1e control-^ regard to procedure. These are shown in the following table. If no preprocessor directives are present. and case is significant. coding function 000 000 00 control-@ null Preprocessing 001 001 01 control-a 002 002 02 control-b 003 003 03 control-c 004 004 04 control-d 005 005 05 control-e 006 006 06 control-f 007 007 07 control-g bell 008 010 08 \b control-h backspace 009 011 09 \t control-i tab 010 012 0a \n control-j linefeed 011 013 0b \v control-k vertical tab 012 014 0c \f control-l formfeed All Icon source code passes through a preprocessor before compilation. the source code passes through 015 017 0f control-o the preprocessor unaltered. which cannot 025 031 19 control-y be continued but can be arbitrarily long. dec. escape seq. oct. Preproces- 013 015 0d \r control-m return sor directives control the actions of the preprocessor and are not passed to the Icon 014 016 0e control-n compiler. The entire preprocessor directive must appear on a single line. An 026 032 1a control-z 027 033 1b \e control-[ escape invalid preprocessor directive produces an error except when skipped by condi- 028 034 1c control-\ tional compilation. These characters have C associated names and functions. B App. hex. The comment portion is optional. declaration. C Preprocessing 269 ASCII CONTROL CHARACTERS The first 32 characters in ASCII are called control characters and are entered by depressing the control key while typing another character.

It is possible to define replacement text for Icon reserved words or keywords.0 is not the same as Predefined symbols have no special status. but they do not persist from one source file to another. The text must match exactly: For example. crossing include boundaries. It is are interpreted in the preprocessor’s context and not in relation to the including file’s not an error to undefine a nonexistent name. replacement text is scanned for defined identifiers. The line containing the preprocessing directive is considered to be line n of the given file (or the current file. if unspecified) for diagnostic and other purposes. The most commonly used $line n filenameopt predefined symbols are listed below. allowing its redefinition if desired. they can be 3. Note that the Icon preprocessor does not provide parameterized As input is read. If a feature is absent. but recognition of the original identifier name is disabled to prevent infinite recursion. The file name must be quoted if it is not in the form of an Icon identifier. but a file may not include itself either directly or indirectly. .000. text is any sequence of characters except that any _PRESENTATION_MGR Presentation Manager string or cset literals must be properly terminated within the definition. the value replaces the identifier in the input stream. Relative paths The current definition of name is removed. If it does. possibly causing further substi- tution. PREDEFINED SYMBOLS LINE DIRECTIVES At the start of each source file. and Townsend (1996) for a complete list. the symbol is defined with a value of 1. Jeffery. File names are looked for first in the current directory $undef name and then in the directories listed in the environment variable LPATH. 3. The but this generally is dangerous and ill-advised. An undefine directive has the form Included files may be nested to arbitrary depth. each identifier is checked to see if it matches a previously defined definitions. it must be separated from the name by at least one space. If a feature is present. _PIPES pipes Duplicate definition of a name is allowed if the new text is exactly the same as _SYSTEM_FUNCTION system function the old text. SUBSTITUTION If the text begins with a left parenthesis. The text can be empty. This prevents problems from arising if a file of definitions is included more than once. Definitions remain in effect through the end of the current original source file. Like other symbols. Leading and _X_WINDOW_SYSTEM X Windows trailing white space are not part of the definition. location. See Griswold. symbol. undefined and redefined. the symbol is not defined. C Preprocessing 271 An include directive causes the contents of the specified file to be interpolated in the UNDEFINE DIRECTIVES source file. several symbols are automatically defined to indicate A line directive has the form the Icon system configuration. C App. The file name must be quoted if it is not in the form of an Icon identifier. No white space is added or deleted when a definition is inserted. The line predefined symbol &features value number is a simple unsigned integer. 270 Preprocessing App. _MACINTOSH Macintosh _MSDOS MS-DOS _MSDOS_386 MS-DOS/386 DEFINE DIRECTIVES _MS_WINDOWS_NT MS Windows NT _OS2 OS/2 A define directive has the form _UNIX UNIX _VMS VMS $define name text _WINDOW_FUNCTIONS window functions The define directive defines the text to be substituted for later occurrences of the _MS_WINDOWS MS Windows identifier name in the source code.

C Occurrences of defined names within comments. have different syntactic The $else section is optional. infix (binary) operators. or preprocessor directives are not altered. they are intended for reference only. L. and keywords perform computations. They are divided into prefix (unary) operators. operators. operator expects and the type it returns. Different operators. App. $ifdef succeeds if a definition exists. By then it is too late. Keywords all have a common syntax. S. D Substitution cannot produce a preprocessor directive. $ifdef name or $ifndef name … code to use if test succeeds … The operations fall into four main categories: functions. or T) typically used with conditional compilation to indicate an improper set of defini. The descriptions are A conditional block has this general form: brief. Operations related to graphics are not included. The preprocessor is ignorant of multi-line string literals. especially the types of data a function or included conditional blocks are similarly self-contained. D Language Reference Manual 273 272 Preprocessing App. Conditional blocks can be nested provided that all of forms. This operators with distinctive syntax. however. Functions. $ifndef succeeds if a definition does not exist. keywords. Types are indicated by letters as follows: ERROR DIRECTIVES c cset C co-expression f file L list An error directive has the form i integer N numeric (i or r) n null R record (any record type) $error text p procedure S set r real T table An $error directive forces a fatal compilation error displaying the given text. on the other hand. … code to use if test fails … control structures determine the order of expression evaluation. $else and control structures. and it potentially can be fooled by these. x any type tions. This is s string X any structure type (R. 273 . This reference manual summarizes Icon’s built-in repertoire. operators. and the $if/$else/$endif directives for a particular block are in the same source file. literals. CONDITIONAL COMPILATION Conditional compilation directives have the form Language Reference Manual $ifdef name and $ifndef name $ifdef or $ifndef cause subsequent code to be accepted or skipped depending on whether name has been previously defined. Function names $endif provide a vocabulary with a common syntax in which computations are performed on argument lists. does not prevent the conditional inclusion of other files via $include as long as any Data types are important in Icon. The value of the definition does not matter.

A list of generators appears at the end of this appendix. s2) the function may be called repeatedly with different argument values. since the string "10" is converted to the integer 10. i. argument fails. i2) succeeds and produces the position of the first character in s[i1:i2] if this information is shown. For 104 c not cset example. 1. so the types of arguments may be different from the expected type 205 |r1| greater than 1 and still be acceptable. s2) produce the same result. s2. There also are cross references among operators and control structures with similar syntax. The format of entries for operators and keywords is similar. see the entry for center() for i1 &pos if s is defaulted. " "). 10. indicates that center() has three arguments. otherwise it fails. …. See also: cos() Default values are provided automatically in some cases when an argument is omitted (or has the null value). sn to 1. abs(N1) : N2 compute absolute value The type of the result produced by a function follows the function prototype. The possible errors and their causes Defaults: s &subject are listed for each function and operation. left(). Consequently. If an argument generates more than one value. such as ∗x and N1 ∗ N2. otherwise 1 examples. Errors may occur for a variety of reasons. The arguments of functions are evaluated from left to right. For example. note that a phrase such as “s not string” means s is neither i2 0 a string nor a type that can be converted to a string. D App. the second is an integer. s. with a separating colon. converting a very long string to an integer for use in a numerical compu- See also: many() and match() tation conceivably could run out of memory. . abs(N1) produces the absolute value of N1. as in acos(r1) produces the arc cosine of r1 in the range of 0 to π for r1 in the range of –1 !s : s1. For example. Again. s2) and center(s1. center(s1. If the evaluation of an Numeric suffixes are used to distinguish different arguments of the same type. i1. In particular. s. such as center(). acos(r1) : r2 compute arc cosine The results for generators are indicated by a sequence. i1. that character is in c. For example. center(s1. i. s2) : s3 Error: 102 N1 not numeric indicates that center() produces a string. Cross references among entries have two forms. Icon performs type conversion automatically if an argument does not have the Errors: 102 r1 not real expected type. and right(). Refer to the entry for center() to see how any(c. center(s1. The first and third are strings. the default for the second argument of any(c. while the third argument defaults to a single blank. center(s1) is equivalent to center(s1. an error also can occur 103 s not string if there is not enough memory to convert an argument to the expected type. Most cross references refer to functions and operators that perform related computations. D Language Reference Manual 275 In addition. i2) : i3 locate initial character center() is 1. Such errors are unlikely and are not listed. of results for a given set of arguments. the function is not called. Errors: 101 i1 or i2 not integer In addition to the errors listed in the entries that follow. "10". even though the computations per- formed are not related. the symbol v indicates a situation in which a variable is required or FUNCTIONS always produced.274 Language Reference Manual App. Some functions may generate a sequence For example.

For procedures with a 104 c1. character of c1 in s[i1:i2] that is balanced with respect to characters in c2 and c3. c2. i4. See also: find() and upto() Error: 106 p not procedure See also: proc() center(s1. c2. i2) : i3. i2) generates the sequence of integer positions in s preceding a termination depends on the operating system. s. If f is a pipe. D App. in locate balanced characters the change cannot be made. the value returned is the negative of the number of formal parameters. i. c3. inclusive Error: 102 r1 or r2 not real See also: ord() See also: tan() chdir(s) : n change directory chdir(s) changes the current directory to s but fails if there is no such directory or if bal(c1. the value s &subject returned is the exit code. i1. s2) : s3 position string at center center(s1. s2) produces a string of size i in which s1 is centered.276 Language Reference Manual App. asin(r1) : r2 compute arc sine Defaults: i 1 asin(r1) produces the arc sine of r1 in the range of –π/2 to π/2 for r1 in the range –1 s2 " " (blank) to 1. If f is an ordinary file. or c3 not cset variable number of arguments. Defaults: c1 &cset c2 '(' close(f) : x close file c3 ')' close(f) closes f. of r1. …. the value returned is f. with s2 used for padding at left and right as necessary. Whether the change in directory persists after program bal(c1. i. r2) produces the arc tangent of r1 / r2 in the range of –π to π with the sign char(i) produces a one-character string whose internal representation is i. but Error: 103 s not string fails if there is no such position. otherwise 1 i2 0 Error: 105 f not file See also: flush() and open() . Errors: 101 i not integer Default: r2 1. i1. s. D Language Reference Manual 277 args(p) : i get number of procedure arguments Errors: 101 i1 or i2 not integer 103 s not string args(p) produces the number of arguments for procedure p. c2. Errors: 101 i not integer Errors: 102 r1 not real 103 s1 or s2 not string 205 |r1| greater than 1 205 i<0 See also: sin() See also: left() and right() atan(r1. c3. i1 &pos if s is defaulted. r2) : r3 compute arc tangent char(i) : s produce character atan(r1.0 205 i not between 0 and 255.

103 s1 not string 210 i1. dtor(r1) : r2 convert degrees to radians delay(i) : n delay execution dtor(r1) produces the radian equivalent of r1 given in degrees. in not positive or in increasing sequence See also: entab() copy(x1) : x2 copy value copy(x1) produces a copy of x1 if x1 is a structure. x) : X delete element collect(i1. in) produces a string based on s1 in which each tab character is of i2 is ignored for the static region. Tab stops are at i1. f) writes the image of the current co-expression and the values of the local cos(r1) : r2 compute cosine variables in the current procedure call. The regions are identified for key x from X. D App. i2. a collection is done. in) : s2 replace tabs by blanks If i1 is 0. D Language Reference Manual 279 collect(i1. i1 region See also: insert() and member() 1 static 2 string 3 block detab(s1. Error: 102 r1 not real Error: 101 i not integer See also: rtod() . but no region is identified and i2 has no effect. displayed. delete(X. otherwise it produces x1. the values of global variables are displayed. in not integer 205 i1 not between 0 and 3 inclusive or i2 < 0. Output is written to f. i1. i2. the local variables in the i preceding procedure calls are displayed as well. …. in. but fails if the conversion is not 213 f not open for writing possible. i2 0 Default: i1 9 Errors: 101 i1 or i2 not integer Errors: 101 i1. If X is a table. If i is greater than 0. i2. f) : n display variables display(i. After all local variables are cos(r1) produces the cosine of r1 in radians. i1. The value detab(s1. with additional stops Defaults: i1 0 obtained by repeating the last interval. x) produces X. delete(X. It fails if the requested space is not available. …. …. i2) causes a garbage collection in region i1. i2. i2) : n perform garbage collection delete(X. requesting i2 bytes of space in If X is a set. i2. as follows: Error: 122 X not set or table. x) deletes the element that region. …. replaced by one or more blanks. display(i. …. delete(X. delay() delays program execution i milliseconds.278 Language Reference Manual App. Error: 102 r1 not real Defaults: i &level See also: cos() f &errout Errors: 101 i not integer 105 f not file cset(x) : c convert to cset 205 i<0 cset(x) produces a cset resulting from converting x. x) deletes x from X.

…. i1. i1. …. D App. pull(). and put() exp(r1) : r2 compute exponential getch() : s get character exp(r1) produces e raised to the power r1. getch() waits until a character has been entered from the keyboard and then produces the corresponding one-character string.. in) : s2 replace blanks by tabs i1 &pos if s2 is defaulted. 103 s1 or s2 not string Default: i1 9 See also: bal(). 204 overflow See also: getche() and kbhit() See also: log() and N1 ^ N2 getche() : s get and echo character find(s1. i2. D Language Reference Manual 281 Defaults: s2 &subject entab(s1. match().280 Language Reference Manual App.. Error: 101 i not integer Error: 108 L not list See also: stop() See also: pop(). i2) : i3. get is a synonym for pop. . The as a substring in s2[i1:i2]. The character is not displayed. i2. i2. i4. in find string getche() waits until a character has been entered from the keyboard and then find(s1. …. in not integer 103 s1 not string 210 i1. get(L) produces the leftmost element of L and removes it from L. function() : s1. i1. function fails on an end of file. but fails if there is no such position. s2. …. otherwise 1 entab(s1. exit(i) exit program get(L) : x get value from list exit(i) terminates program execution with exit status i. with additional stops obtained by Errors: 101 i1 or i2 not integer repeating the last interval. i2. s2. Errors: 102 r1 not real The function fails on an end of file. and upto() Errors: 101 i1. i2. i2) generates the sequence of integer positions in s2 at which s1 occurs produces the corresponding one-character string. Tab stops are at i1. The character is displayed. but fails if L is Default: i normal exit (machine dependent) empty. See also: close() errorclear() : n clear error indication errorclear() clears the indications of the last error. in) produces a string based on s1 in which runs of blanks are i2 0 replaced by tabs. sn generate function names See also: &error function() generates the names of the Icon (built-in) functions.. …. s2. in. i1. See also: getch() and kbhit() . …. in not positive or in increasing sequence flush(f) : f flush output See also: detab() flush() flushes any accumulated output for file f. push().

ishift(i1. See also: iand(). See also: icom(). insert(X. x1. ior(). kbhit() : n check for keyboard character kbhit() succeeds if a character is available for getch() or getche() but fails otherwise. but fails if the conver- used for padding at the right as necessary. and ixor() Error: 101 i1 or i2 not integer See also: iand(). key(T) : x1. Vacated bit positions are zero-filled. i2) produces the result of shifting the bits in i1 by i2 positions. Positive values Error: 101 i1 or i2 not integer of i2 shift to the left with zero fill. D App. insert(X. i2) produces the bitwise exclusive or of i1 and i2. insert(X. insert(X. ishift(). x2. i2) : i3 compute bitwise exclusive or Error: 101 i1 not integer ixor(i1. i. i2) produces the bitwise inclusive or of i1 and i2. set. x2) produces X. ishift(). i2) : i3 compute bitwise inclusive or getenv(s1) produces the value of the environment variable s1. i. ior(). Defaults: i 1 See also: numeric() and real() s2 " " (blank) . ior(). s2) : s3 position string at left integer(x) : i convert to integer left(s1. x2) : X insert element See also: getch() and getche() If X is a table. sion is not possible. icom(). Error: 101 i1 or i2 not integer Error: 103 s1 not string See also: iand(). …. icom(). xn generate keys from table Default: x2 &null key(T) generates the keys in table T. ior(). and ixor() icom(i1) : i2 compute bitwise complement icom(i1) produces the bitwise complement of i1. icom(). negative values shift to the right with sign extension. and ixor() iand(i1. i2) : i3 compute bitwise and ishift(i1. i2) produces an integer consisting of the bitwise and of i1 and i2. x1. x1. D Language Reference Manual 283 getenv(s1) : s2 get value of environment variable ior(i1. and ishift() image(x) : s produce string image image(x) produces the string image for x. Errors: 122 X not set or table Error: 124 T not table See also: delete() and member() left(s1.282 Language Reference Manual App. s2) produces a string of size i in which s1 is positioned at the left. and ixor() Error: 101 i1 or i2 not integer See also: iand(). i2) : i3 shift bits iand(i1. x2) inserts key x1 with value x2 into X. ixor(i1. ishift(). If X is a set. with s2 integer(x) produces the integer resulting from converting x. but fails if s1 is not ior(i1. x1) inserts x1 into X.

s2. otherwise it fails. Defaults: s2 &subject Errors: 216 function not found i1 &pos if s2 is defaulted. s2) loads the function named s2 from the library file s1 and produces match(s1. i2) : i3 locate many characters See also: delete() and insert() many(c. that is equal to s1. x) succeeds if x is a key of an element in X but fails otherwise. i1. or s3 not string 205 i<0 208 ∗s2 ~= ∗s3 loadfunc(s1. i1. s2. a procedure for it. s2 must be a C or compatible function that provides a particular if any.284 Language Reference Manual App. s2. r2) : r3 compute logarithm 103 s1 or s2 not string log(r1. D Language Reference Manual 285 Errors: 101 i not integer Errors: 101 i1 or i2 not integer 103 s1 or s2 not string 103 s not string 205 i<0 104 c not cset See also: center() and right() See also: any() and match() map(s1. i2) produces the position beyond the initial substring of s2[i1:i2]. move(i) reverses the assignment to &pos if it is resumed. member(X. D App. that occur in s2 into corresponding characters in s3. i2) : i3 match initial string loadfunc(s1. It fails if s[i1] is not in c. any(). i2) succeeds and produces the position in s after the longest initial sequence of characters in c within s[i1:i2]. See also: exp() member(X. and many() Default: r2 e Errors: 102 r1 or r2 not real member(X. Error: 122 X not set or table many(c. s2) : p load external function match(s1. x) : L create list map(s1. See also: =s. s3) produces a string of size ∗s1 obtained by mapping characters of s1 list(i. r2) produces the logarithm of r1 to the base r2. s. interface expected by loadfunc(). s3) : s4 map characters list(i. otherwise 1 move(i) produces &subject[&pos:&pos + i] and assigns &pos + i to &pos. s2. . x) produces x if it succeeds. s. x) succeeds if x is a member of X but fails otherwise. i1. If X is a table. but fails if i2 0 i is out of range. x) produces a list of size i in which each value is x. x) : x test for membership 205 r1 <= 0 or r2 <= 1 If X is a set. move(i) : s move scanning position Defaults: s &subject i1 &pos if s is defaulted. Defaults: i 0 Defaults: s2 string(&ucase) x &null s3 string(&lcase) Errors: 101 i not integer Errors: 103 s1. member(X. otherwise 1 103 s1 or s2 not string i2 0 Errors: 101 i1 or i2 not integer log(r1. i1. s2.

D App. or operator. If the one-character string s. but fails "c" create if s is not the name of one.286 Language Reference Manual App. but fails open(s1. If v is a Errors: 103 s not string subscripted list or table. proc(s. function. See also: get(). in which case conversely on output. numeric(x) produces an integer or real number resulting from converting x. pull(). i) : p convert to procedure "b" open for reading and writing "p" open a pipe proc(s. v is a string. i specifies the number "t" translate line termination sequences to linefeeds of arguments: 1 for unary (prefix). push(). 0) "u" do not translate line termination sequences to linefeeds produces the built-in function named s even if the global identifier having that name has been assigned another value. in s2. 2 for binary (infix). pop is a synonym for get. D Language Reference Manual 287 Error: 101 i not integer Errors: 103 s1 or s2 not string 209 invalid option See also: tab() See also: close() name(v) : s produce name ord(s) : i produce ordinal name(v) produces the name of the variable v. The untranslated mode should be used when reading and proc() simply returns the first argument. The options are: Error: 101 i1 not integer character effect See also: &pos and &subject "r" open for reading "w" open for writing "a" open for writing in append mode proc(s. and 3 for ternary. the name of the string and the subscript range are shown. s2) : f open file pos(i1) produces &pos if i1 or its positive equivalent is equal to &pos. proc(s. The default mode is to translate line termination sequences to linefeeds on input and The first argument of proc() may be a procedure. and put() See also: integer() and real() pos(i1) : i2 test scanning position open(s1. If v is an identifier or a keyword that is a variable. function. or operator corresponding to s. but fails if the file cannot be opened. the record type and field name are produced with a separating period. but fails if L is numeric(x) : N convert to numeric empty. 0) fails if s is not the name of a function. If s is the string name of an operator. the type name followed by the subscripting expression is 205 ∗s not 1 produced. Default: s2 "rt" . See also: char() Error: 111 v not a variable See also: variable() pop(L) : x pop from list pop(L) produces the leftmost element of L and removes it from L. If v is a record field ord(s) produces an integer (ordinal) between 0 and 255 that is the character code for reference. s2) produces a file resulting from opening s1 according to options given otherwise. the name of the identifier or keyword is produced. but fails Error: 108 L not list if the conversion is not possible. writing binary files. i) produces the procedure.

push(L) with no sion is not possible. x2. Errors: 108 L not list rename(s1. reads() should be used for reading binary data. x2. i) produces a string consisting of i concatenations of s1. s2) : n rename file See also: get(). xn) : L push onto list real(x) : r convert to real push(L. …. …. pop(). and put() remove(s) : n remove file remove(s) removes (deletes) the file named s. x1. D Language Reference Manual 289 Default: i 1 reads(f. …. In reads(). xn onto the right end of L. push(). x2. line See also: args() termination sequences have no special significance. put(L. Defaults: f &input i 1 pull(L) : x pull from list Errors: 101 i not integer pull(L) produces the rightmost element of L and removes it from L. or the remaining 205 i not 0. x1. D App. See also: reads() . pop(). i) : s2 replicate string Errors: 105 f not file 212 f not open for reading repl(s1. 2. so xn becomes the first (leftmost) value of L. pull(). x2. but fails if the conver- order from left to right. 1. Error: 103 s1 or s2 not string read(f) : s read line See also: remove() read(f) produces the next line from f but fails on an end of file. put(L) with no second argument puts a null value onto L. x2. …. but fails if the renaming cannot be done. pop(). i) : s read string Errors: 101 i not integer reads(f. Default: f &input repl(s1. See also: integer() and numeric() Errors: 108 L not list See also: get(). and push() rename(s1. Values are added in See also: rename() order from left to right. pull(). unlike read(). onto the left end of L. i) produces a string consisting of the next i characters from f. and put() See also: read() push(L. but fails if L is 105 f not file empty. xn) pushes x1. Values are pushed in real(x) produces a real number resulting from converting x. xn) puts x1. second argument pushes a null value onto L. but fails on an end of file. xn) : L put onto list Error: 103 s not string put(L. or 3 characters of f if fewer remain. so xn becomes the last (rightmost) value of L. x1. s2) renames the file named s1 to be s2. x2. x1. …. …. but fails if s cannot be removed. 205 i <= 0 Error: 108 L not list 212 f not open for reading See also: get().288 Language Reference Manual App.

with 211 i2 = 0 s2 used for padding at the left as necessary. obtained by sorting the elements of X. D Language Reference Manual 291 Errors: 101 i not integer Errors: 101 i not integer 103 s1 not string 105 f not file 205 i<0 See also: where() reverse(s1) : s2 reverse string seq(i1. For i = 3 or 4. i) seeks to position i in f but fails if the seek cannot be performed. i) : L sort structure seek(f. If X is a table. s2) : s3 position string at right Errors: 101 i1 or i2 not integer right(s1. 0) seeks to the end of file f. the list elements are alternative keys and values. depending on the value of i. i) produces a list in the file is at position 1. list. seek(f. sort(X. Sorting is by keys for i odd.290 Language Reference Manual App. x) terminate with run-time error Error: 102 r1 not real runerr(i. D App. i. If X is a record. See also: asin() Default: x no offending value sort(X. See also: i1 to i2 by i3 Defaults: i 1 s2 " " (blank) Errors: 101 i not integer serial(x) : i produce serial number 103 s1 or s2 not string serial(x) produces the serial number of x if it is a type that has one but fails otherwise. i) produces a list containing values from x. For i = 1 or 2. seq(i1. seek(f. s2) produces a string of size i in which s1 is positioned at the right. i. the list elements are two-element lists of key/value pairs. runerr(i. 205 i<0 See also: center() and left() set(L) : S create set set(L) produces a set whose members are the distinct values in the list L. i2) : i3. i4. sort(X. rtod(r1) : r2 convert radians to degrees Default: L [] rtod(r1) produces the degree equivalent of r1 given in radians. . Errors: 108 L not list Error: 102 r1 not real See also: dtor() sin(r1) : r2 compute sine sin(r1) produces the sine of r1 given in radians. Defaults: i1 1 i2 1 right(s1. or set. The first byte i) produces the values of X in sorted order. by values for i even. i2) generates an endless sequence of integers starting at i1 with increments Errors: 103 s1 not string of i2. x) terminates program execution with error i and offending value x. … generate sequence of integers reverse(s1) produces a string consisting of the reversal of s1. i) : f seek to position in file sort(X.

or set X. set. but structures lacking an ith field appear before structures having them. list. table. List and integer exit status. Two structure values in X having equal ith fields are ordered as they would be in regular sorting. x2. xn) stop execution Errors: 102 r1 not real stop(x1. 2. or a record Error: 101 i not integer 205 i=0 See also: move() See also: sort() sqrt(r1) : r2 compute square root table(x) : T create table sqrt(r1) produces the square root of r1. See also: sortf() system(s) : i call system function sortf(X. tab(i) : s set scanning position Default: i 1 tab(i) produces &subject[&pos:i] and assigns i to &pos. but fails if the conversion is 205 i not 1. …. Default: c ' ' (blank) . x2. See also: atan() Default: xi "" (empty string) Errors: 109 xi not string or file trim(s1. i) produces a sorted list of the values from the record. but fails if i is out of range. c) produces a string consisting of the characters of s1 up to the trailing See also: exit() and write() characters contained in c. Errors: 102 r1 not real Default: x &null 205 r1 < 0 See also: N1 ^ N2 tan(r1) : r2 compute tangent tan(r1) produces the tangent of r1 given in radians.292 Language Reference Manual App. It Errors: 101 i not integer reverses the assignment to &pos if it is resumed. 125 X not list. subsequent output is to xi. The value Error: 103 s not string of i can be negative but not zero. xn. record values in X are ordered by comparing the values of their ith fields. or a record string(x) produces a string resulting from converting x. set. or 4 not possible. D App. D Language Reference Manual 293 Default: i 1 string(x) : s convert to string Errors: 101 i not integer 115 X not list. Initial output is to standard error output. i) : L sort structure by field system(s) calls the C library function system to execute s and produces the resulting sortf(X. c) : s2 trim string 213 xi file not open for writing trim(s1. If xi is a file. x2. …. stop(x1. …. table(x) produces a table with a default value x. xn) terminates program execution with an error exit status after 204 r1 a singular point of tangent writing strings x1. 3.

s. … in locate characters See also: writes() upto(c. xn) : xn write string i1 &pos if s is defaulted. …. x2. Initial output is to standard Errors: 101 i1 or i2 not integer output. If evaluation of the argument fails. x2. i2) generates the sequence of integer positions in s preceding a character of c in s[i1:i2]. 103 s not string Default: xi "" (empty string) 104 c not cset Errors: 109 xi not string or file See also: bal() and find() 213 xi file not open for writing See also: write() variable(s) : v produce variable Produces the variable for the identifier or keyword named s. It fails if there is no such position. 1. i1. the operator symbol appears before the argument on which it Error: 103 s not string operates. Error: 102 N not integer or real See also: N1 + N2 . and then those that where(f) produces the current byte position in f. If the See also: name() argument generates a sequence of results. subsequent output is to xi. There are comparatively few prefix operations. co-expression. the operation may be performed several times. D Language Reference Manual 295 Errors: 103 s1 not string 104 c not cset write(x1. Error: 105 f not file +N : N compute positive See also: seek() +N produces the numeric value of N. xn) writes strings x1. In a prefix operation.294 Language Reference Manual App. s. …. …. Local identifiers override global identifiers. If xi is a file. …. If xi is a file. i4. cset. …. xn without a line termination sequence i2 0 added at the end. x2. but it fails if there is no PREFIX OPERATIONS such variable. subsequent output is to xi. xn) writes strings x1. type(x) : s produce type name Initial output is to standard output. type(x) produces a string corresponding to the type of x. string. Default: xi "" (empty string) Errors: 109 xi not string or file 213 xi file not open for writing upto(c. They are listed in the order of where(f) : i produce position in file the types of arguments: numeric. The first byte in the file is at position apply to arguments of several different types. x2. the operation is not performed. D App. Defaults: s &subject writes(x1. i2) : i3. …. xn) : xn write line write(x1. xn with a line termination sequence added at the end or when switching files. x2. i1. otherwise 1 writes(x1. x2.

tab(). or a structure =s : s match string in scanning 205 x1 < 0 =s is equivalent to tab(match(s)). string. co–expression. If x1 > 0.0. and produces variables if x1 is a variable. If x1 is a table. If x1 is a list or record. !x1 generates the elements of x1. !x1 generates the elements of x1 as variables in no predictable order. See also: s ? expr Error: 103 s1 not string See also: match().296 Language Reference Manual App. but type changed between resumptions 116 x1 not string. …. ?x1 produces the value of a randomly selected element of x1 as a variable. If x1 is an integer. or a structure See also: N1 ∗ N2 . it produces a real number Errors: 102 N not integer or real in range 0. D Language Reference Manual 297 –N : N compute negative ?x1 : x2 generate random value –N produces the negative of N. it produces an integer in range 1 to x1. file. It produces a ∗x : i compute size variable if x is a variable. See also: N1 / N2 Error: 112 x not cset. @C : x activate co-expression If x1 is a string. If x1 is a set. ~c1 : c2 compute cset complement from x1. ∗x produces the size of x.0 to 1. !x1 generates the remaining lines of x1. but fails otherwise. !x1 generates the one-character substrings of x1. ?x1 produces a number from a pseudorandom sequence. string. ~c1 produces the cset complement of c1 with respect to &cset. inclusive. and N1 = N2 !x1 : x2. If x1 is a list or record. which is a variable. The order Error: 118 C not co–expression of generation is from the beginning to the end. !x1 generates the members of x1 in no predictable order. @C produces the outcome of activating C. Errors: 104 c1 not cset If x1 is a table. 212 x1 is file but not open for reading Errors: 118 C1 not co–expression See also: N1 ^ N2 /x : x check for null value /x produces x if the value of x is the null value. xn generate values If x1 is a file. or a structure ^C1 produces a refreshed copy of C1. If x1 = 0. Errors: 113 x1 not integer. D App. which are variables. See also: x@C If x1 is a set. ?x1 produces a randomly selected element. x3. ?x1 produces a randomly selected member of x1. ^C1 : C2 create refreshed co-expression Errors: 103 x1 originally string. 203 integer overflow If x1 is a string. ?x1 produces a randomly selected one-character substring of x1 that See also: N1 − N2 is a variable if x1 is a variable.

INFIX OPERATIONS Errors: 102 N1 or N2 not integer or real 201 N2 = 0 In an infix operation. If evaluation of an argument fails. the operation may be performed several times. and sqrt() N1 – N2 produces the difference of N1 and N2.x produces the value of x. See also: /x If an argument generates a sequence of results. They are listed first by those that perform N1 % N2 : N3 compute remainder computations (such as N1 + N2) and then by those that perform comparisons (such N1 % N2 produces the remainder of N1 divided by N2. See the index. It produces N1 ∗ N2 produces the product of N1 and N2. D App. There are many infix operations. Errors: 102 N1 or N2 not integer or real See also: expr \ i 203 integer overflow 204 real overflow or underflow See also: ∗x . exp(). See also: +N Errors: 102 N1 or N2 not integer or real 204 real overflow. but fails otherwise. or N1 = 0 and N2 <= 0 206 N1 < 0 and N2 real N1 – N2 : N3 compute difference See also: ^C. Assignment operations are listed last. if necessary. a variable if x is a variable. D Language Reference Manual 299 \x : x check for non-null value N1 ∗ N2 : N3 compute product \x produces x if the value of x is not the null value. sign of N1. See also: −N Errors: 120 x1 and x2 not both cset or both set . Errors: 102 N1 or N2 not integer or real 203 integer overflow N1 ^ N2 : N3 compute exponential 204 real overflow or underflow N1 ^ N2 produces N1 raised to the power N2. f N1 / N2 produces the quotient of N1 and N2.x : x dereference variable . an operator symbol stands between the two arguments on 204 real overflow or underflow which it operates. N1 / N2 : N3 compute quotient See also: R. Errors: 102 N1 or N2 not integer or real N1 + N2 : N3 compute sum 202 N2 = 0 204 real overflow or underflow N1 + N2 produces the sum of N1 and N2. underflow. Errors: 102 N1 or N2 not integer or real 203 integer overflow x1 ++ x2 : x3 compute cset or set union 204 real overflow or underflow x1 ++ x2 produces the cset or set union of x1 and x2. 298 Language Reference Manual App. the operation is not performed. The sign of the result is the as N1 < N2).

s1 >> s2 : s2 lexically greater than s1 >>= s2 : s2 lexically greater than or equal Errors: 108 L1 or L2 not list s1== s2 : s2 lexically equal See also: s1 || s2 s1 <<= s2 : s2 lexically less than or equal s1 << s2 : s2 lexically less than s1 ~== s2 : s2 lexically not equal R. Error: 103 s1 or s2 not string Errors: 107 R not a record type 207 R does not have field f See also: . D Language Reference Manual 301 Error: 118 C not co–expression x1 – – x2 : x3 compute cset or set difference See also: @C x1 – – x2 produces the cset or set difference of x1 and x2. transmitting the value of x1 to it. Error: 120 x1 and x2 not both cset or both set N1 > N2 : N2 numerically greater than N1 >= N2 : N2 numerically greater than or equal N1 = N2 : N2 numerically equal s1 || s2 : s3 concatenate strings N1 <= N2 : N2 numerically less than or equal N1 < N2 : N2 numerically less than s1 || s2 produces a string consisting of s1 followed by s2. x1 @ C activates C. x1 ∗∗ x2 produces the cset or set intersection of x1 and x2. but fail otherwise. N1 ~= N2 : N2 numerically not equal Errors: 103 s1 or s2 not string The numerical comparison operators produce N2 if the condition is satisfied. but fail x1 @ C : x2 transmit value to co-expression otherwise.f produces a variable for the f field of record R.f : x get field of record The lexical comparison operators produce s2 if the condition is satisfied. Error: 102 N1 or N2 not integer or real L1 ||| L2 : L3 concatenate lists L1 ||| L2 produces a list consisting of the values in L1 followed by the values in L2. It produces a variable if x2 is a variable. . Errors: 120 x1 and x2 not both cset or both set x1 & x2 : x2 evaluate in conjunction x1 ∗∗ x2 : x3 cset or set intersection x1 & x2 produces x2. it produces the outcome of activating C. but fail See also: L1 ||| L2 otherwise. D App.300 Language Reference Manual App.x x1 === x2 : x2 value equal x1 ~=== x2 : x2 value not equal The value comparison operators produce x2 if the condition is satisfied. R.

xn] : L create list See also: v := x and v1 <−> v2 [x1. xn] produces a list containing the values x1. more than two arguments. x1[x2] produces the element corresponding to key x2 of x1. but other argument not string 111 v1 or v2 not a variable [x1. The error conditions for augmented assignment operations are the same as for performed. and v1 <–> v2 See also: v <− x and v1 :=: v2 v op:= x : v augmented assignment OTHER OPERATIONS v op:= x performs the operation v op x and assigns the result to v. x1[x2] produces a variable if x1 is a variable. but other argument not integer 111 v not a variable 103 v1 or v2 requires string. but x not integer If x1 is a string. . x1[x2] : x3 subscript Errors: 101 v requires integer. Errors: 101 v requires integer. but x not string x1. x2. but x not string 111 v not variable i1 to i2 by i3 : i1. x2.302 Language Reference Manual App. but x not integer 103 v requires string. x1[x2] produces element x2 of x1. If evaluation of an argument fails. the operation may be the basic operations. x2. [ ] produces an empty list. but x not string Errors: 101 v1 or v2 requires integer. It reverses the assignment if it is resumed. v <– x2. it produces the variable v. …. x1[x2] produces a one-character string consisting of character x2 of 103 v requires string. Some have augmented assignment operators for all infix operations except assignment opera. See also: v := x and v1 <−> v2 If x1 is a table. It reverses the exchange if it is resumed. but other argument not string 111 v1 or v2 not a variable See also: v op:= x. xn. but other argument not integer 103 v1 or v2 requires string. Error: 101 v requires integer. For example. but x not integer 103 v requires string. performed several times. v1 <–> v2 exchanges the values v1 and v2 and produces the variable v1. There are The operations on the following pages have varying types of syntax. i2. D Language Reference Manual 303 v := x : v assign value v1 <–> v2 : v1 exchange values reversibly v := x assigns the value of x to v and produces the variable v. D App. v1 :=: v2. in generate integers in sequence See also: v := x i1 to i2 by i3 generates the sequence of integers from i1 to i2 in increments of i3. …. or i3 not integer v1 :=: v2 : v1 exchange values 211 i3 = 0 v1 :=: v2 exchanges the values of v1 and v2 and produces the variable v1. 111 v not a variable If x1 is a list or record. If an argument generates a sequence of results. …. Default: i3 1 if by clause is omitted Errors: 101 i1. See also: list() v <– x : v assign value reversibly v <– x assigns the value of x to v and produces the variable v. i1 +:= i2 produces the same result as i1 := i1 + i2. See also: seq() Errors: 101 v1 or v2 requires integer. the operation is not tions. ….

…. x1[i1:i2] If x is a function or procedure. If x is an integer. nonpositive. x1[i1+:i2] produces the substring of x1 between i1 and i1 + i2. xn]. but x2 not integer x1[i1–:i2] produces a variable if x1 is a variable. arguments in the list or record X. xn) : xm process argument list If x1 is a string. D App. but fails if i is out of the range 1. x(x1. the subscripting operation fails if a subscript is out of range. or record If x1 is a list. x2. and x[i1+:i2] x1[i1:i2] : x2 produce substring or list section x(x1. 114 x1 not string. x[i1:i2]. In this case. xn) produces the outcome of xi. i1 and i2 may be nonpositive. x1[i1:i2] produces a list consisting of the values of x1 in the given range. …. See also: x(…) Errors: 101 i1 or i2 not integer 114 x1 not string or list See also: x1[x2]. …. x2. it produces a variable if xi is a variable. …. i1 and i2 may be nonpositive. x[x1. In either case. x1[i1–:i2] : x2 produce substring or list section In all cases. the subscripting operation fails if a subscript is out of range. x2. x[i1+:i2]. x1 ! X produces the outcome of calling x1 with the x1[i1+:i2] produces a variable if x1 is a variable. xn) produces the outcome of calling x with produces a variable if x1 is a variable. and x[i1−:i2] See also: x ! X. if x1 is out of range of X. x2. and x[i1–:i2] . x2. x(x1. …. n. xn]. list. the subscripting operation fails if the subscript is out of range. Errors: 106 x not procedure or integer 108 X not list or record In either case. x2 may be nonpositive. xn] is equivalent to x[x1. x2. table. x[i1:i2]. x1[i1+:i2] produces a list consisting of the values of x1 in the given range. …. x2. …. 114 x1 not string or list See also: x[x1] See also: x1[x2]. i may be In either case. list. Default: x –1 Errors: 101 i1 or i2 not integer Errors: 106 x not procedure or integer 114 x1 not string or list 117 x is main. …. x{…} x1[i1+:i2] : x2 produce substring or list section x1 ! X : x2 process argument list If x1 is a string. xn] : Xn multiple subscript Errors: 101 i1 or i2 not integer x[x1. but there is no main procedure (during startup) See also: x1[x2]. In either case. Errors: 101 x1 is string. In either case. …. xn. x1[i1–:i2] produces a list consisting of the values of x1 in the given range. x1[i1:i2] produces the substring of x1 between i1 and i2. x1 ! X produces X[x1] but fails If x1 is a list. and x[i1–:i2] In either case. x[i1:i2]. i1 and i2 may be nonpositive. x1[i1–:i2] produces the substring of x1 between i1 and i1 – i2. the subscripting operation fails if a subscript is out of range. x2. If x1 is an integer. x[i1+i2]. arguments x1. If x1 is a list. If x1 is a function or procedure. See also: x[x1.304 Language Reference Manual App. D Language Reference Manual 305 In all cases. If x1 is a string. or a record.

values may be assigned to these. The first value is the total for all regions. xn} is equivalent to x([create x1. as in "1996/10/15". i4 cumulative allocation The value of &digits is a cset containing the ten digits. See the assignment operations for error 15. . October allowable type depends on the keyword. in bytes. x2.71828. However.m. D Language Reference Manual 307 x{x1. &digits : c digits &allocated : i1. 2. as in "Tuesday. The value of &e is the base of the natural logarithms. . respectively. &error is a variable. and block regions. …. a dump in the by garbage collection. i2. style of display() is provided.". &collections : i1. i2. If the value of &error is nonzero. Note: &allocated gives the cumulative alloca. 1996 7:21 p. &dump : i termination dump tion. Error: 106 x not procedure or integer See also: x(…) &date : s date The value of &date is the current date. i3. The value of &current is the currently active co-expression. create x2. &dateline : s date and time of day Some keywords are variables. &errornumber fails if no error has occurred. The space allocated in the static region is always given as zero. i3. The value of &errornumber is the number of the last error converted to failure. &clock : s time of day &error : i control error conversion The value of &clock is a string consisting of the current time of day. that is. &error is zero initially. &allocated generates the total amount of space. string. followed by the totals for the static. …. create xn]). KEYWORDS Keywords are listed in alphabetical order. allocated since the begin- ning of program execution. &storage gives the current allocation. x2. xn} : xm process argument list as co-expressions &current : C current co-expression x{x1. i4 garbage collections &collections generates the total number of garbage collections followed by the &errornumber : i number of last error numbers caused by allocation in the static. a run-time error is converted to expression failure and &error is decremented. D App. the amount that has not been freed If the value of &dump is nonzero when program execution terminates. the The value of &dateline is the current date and time of day. 306 Language Reference Manual App.. conditions. &ascii : c ASCII characters &e : r base of natural logarithms The value of &ascii is a cset consisting of the 128 ASCII characters. string. &cset : c all characters The value of &cset is a cset consisting of all 256 characters.. …. and block regions. respectively. as in "19:21:00".

3. . . &phi : r golden ratio The value of &phi is the golden ratio.and lowercase letters. &line : i source line number The value of &line is the number of the source-program line in which it appears. &null : n null value The value of &null is the null value..61803. to failure. &errortext fails if no error has occurred. &output : f standard output The value of &output is the standard output file. &file : s source file The value of &file is the name of the file from which the current program line was compiled. .308 Language Reference Manual App. &host : s host system The value of &host is a string that identifies the host system on which Icon is running. &pi : r ratio of circumference to diameter of a circle The value of &pi is the ratio of the circumference of a circle to its diameter. The value of &errorvalue is the value that caused the last error converted to failure.. s2.. &features : s1.14159. &level : i procedure level The value of &level is the level of the current procedure call. &errout : f standard error output The value of &errout is the standard error output file. …. &main : C main co-expression The value of &main is the co-expression for the main procedure.. D App. &input : f standard input The value of &input is the standard input file. &letters : c letters &errorvalue : x value causing last error The value of &letters is a cset consisting of the 52 upper. sn implementation features The value of &features generates strings identifying the features of the executing version of Icon. D Language Reference Manual 309 &errortext : s description of last error &lcase : c lowercase letters The value of &errortext is the error message corresponding to the last error converted The value of &lcase is a cset consisting of the 26 lowercase letters. 1. &errorvalue fails if no error has occurred or no specific value caused the error. &fail failure &fail produces no result.

with the few control structures that use operator symbols appearing at the end. The value of &source is the co-expression for the activator of the current co- expression. range of &subject. D Language Reference Manual 311 &pos : i scanning position &time : i elapsed time The value of &pos is the position of scanning in &subject. decremented for each message produced. &version : s Icon version &regions : i1. returns. suspends. &random is zero initially.310 Language Reference Manual App. and block regions. that is what distinguishes a control structure from a function or operation. &storage : i1. . i2. and block break expr : x break out of loop regions. in fact. break expr exits from the enclosing loop and produces the outcome of expr. string. Most control structures are identified by reserved words. Default: expr &null &subject : s subject of scanning See also: next The value of &subject is the string being scanned. &pos is a variable. respec- tively. string. i3 storage regions The value of &version is a string identifying the version of Icon. They are arranged alphabetically on the following pages. i3 storage utilization &storage generates the current amount of space used in the static. A string value is activated or a procedure is called. The size of the static region may not be meaningful. respectively. The seed may be The value of &ucase is a cset consisting of the 26 uppercase letters. i2. &region generates the current sizes of the static. &trace is zero initially. changed by assignment to &random. &random : i random seed &ucase : c uppercase letters The value of &random is the seed for the pseudorandom sequence. a trace message is produced when a co-expression The value of &progname is the file name of the executing program. &subject is a variable. &trace is a variable. The space used in the static region may not be meaningful. CONTROL STRUCTURES The way that arguments of a control structure are evaluated depends on the control &source : C source co-expression structure. &trace : i procedure tracing &progname : s program name If the value of &trace is nonzero. or is resumed. D App. &random is a variable. &trace is can be assigned to &progname to replace its initial value. The scanning position may The value of &time is the number of milliseconds of CPU time since the beginning be changed by assignment to &pos. The subject of scanning may be changed by assignment to &subject. Such an assignment fails if it would be out of of program execution. case expr of { … } : x select according to value case expr of { … } produces the outcome of the case clause that is selected by the value of expr.

The do clause is optional. … evaluate alternatives expr1 | expr2 generates the results for expr1 followed by the results for expr2. . while expr1 do expr2 loop while result while expr1 do expr2 evaluates expr2 each time expr1 succeeds. it fails when The do clause is optional. The do clause is optional. it fails when expr1 succeeds. until expr1 do expr2 loop until result See also: return and suspend until expr1 do expr2 evaluates expr2 each time expr1 fails. Default: expr1 &null (only if the do clause is omitted) See also: fail and return fail fail from procedure fail returns from the current procedure. terminating if expr fails. next go to beginning of loop See also: until expr1 do expr2 next transfers control to the beginning of the enclosing loop. D Language Reference Manual 313 Default: expr &null create expr : C create co-expression See also: fail and suspend create expr produces a co-expression for expr. See also: |expr repeat expr evaluate repeatedly |expr : x1. See also: expr1 | expr2 return expr return from procedure return expr returns from the current procedure. |expr generates the results for expr repeatedly. not expr : n invert failure not expr produces the null value if expr fails. it fails when expr1 fails. The else clause is optional. See also: break expr1 | expr2 : x1. See also: ^C suspend expr1 do expr2 suspend from procedure suspend expr1 do expr2 suspends from the current procedure. See also: while expr1 do expr2 if expr1 then expr2 else expr3 : x select according to outcome if expr1 then expr2 else expr3 produces the outcome of expr2 if expr1 succeeds. producing each result every expr1 do expr2 generate every result generated by expr1.312 Language Reference Manual App. otherwise the outcome of expr3. expr2 is evaluated before resuming expr1. The do clause is optional. causing the call to fail. x2. but fails if expr succeeds. expr1 does not produce a result. every expr1 do expr2 evaluates expr2 for each result generated by expr1. x2. If suspend is resumed. producing the outcome of expr. … evaluate repeatedly repeat expr evaluates expr repeatedly. D App.

314 Language Reference Manual App. D
App. E Command-Line Options 315

expr \ i : x1, x2, …, xi
expr \ i generates at most i results from the outcome for expr.
limit generator
Errors: 101 i not integer
205 i<0
See also: \x

s ? expr : x scan string
Command-Line Options
s ? expr saves the current subject and position and then sets them to the values of s
and 1, respectively. It then evaluates expr. The outcome is the outcome of expr. The
saved values of the subject and position are restored on exit from expr.
Error: 103 s not string
See also: ?x

The following command-line options are recognized by the Icon compiler, icont:
The following expressions may produce more than one result if the context in which
they are evaluated requires it. –c Stop after producing ucode files and do not delete them.
–e file Redirect standard error output to file.
bal(c1, c2, c3, s, i1, i2) &allocated
find(s1, s2, i1, i2) &collections –f s Enable full string invocation.
function() &features
–o name Name the output file name.
key(T) &regions
seq(i1, i 2) &storage –s Suppress informative messages. Normally, both informative
upto(c, s, i1, i2) |expr messages and error messages are sent to standard error output.
!x expr1 | expr2
–t Set &trace to an initial value of –1.
i1 to i2 by i3
–u Issue warning messages for undeclared identifiers.
–v i Set verbosity level of informative messages to i.
–E Direct the results of preprocessing to standard output and
inhibit further processing.

See user manuals for information about platform-specific command-line


App. F Environment Variables 317


Environment Variables

Most operating systems support environment variables. (There are different names
for environment variables on different systems, but the facilities generally are the
Since environment variables are used by Icon primarily to set run-time
parameters such as storage region sizes, the absence of environment variables
usually does not, in itself, directly affect Icon programs. Systems that do not support
environment variables usually provide another way of setting run-time parameters.
When an Icon program is executed, several environment variables are exam-
ined to determine certain execution parameters. Values in parentheses are the
defaults; other values can be set.

BLKSIZE (500000) The initial size of the allocated block region, in
COEXPSIZE (2000) The size, in words, of each co-expression.
IPATH (undefined) The location of ucode files specified in link
declarations for the Icon compiler. IPATH is a
blank–separated list of directories. The current
directory is always searched first, regardless of
the value of IPATH.


318 Environment Variables App. F App. G Error Messages 319

LPATH (undefined) The location of source files specified in prepro-
cessor $include directives. LPATH is otherwise
similar to IPATH. G
MSTKSIZE (10000) The size, in words, of the main interpreter
NOERRBUF (undefined) By default, &errout is buffered. If this variable
is set, &errout is not buffered.
STRSIZE (500000) The initial size of the allocated string region, in
bytes. Error Messages
TRACE (undefined) The initial value of &trace. If this variable has
a value, it overrides the –t option to icont.

See user manuals for information about platform-specific environment vari-

Chapter 16 describes the various kinds of errors that may occur when compiling,
linking, and running Icon programs. The corresponding error messages are de-
signed to be self-explanatory. They are listed here for reference.


The messages for preprecessor errors are:

$define: "(" after name requires preceding space
$define: missing name
$define: unterminated literal
$ifdef/$ifndef: missing name
$ifdef/$ifndef: too many arguments
$include: invalid file name
$include: too many arguments
$line: invalid file name
$line: no line number
$line: too many arguments
$undef: missing name
$undef: too many arguments
circular include
explicit $error
extraneous arguments on $else/$endif
filename: cannot open
invalid preprocessing directive
unexpected $else


320 Error Messages App. G App. G Error Messages 321

unexpected $endif missing right bracket
unterminated $if missing right bracket or ampersand
value redefined missing right parenthesis
missing semicolon
missing semicolon or operator
missing then
syntax error
There are many possible syntax errors. As mentioned in Chapter 16, the actual
If any of these errors occurs in a program, no ucode files are produced and the
source of an error may precede the place where an erroneous construction is
program is not linked.
detected. The messages for syntax errors are:

end of file expected
global, record, or procedure declaration expected LINKING ERROR
invalid argument list
invalid by clause There is one error that can occur during linking:
invalid case clause
invalid case control expression inconsistent redeclaration
invalid create expression
invalid declaration
invalid default clause If this error occurs, no icode file is produced.
invalid do clause
invalid else clause
invalid every control expression RUN-TIME ERRORS
invalid field name
invalid global declaration Run-time error messages are numbered and divided into categories, depending on
invalid if control expression
invalid initial expression
the nature of the error.
invalid keyword construction
invalid local declaration Category 1: Invalid Type or Form
invalid argument
invalid argument for unary operator 101 integer expected or out of range
invalid argument in alternation 102 numeric expected
invalid argument in assignment 103 string expected
invalid argument in augmented assignment 104 cset expected
invalid repeat expression 105 file expected
invalid section 106 procedure or integer expected
invalid then clause 107 record expected
invalid to clause 108 list expected
invalid until control expression 109 string or file expected
invalid while control expression 110 string or list expected
link list expected 111 variable expected
missing colon 112 invalid type to size operation
missing colon or ampersand 113 invalid type to random operation
missing end 114 invalid type to subscript operation
missing field list in record declaration 115 structure expected
missing identifier 116 invalid type to element generator
missing left brace 117 missing main procedure
missing link file name 118 co-expression expected
missing of 119 set expected
missing parameter list in procedure declaration 120 two csets or two sets expected
missing procedure name 121 function not supported
missing record name 122 set or table expected
missing right brace 123 invalid type
missing right brace or semicolon 124 table expected

as well as information about platform-dependent extensions. G App. Category 5: Programmer-Specified Error While differences in Icon due to different computer architectures. and most programs written on one platform run on other platforms 316 interpreter stack too large with little or no change. 323 . underflow. H Platform-Specific Differences 323 125 list. 305 inadequate space for static allocation All of these implementations are based on a generic implementation devel- 306 inadequate space in string region 307 inadequate space in block region oped at The University of Arizona. Consequently. vary some- Category 4: Feature Not Implemented what in the environments they provide. and in some cases there are several different 303 inadequate space for evaluation stack 304 inadequate space in qualifier list implementations for the same operating system and computer. Icon user manuals for specific platforms of Icon contain information about features that are not supported or that differ from the standard implementation. record. Some implementations of Icon also contain additional platform-dependent features. In addition. or set expected H 126 list or record expected Category 2: Invalid Value or Computation 201 division by zero 202 remaindering by zero 203 integer overflow 204 real overflow. 318 co–expression stack too large Different computer architectures and operating systems.322 Error Messages App. This may affect some features of Icon. operating systems. The following sections list areas where differences are likely to be encountered. 500 program malfunction persons who write Icon programs for use on a variety of platforms should be aware of possible problems. the generic implementation of Icon is written in C. and C compilers are relatively minor and only affect portions of Icon. In some cases. Icon is implemented for different operat- 302 memory violation ing systems on the same computer. ranging from personal 301 evaluation stack overflow computers to mainframes. or division by zero 205 invalid value 206 207 negative first argument to real exponentiation invalid field name Platform-Specific Differences 208 second and third arguments to map of unequal length 209 invalid second argument to open 210 non-ascending arguments to detab/entab 211 by value equal to zero 212 attempt to read file not open for reading 213 attempt to write file not open for writing 214 input/output error 215 attempt to refresh &main 216 external function not found Category 3: Capacity Exceeded Implementations of Icon are available for many platforms. Different C compilers 401 co–expressions not implemented themselves differ in the features they support. all implementations are the same 308 system stack overflow in co-expression in most respects. however.

integer overflow The places where differences in character sets are most apparent is in sorting results in error termination. which are based on character codes. The keyboard functions kbhit(). Other EBCDIC characters. Similarly. It is not supported (and has no meaning) for platforms that use visual interfaces unless the platform also provides succeeds for ASCII implementations of Icon but fails for EBCDIC implementations command-line facilities. platforms. In any event. See Co-expressions require a platform-specific context switch. it consists of characters with codes 0 through 127 — the first half of the entire character set. On ASCII implementations of Keyboard Functions Icon. These multi-character equivalents also are available on ASCII implemen. Some map EBCDIC to ASCII on input and vice-versa on output. mentation of Icon may provide an equivalent feature that supports getenv(). Not all platforms support these implementations assign character codes to &ascii so that the graphics are the same keyboard functions. but not all. the interpretation of ASCII control charac- ters given in \^ escape sequences in literals varies for EBCDIC implementations. The system() function is supported on most. differences in character sets do not affect most programs. and lexical comparison. Consequently. implementations of "A" << "a" Icon that run in command-line environments. so that the computer platforms where program operation can be controlled by user-typed corresponding graphics are different from those on ASCII platforms. . It is worth noting that different implementations of Icon on EBCDIC platforms Pipes treat this matter differently. The difference between the two character sets lies in the correspondence between character codes and glyphs. independently of standard input. H App. as on ASCII implementations. The notable exceptions are IBM 370 The following features are not supported on all platforms. If large-integer arithmetic is not supported. platforms. mainframes. getenv() fails. Co-Expressions Both ASCII and EBCDIC have 256 characters. the imple- to { and } . but the converse Executing Commands is true for EBCDIC. The syntax for the IPATH and LPATH environment variables depends on the platform. 324 Platform-Specific Differences App. allowing programs that use them to run on both ASCII and EBCDIC environment variables are not supported. which use the EBCDIC character set. For example. features related to them are not available. If co-expressions Appendix B for a listing of both character sets. in ASCII the uppercase letters have smaller codes than the lowercase ones. Large-integer arithmetic may not be supported on platforms with small amounts of memory. If tations of Icon. $( and $) are equivalent On platforms on which environment variables do not exist per se. Environment Variables Since most EBCDIC consoles do not support brackets. the use of system() is highly specific to the of Icon. For example. although the letter A is assigned to character code 65 in ASCII but to character code Large-Integer Arithmetic 193 in EBCDIC. The cset &ascii presents a different problem. Some other options for open() also are platform-dependent. most operations that use the letter A do not depend on its specific character code. are not implemented. glyphs. Similarly. H Platform-Specific Differences 325 CHARACTER SETS LANGUAGE FEATURES Most computers use the ASCII character set. but the rest of Icon Since Icon operates internally on characters without regard for their associated is unaffected. Different EBCDIC implementations of Icon treat &ascii differently. thus obtaining the ASCII correspondence between character codes and Pipes and the "p" option for the open() function generally are supported only graphics internally. the combination $< and $> can be used in place of [ and ] in program text. and getche() are useful on personal- Some assign the same character codes to it as on ASCII platforms. Sorting produces correspondingly different results in ASCII and EBCDIC platform on which Icon runs. getch(). on UNIX platforms.

the string representation for real numbers may vary. The first value is the name of the As noted in Chapter 11.326 Platform-Specific Differences App. If dynamic loading is not supported. Some platforms. H App. loadfunc() is not defined. For example. such as the console. Whether the change in directory produced by chdir() persists after program Determining Features execution depends on the operating system. and auxiliary ports. tors. use different notions of file naming than are used in examples in this book. . UNIX ASCII Exit Codes co–expressions dynamic loading On most operating systems. H Platform-Specific Differences 327 Dynamic Loading OTHER ISSUES Dynamic loading requires an operating system facility that is not available on Real Numbers all platforms. For platforms that do. and the second value is the character set. In addition. The presence or absence of features of a particular implementation of Icon can Input and Output be checked during program execution. notably VAX/VMS and IBM mainframes. For available memory is inadequate. printer. might produce Some platforms. On most platforms it is easy to provide a script that accomplishes the same thing. large integers use other values. the lack of example. Since this option is only a shortcut. pipes system function Command-Line Option Some implementations support additional features. however. random-access input and output may behave strangely platform for the implementation. The precision and range of real numbers varies considerably from platform to Graphics Facilities platform. the exit code for the normal termination of a environment variables program is 0 and the exit code for error termination is 1. Not all platforms support Icon’s graphic facilities. there Changing Directories may be minor differences and a few features that are not supported. if not(&features = = "co–expressions") then stop("∗∗∗ co–expressions not supported") Determining Functions The function function() generates the names of the (built-in) functions. every write(&features) Some platforms support special file names for input and output to devices. The –x option to icont for launching an icode file automatically is not supported Supported language features are of particular interest for programs that are to on some platforms and may malfunction on other platforms if the amount of be run on platforms that are different from those on which they are developed. followed on text files in translated mode for platforms that use multi-character line termina- by specific features. a program that uses co-expressions can check for their presence as follows: support for –x is only an inconvenience. The keyword &features generates strings listing the features available in an implementation.

Alexander with additions by Gregg M. These programs were written by several different programmers. fn. App. fList. opttable. # Author: Robert J. COMMAND-LINE OPTIONS The procedure options() was mentioned in Chapter 15 as being particularly useful for programs that run in command-line environments. ptname. The code for this procedure follows. Conse- quently. I Sample Programs 329 I Sample Programs This appendix contains several sample programs that illustrate Icon programming techniques in the context of somewhat larger problems than those given in the body of the book. they have somewhat different programming styles and layouts than those used elsewhere in this book. notice the use of tests for the null value to provide defaults for omitted arguments. x. ignore. errproc) local f. opttype. optstring. Townsend procedure options(arg. p. In the initialization section. Some programs have been modified slightly for presentation here. option 329 . fileArg. All of these programs can be found in the Icon program library.

} # } /optstring := string(&letters) # If the argument begins with the character "@". tab(0) ? until pos(0) do { if opttype := \opttable[ # Author: Robert J.": real(p) | return errproc("–" || optname || done := table() " needs numeric parameter") } } else 1 # Determine the type and process accordingly. sn. stop ignoring STRUCTURE IMAGES else x ? { if ="–" & not pos(0) & /ignore then { The procedures ximage() and xdump(x). xtag. ss. indent. } # else return errproc("Unrecognized option: –" || optname) indent := (if indent == "" then "\n" else "") || indent || " " } ss := "" . opttype) then { local i. done) if any(':+. tp. case opttype of { # ":": p if /(state := done) then { "+": integer(p) | return errproc("–" || optname || tr := &trace . fileArg := [ ] # while put(fileArg. read(f)) optstring ? { close(f) while optname := move(1) do { push(arg) # push null to signal end of args from file if optname == " " then next while push(arg. state. These procedure are worth study. x) opttype := tab(any('!:+. they contain else { many sophisticated programming techniques.330 Sample Programs App.')) | "!" } opttable[optname] := opttype while push(arg. fetch option /errproc := stop # words from lines of a text file. end # while x := get(arg) do { if /x then ignore := &null # if end of args from file. illustrate how if ="–" & pos(0) then ignore := 1 # ignore following args if – – values of any type can be handled.'. option := table() # fList := [ ] else if ="@" & not pos(0) & /ignore then { opttable := table() f := open(fn := tab(0)) | return errproc("Can't open " || fn) # Scan the option specification string. &trace := 0 # postpone tracing while in here " needs numeric parameter") indent := "" ". pull(fList)) } } return option # Iterate over program invocation argument words. Alexander optname := ((pos(1). pull(fileArg)) if optname == "–" then } optname := tab(many(&letters)) | move(1) | break else put(fList. also discussed in Chapter 15. tab(0)) | move(1))] then { option[optname] := procedure ximage(x. s. t. do some initialization. sz p := "" ~== tab(0) | get(arg) | static tr return errproc("No parameter following –" || optname) # If this is the outer invocation. I Sample Programs 331 # Initialize. I App.

too. indent.332 Sample Programs App. "table": { # table # image(x) ? { t := table(0) tab(7) every t[!x] +:= 1 sn := tab(find("(")) } s := [. done) # } ss := "" # Output the table. I Sample Programs 333 tp := type(x) "set": { # set s := if xtag := \done[x] then xtag else case tp of { image(x) ? { tab(5) # Unstructured types just return their image(). indent. If so. " || t || ")" } } done[x] := xtag := "L" || sn xtag || " := " || "set()" || ss # Figure out if there is a predominance of any object in the } # list. indent || " ". I App. since if s[2] > ∗x / 3 & s[2] > 2 then { # the subscripts might be structured. done) t := ximage(x[[ ]]. 0] done[x] := xtag := "T" || sn every t := !sort(t) do if s[2] < t[2] then s := t # Output the table elements. ss ||:= indent || xtag || "[" || i || "] := " || # ximage(x[i]. done) } if t ? (not any('\'"') & s := tab(find(" :="))) then s := tp || sz t := "{" || t || indent || " " || s || "}" s[–1:–1] := ". including its default value (which might every i := 1 to ∗x do if x[i] ~=== s then { # also be structured. sn := tab(find("(")) # } "null" | "string" | "integer" | "real" | "cset" | "co–expression" | "file" | "procedure" | "window": image(x) done[x] := xtag := "S" || sn "list": { # list every i := !sort(x) do { image(x) ? { t := ximage(i. " || \t xtag || " := " || "table(" || t || ")" || ss xtag || " := " || s || ss } } . indent || " ". t || "] := " || ximage(i[2]. done) every i := !sort(x) do { if t ? (not any('\'"') & ss := tab(find(" :="))) then t := ximage(i[1]. make it the default object. done) t := "{" || t || indent || " " || ss || "}" if t ? (not any('\'"') & s := tab(find(" :="))) then } t := "{" || t || indent || " " || s || "}" else s := t := &null ss ||:= indent || xtag || "[" || # Output the non–defaulted elements of the list. This is a bit tricky. done) tab(6) if t ? (not any('\'"') & s := tab(find(" :="))) then sn := tab(find("(")) t := "{" || t || indent || " " || s || "}" sz := tab(0) ss ||:= indent || "insert(" || xtag || ". indent || " ". indent || " ". s := s[1] # t := ximage(s.

done) procedure main(args) } local opts. x1. the number of occurrences } is given in parentheses after the line number. line := format(get(uselist)) # line numbers while (∗line + namewidth) > colmax do { # handle long lines procedure xdump(x[ ]) line ?:= { every write(&errout. move(7) t := "" # Author: Ralph E. tab(j)) CONCORDANCES move(1) fill := pad This program produces a simple concordance. . namewidth. trim(line)) There are two options: } –l n set maximum line length to n (default 72). # . j. pad.. lineno) # tabulate all citations return s uselist := sort(uses. 3) # sort by uses end while fill := left(get(uselist). Words less than three characters long } are ignored. fill xtag || " := " || t || "()" || ss } opts := options(args. namewidth) do { # Write ximages of x1. "l+w+") # process options } colmax := \opts["l"] | ColMax namewidth := \opts["w"] | NameWidth # If this is the outer invocation. ximage(!x)) i := j := 0 every i := upto(' ') do { return x[–1] | &null if i > (colmax – namewidth) then break end else j := i } write(fill. line. via item(). # pad := repl(" ". name. If a word occurs more than once on a line. Griswold while t ||:= tab(find("_")) || move(1) t[–1] := "" link options sn := tab(find("(")) $define ColMax 72 } $define MinLength 3 done[x] := xtag := "R_" || t || "_" || sn $define NameWidth 15 every i := 1 to ∗x do { name(x[i]) ? (tab(find(". a listing of all words in the input and tab(0) # new value of line the numbers of the lines in which they appear. i. namewidth) if /state then { uses := table() &trace := tr # restore &trace lineno := 0 } every tabulate(item().. xn. to handle other image(x) ? { kinds of tabulations. colmax. lineno ss ||:= indent || xtag || sn || " := " || ximage(\x[i]. wraps end –w n set maximum width for word to n (default 15). I App. if ∗line > 0 then write(fill.")). indent.. I Sample Programs 335 default: { # record Note that the program is organized to make it easy. truncates # Add to count of line number to citations for name. sn := tab(0)) global uses. 334 Sample Programs App. uselist. clean up before returning.

line procedure main() while line := read() do { GameObject := "animal" lineno +:= 1 Tree := Question("Does it live in water". Tree. I App. end # Get an item. It is an “expert system”' that starts out with limited knowledge. the user can create a program that builds a linenos := sort(linenos. Simply by modifying the local i. word. line first two lines of the main procedure. yes.") if \Learn &Confirm("Want to save knowledge learned this session") then Save() return end . " ". An example is: line := "" GameObject := "president" while line ||:= get(linenos) do Tree := Question("Did he write the Gettysburg address". Article(GameObject). " ". "canary") write(right(lineno. the program asks permission to # Format the line numbers. written in Icon. The program asks its human uses[name][lineno] +:= 1 opponent a series of questions in an attempt to guess the animal about which the return human opponent is thinking. The saved file is a text file that can be # edited. but gets smarter as it plays and learns from end its opponents. global GameObject. end GameObject) do Ask(Tree) write("Thanks for a great game. and there are some other commands too (see the procedure Confirm()). } # } procedure Game() } while Confirm("Are you thinking of ". breaking long lines as necessary. knowing only one question. 3) knowledge base in other categories. procedure format(linenos) The game is not limited to guessing about animals.336 Sample Programs App. Alexander # modifying this procedure. At the conclusion of a session. "goldfish". Different kinds of concordances can be obtained by # Author: Robert J. lineno) ANIMAL GAME /uses[name] := table(0) This is the familiar “animal game”. so typographical errors entered during the heat of battle can be corrected. no) local i. line) line := map(line) # fold to lowercase Get() # Recall prior knowledge i := 1 Game() # Play a game line ? { while tab(upto(&letters)) do { return word := tab(many(&letters)) end if ∗word >= MinLength then # skip short words suspend word # Game() –– Conducts a game. Learn # procedure item() record Question(question. remember what it learned for future sessions. "Reagan". 6). I Sample Programs 337 procedure tabulate(name. line ||:= ("(" || (1 < get(linenos)) || ") ") | " " "Lincoln") return line Typing list at any yes/no prompt shows an inventory of animals known.

" ". Article(guess). " ". Article(node). Article(guess).question) then node. # # Article() –– Come up with the appropriate indefinite article. /sense := " " guess.yes) while /answer do { else node. I App. node) initial { else return Question(question.338 Sample Programs every writes(!q) } write("?") } case s := read() | exit(1) of { end # Commands recognized at a yes/no prompt. node. sense) if not Confirm("It must be ". question # Output() –– Recursive procedure used to output the knowledge tree.") # based on the GameObject. guess. # return procedure Ask(node) end local guess. right") then { static indent Learn := "yes" write("What were you thinking of?") initial indent := 0 guess := read() | exit(1) /f := &output write("What question would distinguish ". guess. guess) ok := table() } every ok["y" | "yes" | "yeah" | "uh huh"] := "yes" } every ok["n" | "no" | "nope" | "uh uh" ] := "no" "Question": { } if Confirm(node. "?") case type(node) of { . &ucase. local answer. f. &lcase)]) | # Save() –– Store our acquired knowledge in a disk file name write("This is a \"yes\" or \"no\" question. "w") end Output(Tree. word) then "an" else "a" "dump": Output(Tree) default: { end (answer := \ok[map(s. } # } procedure Save() } local f return answer == "yes" f := open(GameObject || "s". Article(node).yes := Ask(node. " ". " from ". node. &lcase. case type(node) of { # "string": { procedure Output(node. if question[–1] == "?" then question[–1] := "" # question[1] := map(question[1]. ". " ".no := Ask(node. &ucase) procedure Confirm(q[]) if Confirm("For ". f) # Ask() –– Navigates through the barrage of questions leading to a close(f) # guess. ". s what would the answer be") static ok then return Question(question. I Sample Programs 339 question := read() | exit(1) # Confirm() –– Handles yes/no questions and answers. node. "save": Save() # "get": Get() procedure Article(word) "list": List() return if any('aeiouAEIOU'.

every item := !sort(lst) do { <poem>::=<rule1><nl><rule2><nl><rule3><nl><nl> if ∗line + ∗item > Length then { <noun>::=he|she|the shadowy figure|the boy|a child|a ghost|a black cat . [ ]) <rule1>::=<qual> <noun> <tverb> <object>. RANDOMLY GENERATED SENTENCES # procedure Input(f) This program generates randomly selected strings (“sentences”) from a grammar local nodetype. "y") } Output(node. f. return if nodetype == "Q" then Question(s. line. $define Length 78 • Generation specifications that cause the generation of a specified number of sentences from the language defined by a given nonterminal symbol. Input(f)) else s which can be intermixed. f. " Output(node. line := "" <rule2>::=<noun> <iverb>. "n") write(line[1:–2]) indent –:= 1 } return } end return # end # Show() –– Recursive procedure used to navigate the knowledge tree. indent). repl(" ". test. "A: ".question) } indent +:= 1 line ||:= item || ". procedure Show(node. read(f) ? (tab(upto(~' \t')) & =("y" | "n" | "") & nodetype := move(1) & move(2) & s := tab(0)) The program works interactively. I Sample Programs 341 "string": write(f. repl(" ". # # Get() –– Read in a knowledge base from a file. node) close(f) return lst return end end # Input() –– Recursive procedure used to input the knowledge tree. lst) f := open(GameObject || "s". procedure List() local lst. lst) lst := Show( <rule3>::=<qual> <noun> <iverb>. Input to the program consists of various kinds of specifications. node) write(trim(line)) "Question": { line := "" write(f. sense. s specified by the user. modify. I App. <clause> ... Grammars are basically context-free and resemble BNF in form. indent).yes. The two main kinds of specifications are: end • Productions that define nonterminal symbols in a syntax similar to the rewrit- # List() –– Lists the objects in the knowledge base. Input(f). sense. although there are a number of extensions. "Q: ". ing rules of BNF. item An example of a grammar is: lst := Show(Tree. with alternatives being represented by the concatenation of # nonterminal and terminal symbols. allowing the user to build.340 Sample Programs App. and save grammars. "r") | fail } Tree := Input(f) else put(lst. lst) # procedure Get() if type(node) == "Question" then { local f lst := Show(node.

but stares . prompt := "" a child returns.. if ∗prompt ~= 0 then writes(prompt) a black cat kneels. repeat { frozen.. ifile. plist. } the boy turns away. syms(tab(upto('|') | 0))) do move(1) | break record charset(chars) return alist $define Limit 1000 end procedure main(args) # Look for comment. line := read(in) | break as the boy hesitates. generate. &random := \opts["s"] a child turns away. # Author: Ralph E. Griswold # link options procedure alts(defn) link random local alist global defs. prompt.. I App. ifile := [&input] # stack of input files as the shadowy figure outlines the darkness. but hesitates . while in := pop(ifile) do { # process all files momentarily she stares. <poem>4 specifies the generation of four <poem>s.. For example.. end # Process alternatives. while line[–1] == "\\" do line := line[1:–1] || read(in) | break (!plist)(line) momentarily a ghost destroys the sun. opts := options(args.. opts # # procedures to try on input lines procedure comment(line) # if line[1] == "#" then return else fail end . "tl+s+r") limit := \opts["l"] | Limit Typical output is: tswitch := \opts["t"] as the boy throws a darkness. s. } The program has many other features as shown in the listing that follows.. prompter. the boy captures a star.342 Sample Programs App. if /opts["s"] & /opts["r"] then randomize() momentarily the shadowy figure alights.. comment. source. close(in) as a child alights. limit. in. but hurries . and alights . local line. tswitch alist := [ ] record nonterm(name) defn ? while put(alist. defs["&ucase"] := [[charset(&ucase)]] defs["&digit"] := [[charset(&digits)]] A generation specification consists of a nonterminal symbol followed by a nonnegative integer. I Sample Programs 343 <tverb>::=outlines|stares at|captures|damns|destroys|raises|throws plist := [define. error] <iverb>::=alights|hesitates|turns away|kneels|stares|hurries defs := table() # table of definitions <clause>::=and <iverb>|but <iverb>|and <iverb>|while <ger> <adj> defs["lb"] := [["<"]] # built–in definitions <adj>::=silently|darkly|with fear|expectantly|fearfully|quietly|hauntingly defs["rb"] := [[">"]] <ger>::=waiting|pointing|breathing|reclining|disappearing defs["vb"] := [["|"]] <object>::=<article> <onoun> defs["nl"] := [["\n"]] <article>::=a|the defs[""] := [[""]] <onoun>::=sky|void|abyss|star|darkness|lake|moon|cloud|sun|mountain defs["&lcase"] := [[charset(&lcase)]] <qual>::=while|as|momentarily|frozen. grammar.

alts(tab(0))) } } end } # Define nonterminal. ">") # Look for request to write out grammar. "∗∗∗ excessive symbols remaining") procedure define(line) break return line ? defs[(="<". "∗∗∗ undefined nonterminal: <". name if line ? { . symbol. I Sample Programs 345 } # Look for definition. if ∗pending > \limit then { # write(&errout. ="'" & # chars := cset(tab(–1)) & procedure generate(line) ="'" local goal. } # write() procedure defnon(sym) local chars. move(1) & # count := (pos(0) & 1) | integer(tab(0)) procedure error(line) } then { write("∗∗∗ erroneous line: ". line) every 1 to count do return gener(goal) return end } # Generate sentences. else fail # procedure gener(goal) end local pending. symimage(symbol). out.chars) "nonterm": { return rhs[1:–1] pending := ?\defs[symbol. symbol # Get right hand side of production. tab(find(">::=")))] := (move(4).344 Sample Programs App. I App. listimage(pending)) case type(symbol) of { rhs := "" "string": writes(symbol) every rhs ||:= listimage(!a) || "|" "charset": writes(?symbol. break # procedure grammar(line) local file. pending := [nonterm(goal)] # procedure getrhs(a) while symbol := get(pending) do { local rhs if \tswitch then write(&errout. name end if sym ? { # Look for generation] ||| pending | { end write(& count } then return charset(chars) else return nonterm(sym) if line ? { ="<" & end goal := tab(upto('>')) \ 1 & # Note erroneous input line.

I App. "w") | { if nt == !builtin then { write(&errout. out) write("∗∗∗ undefined nonterminal: ". x write(&errout. "&lcase". "∗∗∗ cannot open ". 3) out := if ∗file = 0 then &output else { while nt := get(a) do { open(file. file) fail s := "" } every x := !a do push(ifile. "&ucase".chars || "'>" } # Write out grammar. name) if ∗file ~= 0 then close(out) end return } # Look for file with input. ">::=".name || ">" end "charset": "<'" || x. getrhs(\defs[name[2:–1]])) | pwrite(name. "". "nl". new # Produce image of list of grammar symbols. "&digit"] name := tab(find("–>")) & move(2) & if ∗name = 0 then { file := tab(0) & a := sort(defs. getrhs(get(a))) } } then { } (∗name = 0) | (name[1] == "<" & name[–1] == ">") | fail else write(ofile. end # # Produce string image of grammar symbol. "vb". "<". I Sample Programs 347 initial builtin := ["lb". procedure prompter(line) # if line[1] == "=" then { procedure symimage(x) prompt := line[2:0] return case type(x) of { return "string": x } "nonterm": "<" || x. file) get(a) fail next } } } write(ofile. return line ? { # if ="@" then { procedure listimage(a) new := open(file := tab(0)) | { local s. # end procedure pwrite(name.346 Sample Programs App. "∗∗∗ cannot open ". name. a # static builtin procedure syms(alt) . ofile) # Process the symbols in an alternative. "rb". # else fail procedure source(line) end local file. nt. "::=". in) & s ||:= symimage(x) in := new return return s } end } # Look for new prompt symbol. local nt.

border) $define Queens 8 every line[4 ∗ (!solution – 1) + 3] <– "Q" do { procedure main(args) write(" ". procedure show() | | | Q | | | | | | static count. alt ? while put(slist. I Sample Programs 349 local slist write(n. line) local i. 0) N QUEENS down := list(2 ∗ n – 1. } | Q | | | | | | | | --------------------------------. The following solution for 8 queens is typical: solution[c] := r # record placement --------------------------------. n) || "|" border := repl("– – – –". border --------------------------------- | | | | | | | Q | | initial { --------------------------------. It is a generalization of the techniques described in Chapter 17. 0) This program displays all the solutions for n non-attacking queens on an n×n } chessboard. 0) rows := list(n. move(1)))) procedure q(c) return slist local r static up. opts write(" ". line := repl("| ". if c = n then show() | | | | | | Q | | | else q(c + 1) # try to place next queen --------------------------------. solution write(" ". border) } opts := options(args. --------------------------------. # | | | | | | | | Q | --------------------------------. n) || "–" # Author: Steven B. "–Queens:") static nonbrack every q(1) # start by placing queen in first column initial nonbrack := ~'<' end slist := [ ] # Place a queen in column c. 348 Sample Programs App. line. end | | | | | Q | | | | --------------------------------- | | Q | | | | | | | # Show the solution on a chess board. tab(many(nonbrack)) | # defnon(2(="<". I App. tab(upto('>')). count := 0 | | | | Q | | | | | --------------------------------. Wampler } link options write("solution: ". every 0 = rows[r := 1 to n] = up[n + r – c] = down[r + c – 1] & The solutions are written showing the positions of the queens on the chess. count +:= 1) global n. down. rows end initial { up := list(2 ∗ n – 1. "n+") n := \opts["n"] | Queens write() if n <= 0 then stop("–n needs a positive numeric parameter") end solution := list(n) # list of column solutions . rows[r] <– up[n + r – c] <– down[r + c – 1] <– 1 do { board.

I App. based on a program by 66666666403666640000220000466663046666666_ # Stephen B. The local i. wsize. opts. "size=41. 350 Sample Programs App. 41") | stop("∗∗∗ cannot open window for black queen") white_queen := WOpen("canvas=hidden". "41. wqueen display is animated so that the queens “move” from solution to solution. "n+") This program uses graphics features that are not described in Chapter 12. 0. bqueen. opts := options(args. white_queen 66666666666500000000000000000056666666666_ 66666666666610000000000000000166666666666_ $define Edge 4 66666666666630000000000000000366666666666_ $define Offset 40 66666666666652222222222222222566666666666_ $define Queens 8 66666666666664444444444444444666666666666_ $define Size 44 66666666666640000000000000000466666666666_ 66666666666651000000000000001566666666666_ . if queens <= 0 then stop("–n needs a positive numeric parameter") An example from the display for 8 queens is shown below. Wampler 66666666620266620000000000266620266666666_ 66666666650002100000000000012000566666666_ link options 66666666663000000000000000000003666666666_ link wopen 66666666666000000000000000000006666666666_ global solution 66666666666300000000000000000036666666666_ global black_queen. but queens := \opts["n"] | Queens it should be clear what is being done. Compare it to the wsize := queens ∗ Size + 2 ∗ Offset textual version shown in the preceding section. I Sample Programs 351 N QUEENS DISPLAYED GRAPHICALLY global queens procedure main(args) This version of the n-queens program displays the solutions in a window. "size=41. c1. " || wsize. Griswold. "label=" || queens || "–queens") | stop("∗∗∗ cannot open window") black_queen := WOpen("canvas=hidden". 0. 41") | stop("∗∗∗ cannot open window for white queen") DrawImage(black_queen. _ 66666666666666666666666666666666666666666_ 66666666666666666666666666666666666666666_ 66666666666666666666666666666666666666666_ 66666666666664003666666663004666666666666_ 66666666666650000466666640000566666666666_ 66666666666640000366666630000466666666666_ 66666666666660000566666650000666666666666_ 66666666666665224666666664225666666666666_ 66663346666666644666666664466666666433666_ 66620004666666631666666661366666664000266_ 66600002666666640666666660466666662000066_ 66600003666666650466666640566666663000066_ 66640026666666660166666610666666666200466_ 66666651666666660046666400666666661566666_ 66666662266666660026666200666666622666666_ 66666666036666660004663000666666306666666_ # Author: Ralph E. WOpen("size=" || wsize || ".

0) 00266400000000065000000560000000004662000_ down := list(2 ∗ queens – 1. I App. c1. j. _ every q(1) # start with queen in first column 00000000000000000000000000000000000000000_ until WQuit() # wait for user to dismiss 00000000000000000000000000000000000000000_ 00000000000026630000000036620000000000000_ end 00000000000166662000000266661000000000000_ 00000000000266663000000366662000000000000_ # Place a queen in column c. 00000000000022222222222222220000000000000_ # 00000000000266666666666666662000000000000_ procedure show() 00000000000156666666666666651000000000000_ local i. down. I Sample Programs 353 66666666666664000000000000004666666666666_ 00000000000022222222222222220000000000000_ 66666666666651000000000000001566666666666_ 00000000134444444444444444444431000000000_ 66666666666640000000000000000466666666666_ 00000000666666666666666666666666000000000_ 66666666666664444444444444444666666666666_ 00000002666666666666666666666666200000000_ 66666666653222222222222222222223566666666_ 00000003666666666666666666666666300000000_ 66666666600000000000000000000000066666666_ 00000003666666666666666666666666300000000_ 66666666400000000000000000000000046666666_ 00000003666666666666666666666666300000000_ 66666666300000000000000000000000036666666_ 00000003666666666666666666666666300000000_ 66666666300000000000000000000000036666666_ 00000000000000000000000000000000000000000_ 66666666300000000000000000000000036666666_ 00000000000000000000000000000000000000000" 66666666300000000000000000000000036666666_ ) 66666666666666666666666666666666666666666" DrawBoard() ) solution := list(queens) # list of column solutions DrawImage(white_queen. 0. 00000000000066661000000166660000000000000_ # 00000000000014420000000024410000000000000_ procedure q(c) 00033200000000220000000022000000002330000_ local r 00466620000000350000000053000000026664000_ static up. 0) 00000150000000066200002660000000051000000_ rows := list(queens. rows 00666640000000260000000062000000046666000_ initial { 00666630000000162000000261000000036666000_ up := list(2 ∗ queens – 1. 0. queen 00000000000026666666666666620000000000000_ every i := 1 to ∗solution do { 00000000000156666666666666651000000000000_ j := solution[i] 00000000000266666666666666662000000000000_ . "41.352 Sample Programs App. 0) 00000044000000066400004660000000440000000_ } 00000006300000066620036660000003600000000_ 00000002630000266664466662000036200000000_ every 0 = rows[r := 1 to queens] = up[queens + r – c] = 00000000464000466666666664000464000000000_ down[r + c – 1] & rows[r] <– up[queens + r – c] <– 00000000166645666666666666546661000000000_ down[r + c – 1] <– 1 do { 00000000036666666666666666666630000000000_ solution[c] := r # record placement 00000000006666666666666666666600000000000_ if c = queens then show() 00000000003666666666666666666300000000000_ else q(c + 1) # try to place next queen 00000000001666666666666666666100000000000_ } 00000000000566666666666666665000000000000_ end 00000000000366666666666666663000000000000_ 00000000000144444444444444441000000000000_ # Show the solution on a chess board.

Size) programming (Griswold. the current status of Icon. MS-DOS. . Icon’s graphics facilities presently are supported for Microsoft Windows. Offset + j ∗ Size. VAX/VMS. . There are two newsletters (Griswold. J Access to Icon Material 355 queen := if (i + j) % 2 = 0 then black_queen else white_queen CopyArea(queen. and Windows every i := 0 to queens – 1 do NT. documentation.arizona. every j := 0 to queens – 1 do if (i + j) % 2 = 1 then Documentation on Icon is extensive. and so on. Size. &window. queens ∗ Size + 1. The current version is 9. and Townsend. the Icon home page queens ∗ Size + 2 ∗ Edge + 1. queens ∗ Size + 1) Implementations of Icon. Griswold. and user manuals for various platforms. There local i. Offset + (i – 1) ∗ Size + 1. Macintosh/MPW. In addition to this book. and Townsend. many UNIX platforms. the implementation of Icon (Griswold and Griswold. and other DrawRectangle(Offset – Edge – 1. Offset – 1. Size) } return Icon evolved through a series of versions. Offset – Edge – 1. } Offset + (j – 1) ∗ Size + 1) J WDelay(500) # pause to avoid blurred motion while ∗Pending() > 0 do { case Event() of { "q": exit() "p": until Event() === "c" } Icon Resources } every i := 1 to ∗solution do { j := solution[i] if (i + j) % 2 = 1 then Fg("black") else Fg("white") FillRectangle(Offset + (i – 1) ∗ Size. many technical DrawRectangle(Offset – 1. VAX/VMS. The address for anonymous FTP is ftp. reports.354 Sample Programs App. technical support. UNIX. and Windows NT. Jeffery. . and one on graphics Size. the Icon program library. Offset + (j – 1) ∗ Size. forthcoming). Microsoft procedure DrawBoard() Windows.cs.arizona. queens ∗ Size + 2 ∗ Edge + 1) is located at return http://www. there are links to general information about Icon. the Amiga. j also are earlier versions for several other platforms.and 1990-). 1986). there is a book on FillRectangle(Offset + i ∗ Size. . which presently end is available for the Acorn Archimedes. reference 355 . documentation. On the World Wide Web. All implementations of Icon are in the public domain. materials are available via the Internet. the Icon program library. 1978. I end From there.

cd /icon and get README.arizona. See also garbage Information about Icon also is available from Icon Project Department of Computer Science The University of Arizona Glossary P. argument list: a list of expressions that provide values for parameters in a procedure call. This glossary assumes familiarity with computer terminology. activation: evaluation of a co-expression. J Glossary 357 From there.O. 357 .lang.S. send mail to icon-group-request@cs. Box 210077 Tucson. To subscribe. and some terms have been used differently in different documents.356 Access to Icon Material App. Icon terminology developed over time. associativity: the order in which like operators are evaluated in the absence of parentheses. allocation: the process of providing space in memory for values created during program execution. in which case the last (right-most) operator is evaluated first. sometimes used to mean Documentation about Icon uses some terms in a technical way. assignment: association of a value with a variable. This glossary explains such terms.icon handles news related to Icon. See also disjunction. in which case the first (left-most) operator is evaluated first or right-to-left. Arizona 85721-0077 U.arizona. The newsgroup comp.A. alternation: a control structure that generates the results of its first operand followed by the results of its second operand. Associativity can be left-to-right. There also is a mailing list connected to the newsgroup via a gateway. voice: (520) 621-6613 fax: (520) 621-4246 e-mail: icon-project@cs. argument: an expression that provides a value for a function or procedure call. What follows reflects current usage.

Different kinds of data structures are orga- ters are used to represent letters. Control backtracking is the underlying mechanism for accomplish- binary operator: an operator with two operands. procedure. Command-line arguments are passed to the There are seven kinds of declarations: global. and Characters are represented internally by small nonnegative integers (typically tables. null. main procedure as a list of strings in its first argument. control backtracking: returning control to previously evaluated but suspended onym for the former. tial order of evaluation of expressions. Icon has 12 data types: co-expression. and so forth. comparison operation: a binary operation that compares two values according to a default case clause: a component of a case expression that contains an expression specified criterion. each record decla- tation of characters. . used to test if two expressions both succeed. as opposed to a control structure: an expression whose evaluation may alter the otherwise sequen- feature written in Icon. Icon structures are records. built-in: a feature that is part of the Icon programming language. machine. invocable. drawing. integer. conversion: see type conversion. Conjunction of the right operand. In addition. with some text so that the text is substituted for subsequent uses of the symbol conditional compilation: the inclusion or exclusion of source code as the result of in the program. call: see invocation. collating sequence: the sorting order for strings imposed by the internal represen. bounded expression: an expression that is limited to at most one result because of control character: a character that has special interpretation in an input/output the syntactic context in which it appears. by a value. A comparison operation succeeds and returns the value of that is evaluated if no other expression is selected in a case expression. Data backtracking occurs only for a few specific operations. co-expression: an expression coupled with an environment for its execution. Otherwise it fails. conditional directives. file. and static. augmented assignment: assignment combined with a binary operation. and then the result is assigned to the left-operand variable. The term data type often is shortened to type. default value: a value that is provided in place of an omitted or null-valued compilation: the process of converting Icon source code to code for a virtual argument of a function. and value comparison. backtracking: control backtracking or data backtracking. data type: a designation that identifies values that share common properties and coercion: implicit type conversion. Icon has no character data type. generators. If the data backtracking: restoring previous values to variables during control backtrack- expression is a generator. Some characters have associated glyphs. record. lists. punctuation marks. has the effect of logical and. local. Examples are backspace and newline. usually used as a syn. operations. 8 bits). ration defines a data type. ing goal-directed evaluation. invoked from a command line. procedure. a value that affects the window. lexical comparison. and conditional directive: a preprocessor directive that includes or excludes source text written to the window. real. context. code depending on whether or not a preprocessor symbol is defined. case expression: a control structure in which the expression to evaluate is selected cset: an unordered collection of characters.358 Glossary Glossary 359 attribute: in the context of graphics. command-line argument: a string given after the program name when Icon is declaration: a component of a program that specifies its properties and structure. ing. See also numerical case clause is indicated by the reserved word default. table. Charac. comparison. A default its right operand if the criterion is satisfied. list. character: the elementary unit from which strings and csets are composed. See also infix operator. cset. data structure: a collection of values. set. See also: mutual evaluation and disjunction. sets. conditional code: source code that is included or not included in a program as the define directive: a preprocessor directive that associates a preprocessor symbol result of preprocessing. The result of compiling a source code file is a pair of ucode files for the default table value: a value specified when a table is created to serve as the value virtual machine. nized and accessed in different ways. string. and window. corresponding to keys that are not in the table. See also limitation. The binary conjunction: a binary operation that evaluates its operands but performs no operation is performed on the value of the left-operand variable and the value computation on them. cursor: the position in string scanning. link. its results can be obtained one at a time by activation. digits.

used to describe the effect of alternation. make a choice. ware. environment variable: a named attribute of the system environment under which generator: an expression that is capable of producing more than one result. and from the beginning of execution to the end. This is accomplished by setting the keyword &error. file: stored data. element: a value in a record. Escape sequences usually are used for characters that cannot would fail. graphics: drawing. a user action such as a mouse click or typed heterogeneous structure: a structure whose elements have different types. Goal-directed evaluation is implicit in expression evaluation. passed as arguments to procedures. execution is called a run-time error. and images in a window. error directive: a preprocessor directive that forces an error in compilation. or punctuation mark. image: see string image. . by calling collect(). homogeneous structure: a structure all of whose elements have the same type. and returned by dereferencing: producing the value of a variable. field: an element of a record. goal-directed evaluation: the attempt to produce a successful outcome by resuming escape sequence: a sequence of characters in a string or cset literal that encodes a suspended generators to get alternative values when an expression otherwise single character. dialog: in the context of graphics. also iteration and control backtracking. or set. directive: a preprocessor command. Dereferencing floating point: an approximate representation of real numbers in computer hard- also can be done explicitly using the dereferencing operator. a value of any type. An error that occurs during an entire program. also an Icon data type that references such a file. a program runs. statement. See also error conversion. also called coercion. error: a condition or situation that is invalid. evaluation: execution of an expression to produce its outcome. icode: the result of linking ucode files to produce executable code for the Icon virtual machine. All data types in Icon are first class. digit. An error in compilation prevents linking. cally when the value of a variable is needed in a computation. event: in the context of graphics. garbage collection: the process of reclaiming space in memory that has been disjunction: logical or. See be given literally. Garbage collection occurs automatically tion. allocated but is no longer needed.360 Glossary Glossary 361 deque: a “double-ended queue” that allows both addition and removal at each end. Failure is not an error. failure: the lack of a result. identifier: a string of characters that names a variable. global variable: a variable whose value is accessible throughout the entire program error conversion: changing run-time errors to expression failure rather than pro. Errors may occur during compilation. An error in global declaration: a scope declaration that makes a variable accessible throughout linking prevents the production of an icode file. execution: the process of running an Icon program resulting from compilation and linking. Icode files are in a binary format that depends to some extent on the expression: a component of a program that performs a computation. or a key/value pair in a table. first-class data type: a data type whose values can be used without restriction: Icon lists are deques. linking. Failure is the opposite of success. include directive: a preprocessor directive that copies a file into a program. and in which the user can enter text. list. a temporary window that provides information font: the size and general appearance of text written in a window. character that a program can detect. See also architecture of a specific computer. implicit conversion: type conversion that occurs automatically as needed. Environment variables can be used to specify the size of Icon’s generic procedure: a procedure that accepts arguments of any type and/or returns memory regions. expression evaluation that does not produce a result. Garbage collection can be forced dump: see termination dump. gram termination. Dereferencing is done automati. and so forth. assigned to variables. and so on. usually on magnetic media such as disk. See also conjunc. the locations of libraries. glyph: a graphic symbol such as a letter. text. function: a built-in procedure. generation: the production of more than one result in sequence. GIF: a format used for storing image data in a file. procedures. or execution. when insufficient space remains for allocation.

In UNIX. Some- link declaration: a declaration that causes a library module to be included in a times the term object is used for just data structures. initial clause: an optional component of a procedure that contains expressions to be list: a data structure that consists of a sequence of values called elements. in DOS. any value. member: a value in a set. 0. be accessed by position (subscripted) and as stacks and queues. the line terminator is a linefeed initially. large these conventions. Contrast with reserved word. literal: a sequence of characters in a source program that directly represents a value. Limitation can be function or procedure. Some keywords are variables. invocable declaration: a declaration that specifies procedures that are to be in. There are also collating sequence. and data structures. such as 137. Linking may combine ucode files directive. and –15. Also called storage. See also: newline character. mutual evaluation: an expression consisting of an argument list but with no limitation: restricting the number of times a generator is resumed. also called element. but not when a procedure suspends. See also: global variable iteration: production of all the results of a generator. The result of a specific argument can the generator appears. lexical scoping: A method of scoping that depends on the text of a program rather than on the program state during execution. files. Iteration can be accomplished and static variable. lexical comparison: comparison of strings “alphabetically” according to the nu- merical values used to represent characters. from several compilations to produce a single icode file. matching function: a function that returns a portion of the subject in string scanning. infix operator: an operator that appears between operands. Also called storage region. memory: the space in which a program and the objects it creates are stored. be selected by an integer preceding the argument list. More specifically. operand: an expression that provides a value for an operation. Local variables are sometimes used synonymously. See also argument. These are strings. The result is a real number. See also binary opera. Icon identifiers have the null value the end of a line of text in a file. on the Macintosh. Invocation and call are declared and during a single invocation of the procedure. Lists can evaluated only on the first invocation of the procedure. See also bounded expression. by a control structure or by conjunction with an expression that always fails. A mutual evaluation expression succeeds only if all the specified by a control structure or occur because of the syntactic context in which expressions in the argument list succeed. created when a procedure is invoked and are destroyed when a procedure returns or fails. it is a linefeed object: in the most general sense. Such procedures may be called using string invocation. mixed-mode arithmetic: arithmetic performed on a combination of integers and real numbers. line terminator: a character or pair of characters that is used by convention to mark null value: the single value of the null type. Memory is implemented in RAM. Icon uses lexical scoping. Other platforms generally use one of represented by a pointer to memory. it is the return character. real numbers. character. local variable: a variable that is accessible only to the procedure in which it is invocation: the evaluation of a procedure or function. separate memory regions for strings and for other objects. a value that is character followed by a return character. program during linking. procedures. See memory region: a portion of memory used for storing Icon values. key: a value used to identify an entry in a table. keyword: An ampersand (&) followed by a string of letters that has a special meaning. Also called string comparison. suitable for execution. linking: the process of converting one or more pairs of ucode files into an icode file tor. co-expressions. csets. integers. The term sometimes is extended to include matching procedures. . even if there is no explicit reference to them such as the integer 1 and the string "hello". Positional integer: a whole number. See also goal-directed evaluation. a data type. library module: a file consisting of one or more procedures or other declarations that have been compiled into ucode so that they may be incorporated in a program module: see library module. line directive: a preprocessor directive that sets the source-program line number newline character: the single character used to represent a line terminator in Icon and file name for diagnostic purposes. accesses produce variables. cluded when a program is linked. regardless of the actual representation used in the underlying system. in the program. by linking. windows.362 Glossary Glossary 363 include file: a file that is copied into a program as a consequence of an include linker: the program that converts ucode to icode.

procedure returns. See reserved word: a string of letters that has syntactic meaning and cannot be used as also define directive. run-time system: a collection of routines used during program execution. run-time: the time during program execution. A record size operation. expression are evaluated. Run-time errors procedure: a computational unit whose definition is cast in the form of an identifier. pointer semantics: the representation of structures by references to their locations record: a data structure consisting of a fixed number of values that are referenced by in memory. example. run-time error: an error that occurs during program execution. polymorphous operation: an operation that applies to more than one data type. preprocessor symbol: a name associated with some replacement text in the prepro. Queue access is called first-in. cause program termination unless error conversion is enabled. in a list. . There may be several references to the first. precedence: the order in which unlike binary operators in an unparenthesized record declaration: a declaration that defines a record. This preprocessing: a step prior to compilation in which directives can be used to define is an abstract concept used for characterizing generators. Icon lists can be used as queues. include files. procedure return: irrevocably leaving the invocation of a procedure. result sequence: the sequence of results that a generator is capable of producing. ∗X. Sometimes used in a broader a procedure whose arguments are co-expressions and whose call has braces sense to include function and procedure calls to distinguish expressions that instead of parentheses around the argument list. The operator with the highest precedence is evaluated reference: a value that identifies a structure. not a program con- constants. Paths are used for locating library real: a data type that approximates real numbers. struct. return: see procedure return.364 Glossary Glossary 365 operation: an expression that is part of the built-in computational repertoire of Icon programmer-defined control structure: a control structure that is implemented by and cast in the form of an operator and operands. followed by a list of parameters to be used in the computation. Reals are represented in floating modules and include files. (radix). parameter: an identifier in a procedure declaration that specifies a variable to which radix literal: an integer literal that is expressed as a value given to a specified base a value is passed when the procedure is called. See also suspen- functions) and declared procedures. The term procedure includes both built-in procedures (also called resumption: continuing the evaluation of a suspended generator. outcome: a result or failure as a consequence of evaluating an expression. tives. prefix operator: an operator that stands before its operand. cessor. allowing multiple variables to refer to the same structure. program state: a global condition that affects an aspect of program execution. field names. Contrast with keyword. is an example. predefined symbol: a preprocessor name for which there is a built-in definition. For tion. defined control operation. same structure. and include or exclude code conditionally. first- window. Parameters are local variables. local. tracing is a global state. There are three kinds of scope: global. Preprocessor symbols may be predefined or defined by define direc. The record constructor: a function that creates an instance of a record. an identifier. See also outcome. All prefix operators in result: a value or a variable produced by evaluating an expression. path: a specification for the location of a file. queue: a sequence of values in which values are added at one end and removed from palette: a specification of a list of colors that can be used for drawing an image in a the other. passing arguments: the assignment of argument values in a procedure call to the range specification: a specification for consecutive characters in a string or values parameters of the procedure. See also: stacks and deques. out (FIFO). but sometimes it is used in the more sion. operator: a symbol consisting of one or more characters that designates an opera. The fields of a record are variables. constructor is provided automatically for every record declaration. which names the procedure. Icon are unary operators. point format. restricted sense of the latter. scope: the extent in time and location in which a variable is accessible. it may produce a result or it may fail. and static. Also called programmer- perform computation from control structures. When a scanning: see string scanning.

or in any event if termination dumping is enabled. the movement of a cursor position in it. Type conversion can be performed explic- name for an operator resembles the symbols that designate the operator. or operator by its string type: see data type. &output is the standard output file. A section is a list subscript: a value used as an index to select an element of a structure or a substring separate from the list from which it is derived. table: a data structure composed of key/value pairs. string invocation: the invocation of a function. structure of that type and increases by one for each newly created structure of success: evaluation of an expression that produces a result. If explicit type conversion cannot be done. Icon lists can be used as stacks. Stack access is called last-in. serial number: a number that uniquely identifies a structure or window. Tables can be subscripted by a value of any type. the opposite of failure. statement: a component of a program that determines how computations are done but performs no computation of its own. first-out (LIFO). written by default. itly by using type-conversion functions. Syntax errors are detected during general term element. subject: the string on which string scanning operates. The string implicit type conversion or coercion. unary operator: an operator with one operand. structure: see data structure. of a string. Type conversion string name: a string that identifies a function. Each type of structure has its own sequence of serial numbers that starts with 1 for the first substring: a string within a string. that type. procedure. Ucode files are readable text. Strings in Icon are values in their own right. See also traceback: a listing of procedure calls leading to the evaluation of the current expression.366 Glossary Glossary 367 section: a list formed from consecutive values in another list. also: queues and deques. translated mode: a mode of input/output in which line terminators in files are string: a sequence of characters. the default table value is produced. or operator. the value of &trace is nonzero. transmission: passing a value to a co-expression when it is activated. standard input: the file from which information is read by default. static declaration: a scope declaration that makes a variable accessible to all invocations of the procedure in which the declaration appears but nowhere else. performed. type-conversion function fails. thrashing: a situation in which garbage collection occurs frequently because the amount of available memory is small. See also prefix operator. all other subscripts are integers. tracing: diagnostic information about procedure calls and co-expression activation that is written to standard error output. type conversion: converting a value from one data type to another. . See also untranslated mode. A value in a set is called a member and sometimes by the more syntax error: a grammatical error in a program. suspension: interruption of the evaluation of a generator when a result is produced. cally translated to line terminators on writing. If implicit type conversion cannot be string scanning: high-level string analysis using the concepts of a subject string and done. this is called name for a function or procedure is just the name by which it is used. procedure. stack: a sequence of values in which values are added and removed at only one end. Table subscripting produces variables. not automatically translated into newlines on reading and newlines are automati- arrays of characters. set: a data structure consisting of distinct values upon which set operations can be See also resumption. If the standard input file. Each record type has its own sequence of serial numbers. termination dump: a listing of information upon program termination. storage: see memory. The string occurs automatically when a value is not of the expected data type. string image: a string that describes a value. &errout is the standard error output file. standard error output: the file to which error messages and tracing information is termination: the end of execution. a run-time error occurs. name. table does not contain the key. &input is the table lookup: referencing a table by a key to produce the corresponding value. standard output: the file to which information is written by default. Icon has no statements. See Tables can be subscripted by keys to assign or access corresponding values. ucode: the result of compiling Icon source code into code for Icon’s virtual machine. Tracing is a program state enabled when static variable: a variable with static scope. A traceback is provided when a program terminates with a run-time error. expression. compilation. in which keys are distinct.

E. The University of Arizona. 1980. See also translated mode. Dijkstra. Lee.R. 37-44. window: a rectangular area of the screen in which drawing can be done and in which user events can be accepted.A. Arizona: Department of Computer Science. See also define directive. American National Standard Code for Information Interchange. and some keywords.