An Icon Pre-Processor Frank J. Lhota Mei Associates, Inc. 1050 Waltham Street Lexington, MA 02173-8024 Voice: (617) 862-3390 FAX: (617) 862-5053 The Icon Programming Library comes with an Icon preprocessor called IPP. I have made several enhancements to this program, and I would like to submit the enhanced version of the IPP to the IPL. New IPP features For those who are not familiar with the IPP, the header comments in the IPP.ICN file provide complete intructions on its use. The rest of this section assumes a familiarity with the previous version of the IPP. This new version of the IPP processes #line directives, which can be used to change the value of the _LINE_ and _FILE_ symbols. Also, the new IPP wiil generates #line directives when needed, so that the preprocessor output will always indicate the original source of its text. As a result, if we pipe the output of IPP to icont, e.g., iconx ipp.icx foo.icn | icont -ofoo - then (assuming that the source itself does not have any line directives) the &file and &line keywords refer to the lines in the original source file, not to "stdin" and the line numbers of the IPP output. The #line directives will be generated even when other comments are being stripped from the input. The preprocessor command syntax has been relaxed a bit. The basic form of a preprocessor command line is still $command [arguments] but now the user is permitted to include spaces around the '$', so that preproccessor commands can have a pretty-print look, e.g. $ifndef FOO $if BAR = 0 $ define FOO -1 $else $ define FOO BAR $endif $endif # ndef FOO - 1 - On non-UNIX systems, the new IPP has a more liberal search algorithm for $include files. For files enclosed with <>, the directories specified in the IPATH environment variable are searched for the file. The search for file enclosed in "" starts with the current directory, then proceeds to the IPATH directories. As before, the -I command line option can be used to add directories to the beginning of the standard search path. The following preprocessor commands have been added to IPP: $elif: Invoked as 'elif constant-expression'. If the lines preceding this command were processed, this command and the lines following it up to the matching $endif command are ignored. Otherwise, the constant-expression is evaluated, and the lines following this command are processed only if it produces a result. $error: This command issues a error, with the text coming from the argument field of the command. As with all errors, processing is terminated. $warning: This command issues a warning, with the text coming from the argument field of the command. In addition to the operators previously supported, the constant expressions appearing in $if / $elif command can now use the unary versions of the '+' and '-' operators, and the 'not' control structure. Also, backtracking is used in the evaluation of constant expressions, so that when the command $if FOO = (2|3) is processed, the lines following it are processed precisely when either FOO equals 2 or FOO equals 3. Uses of the IPP To understand the following examples, the reader should keep in mind this feature of the IPP: The IPP creates a pre-defined symbol out of each string generated by &features. These symbols are created by taking the non-letter characters of the &features strings and replacing them with underscores. Thus, if &features includes UNIX, the symbol UNIX is defined; if co-expressions are supported, the symbol co_expressions is defined, and so on. The IPP can be an handy tool for distributing Icon programs that require some customization for specific implementations. A prime example of this is the IPP itself. IPP must be able to contruct a - 2 - full pathname for a file, given a directory and file name. On many systems, this is done by performing the catenation directory || "/" || filename This file naming convention is not, however, universal. On DOS and OS/2 systems, "\\" should be used instead of "/" to separate the directory and filename. Under VMS, the separator should be "". To accomodate these system-dependant variations, the IPP source (in the file IPP.ICN, on this disk) is written using the symbol DIR_SEP for the string that separates the directory and filename portions of a complete path. The IPP code starts with the preprocessor directives: $ifndef DIR_SEP $ifdef UNIX $define DIR_SEP "/" $elif def(MS_DOS) | def(MS_DOS_386) | def(OS_2) $define DIR_SEP "\\" $elif def(VMS) $define DIR_SEP "" $else $error Need a definition for DIR_SEP $endif $endif # ndef DIR_SEP After preprocessing this code, DIR_SEP will be "/" on UNIX systems, and "\\" on DOS and OS/2 systems. For other systems, an appropriate value for DIR_SEP could be specified on the preprocessor command line by using the -D options, e.g. ipp -D DIR_SEP=\"\" ipp.ipp ipp.icn Another example of Icon software that could exploit IPP customization is BINCVT, the IPL package of utilities for converting between integers and their internal binary representations. The version of BINCVT currently included in the IPL assumes a "big-endian" system. On "big-endian" systems, the bytes in the binary representation of an integer are arranged from most significant to least significant. However, major platforms such as the IBM PC family or the VAX machines use the "little-endian" method for storing integers, in which the bytes representing an integer go from least significant to most significant. Using IPP, one can write a version of BINCVT that can be preprocessed to produce a working package for either big-endian or little-endian systems. The symbol LITTLE_ENDIAN will be defined (via the command line option -D LITTLE_ENDIAN) to produce output for little endian systems. Most of the functions in BINCVT can be expressed in terms of starting at the most significant byte, and moving to the less significant bytes. Hence, the generalized BINCVT starts with the definitions: - 3 - $ifdef LITTLE_ENDIAN $define GOTO_BIG_END tab (0) $define TO_SMALL_END -1 $else $define GOTO_BIG_END $define TO_SMALL_END 1 $endif Using these definitions, we can write a version of the unsigned function that will work for either integer storage method: procedure unsigned(s) local result result := 0 s ? { GOTO_BIG_END while result := ord(move(TO_SMALL_END)) + result * 16r100 } return result end The file BINCVT.IPP on this disk contains the source code for this example. Conclusions The IPP allows Icon programmers to write more flexable and more portable code. The latest version of the IPP is easier to use and more powerful than the previous version. - 4 -