Previous | Table of Contents | Next |
Scanning Environments
The subject and the position in it constitute a scanning environment. Before beginning a scanning expression, the current scanning environment is saved, and it is restored when the new scanning expression terminates. This allows scanning expressions to be nested.
An example is
while line := read() do { result := line ? { while field := tab(upto(,)) do { field ? { if =X then next } result ||:= left(field, Width) move(1) } } write(result ||:= left(tab(0), Width)) }
which omits fields that begin with X.
The function pos(i) succeeds if the current position in the subject is i but fails otherwise. The argument of pos(i) can be a nonpositive specification. For example, pos(1) succeeds if the position is before the last character in the subject.
The keywords &subject and &pos contain the values of the subject and position in the current scanning environment. They change when the scanning environment changes.
The position in the subject can be changed explicitly by assignment to &pos. For example,
&pos := 1
sets the position to the beginning of the subject. Assignment to &pos fails if the position would be outside the range of the subject.
In most situations, it is not necessary to refer to &subject and &pos explicitly. There are situations, however, in which this is useful. See section 6.3.2.
Procedure calls do not change the scanning environment. This allows procedures to be used for scanning within a scanning expression. An example is
procedure blankx() if =X then return else return tab(0) end
which could be used to replace fields that begin with an X by blank fields, leaving other fields unchanged, as in
while line := read() do { result := line ? { while field := tab(upto(,)) do { field := { field ? blankx() } result ||:= left(field, width) move(1) } } write(result ||:= left(tab(0), width)) }
Icon provides four kinds of structures for organizing and accessing collections of values in different ways:
Structures are created during program execution. The values in structures can be of any type, and a structure can contain values of different types. All structures except records can change in size during program execution.
6.2.4.1. Records
Records are declared, as in
record rational(numer, denom)
which declares a record named rational with field names numer and denom.
Instances of records are created during program execution by using a function whose name corresponds to the record name and whose arguments correspond to the fields, as in
portion := rational(2, 3)
A record declaration adds a type corresponding to the record name to Icons built-in type repertoire. For example, type(portion) produces rational.
Record fields are accessed by name using the binary dot (.) operator, as in
portion.numer := 1
which changes the numer field of portion to 1.
Record fields also can be accessed by position, as in
portion[2] := 5
which changes the denom field of portion to 5.
6.2.4.2. Lists
A list consists of a sequence of zero or more values. A list is created by an expression in which the values are enclosed in square brackets, as in
primaries := [red, blue, green]
A list also can be created by the function list(i, x), which produces a list of i values, all of which are x. For example,
grades := list(35, 0)
assigns to grades a list of 35 values, all of which are 0.
An empty list, which contains no values, can be produced by [] or list(0).
The values in a list are called elements. The elements in a list can be accessed by using subscripts, as in
write(primaries[2])
which writes blue. Elements also can be changed by assigning to a subscript, as in
grades[21] +:= 10
which adds 10 to the twenty-first element of grades.
Nonpositive specifications can be used for subscripting lists. For example,
write(primaries[1])
writes green.
Two lists can be concatenated to produce a new list using the operation L1 ||| L2, as in
newgrades := grades ||| list(5, 0)
which assign to newgrades a list of 40 values.
The section operation, L[i:j], produces a new list consisting of elements i through j of L.
6.2.4.3. Using Lists as Queues and Stacks
There are five functions for adding or removing values from the ends of lists, allowing lists to be used as stacks and queues. In this usage, the first element of a list is at its right end and the last at its left. The functions are
The way these functions work is illustrated by this diagram:
An example of using stack and queue access is this code segment that writes the input file in reverse order:
lines := [] # start with empty list while push(lines, read()) # add lines at beginning while write(get(lines)) # write lines from beginning to end
Previous | Table of Contents | Next |