Programming Corner from Icon Newsletter 22


October 21, 1986 ; Icon Version 6

Archiving Programs

Our readers frequently ask for some examples of simple programs that do not require an extensive knowledge of Icon to understand. Here are two that are quite simple and lend themselves to extensions that provide good exercises for beginning Icon programmers.

Most computer systems have some kind of a facility for combining files within a common file that can be used for transporting a large number of small files from one place to another or just to keep track of them. Such archiving facilities have many features, but most of them are system-dependent.

Here are two simple, relatively portable, Icon programs for archiving files and de-archiving them. The idea is simply to concatenate the files to be archived to make one large file. A header precedes each file, giving its name. An rather arbitrary string, "!!!!!", is chosen to distinguish headers; it cannot occur in any file to be archived (but see the exercises).

The archiving program takes a list of file names to be archived from standard input:
procedure main()
    while name := read() do {
      input := open(name) |
          stop("cannot open \"",name,"\"")
      write("!!!!!",name)
      while write(read(input))
      close(input)
      }
end
Note the use of an alternative to produce an error message in case a named file cannot be opened. On most systems it is important to close a file once it is no longer needed, as shown, to release space used by the i/o system for reuse.

The de-archiving program is just a little more complicated:
procedure main()
   while line := read() do{
      line ? if ="!!!!!" then {
         close(\out)
         out := open(name := tab(0),"w") |
            stop("cannot open ",name)
         }
      else write(out,line)
      }
end
As lines are read in, they are examined for headers. For archives constructed by the program above, the first line is always a header. (What would happen if it were not?) When a header is found, the previous file is closed, the new file name is taken from the rest of the line, and the new file is opened. If the line is not a header, however, it is written to the current file.

There is one "trick" used here that is, in fact, good idiomatic style in Icon -- the file is closed only if it is not null-valued. This happens only when the first header is encountered. At this point, out is null-valued because no assignment has been made to it yet. Thus, \out fails and close is not called. Subsequently, out is assigned a (non-null) file value and \out succeeds. This idiom takes advantage of the fact that the initial values of variables in Icon are null. It saves special coding for the start-up case.

The two programs above are crude, but generally workable. There are all kinds of possibilities for improvements and extensions:

A Simple Calculator

The following program, based on one written by Steve Wampler when his hand-held calculator broke, is a good illustration of the use of lists as stacks and of the motivation for the string invocation of operations:
procedure main()
   local stack, token, arg1, arg2
   stack := []
   while token := read() do
      if numeric(token) then push(stack,token)
      else if proc(token,2) then {
         arg2 := pop(stack) | {
            write(&errout,"*** empty stack ***")
            next
            }
         arg1 := pop(stack) | {
            write(&errout,"*** empty stack ***")
            next
            }
      push(stack,result := token(arg1,arg2)) |
         write(&errout,"*** operation failed ***")
         write(result)
         }
   else write(&errout,"*** invalid entry ***")
end
The calculator takes successive lines of input as numerical computations in reverse-polish notation. If the input token is numeric, it is pushed. Otherwise, there is a check to see if the token is a binary operator: proc(token,2). This function, which is an extension to Version 5 of Icon, fails if token is not a string representing a binary operator. For example, "+" is such a string, but "$" is not. If the token represents a binary operator, two arguments are popped off the stack and the operator is applied to them. The result is pushed and the loop continues.

As exercises, consider the following:
Icon home page