MACRO 05/20/78 MACRO NAME macro - process macro definitions SYNOPSIS macro [file] ... DESCRIPTION Macro reads the source file(s) and writes onto the standard output a new file with the macro definitions deleted and the macro references expanded. If no file names are specified, the standard input is read. Macros are generally used to extend some underlying language to perform a translation from one language to another; that is, a macro processor allows one to define symbolic constants so that subsequent occurrences of the constant are replaced by the defining string of characters. The general format is: define(name,replacement text) All subsequent occurrences of "name" in the file will be replaced by "replacement text". Blanks are significant and may occur only inside the replacement text. Upper and lower case letters are also significant. Nesting of definitions is allowed, as is recursion. The definition may be more than one line long. An elementary example of a macro is: define(EOF,-1) Thereafter, all occurrences of "EOF" in the file would be replaced by "-1". Macros with arguments may also be specified. Any occurrence in the replacement text of "$n", where n is between 1 and 9, will be replaced by the nth argument when the macro is actually called. For example, define(copen,$3 = open($1,$2) if ($3 == ERR) call cant($1)) would define a macro which, when called by "copen(name, READ, fd)" would expand into: fd = open(name,READ) if (fd == ERR) call cant(name) If a macro definition asks for an argument that wasn't -1- MACRO 05/20/78 MACRO supplied, the "$n" will be ignored. Macros can be nested, and any macros encountered during argument collection are expanded immediately--unless they are surrounded by brackets "[]". That is, any input surrounded by [ and ] is left absolutely alone, except that one level of [ and ] is stripped off. Thus it is possible to write the macro "d" as define(d,[define($1,$2)]) The replacement text for "d", protected by the brackets is literally "define($1,$2)" so one could say d(a,bc) and be assured that "a" would be defined to be "bc". Brackets must also be used when it is desired to redefine an identifier: define(x,y) define(x,z) would define "y" in the second line, instead of redefining "x". To avoid redefining "y", the operation must be expressed as define(x,y) define([x],z) The macro processor also includes a conditional test, with the built-in function "ifelse". The input ifelse(a,b,c,d) compares "a" and "b" as character strings. If they are the same, "c" is pushed back onto the input; if they differ, "d" is pushed back. As a simple example, define(compare,[ifelse($1,$2,yes,no)]) defines "compare" as a two-argument macro returning "yes" if its arguments are the same, and "no" if they are not. The brackets prevent the "ifelse" from being evaluated too soon. Another built-in function available is "incr". "incr(x)" converts the string "x" to a number, adds one to it, and returns that as its replacement text (as a character string). "x" had better be numeric, or the results may be undesireable. "incr" can be used for tasks like define(MAXCARD,80) define(MAXLINE,[incr(MAXCARD)]) -2- MACRO 05/20/78 MACRO which makes two parameters with values 80 and 81. The third built-in function available in the macro processor is a function to take substrings of strings. substr(s, m, n) produces the substring of "s" which starts at position "m" (with origin one), of length "n". If "n" is omitted or too big, the rest of the string is used, while if "m" is out of range the result is a null string. For example, substr(abc, 2, 1) results in "b", substr(abc, 2) results in "bc", and substr(abc,4) is empty. The last built-in function available in the macro processor is one to perform simple arithmetic functions: arith(operand1,op,operand2) where the operation specified by 'op' may be + (add), - (subtract), * (multiply), or / (divide). Negative numbers are not handled yet. Thus, define(add,[arith($1,+,$2)]) add(5,3) would produce the result '8'. As a final example, here is a macro which computes the length of a character string: define(len,[ifelse($1,,0,[incr(len(substr($1,2)))])]) Note the recursion, which is perfectly permissible. The outer layer of brackets prevents all evaluation as the definition is being copied into an internal table. The inner layer prevents the "incr" construction from being done as the arguments of the "ifelse" are collected. The value of a macro call "len(abc)" would be 3. -3- MACRO 05/20/78 MACRO FILES None SEE ALSO Kernighan and Plauger's "Software Tools", pages 251-283 DIAGNOSTICS arg stack overflow The maximum number of total arguments has been exceeded. Currently this is 100. call stack overflow The maximum level of nesting of definitions has been exceeded. Currently this is 130. EOF in string An end-of-file has been encountered before a bracketed string has been terminated. evaluation stack overflow The total number of characters for name, definition, and arguments has been exceeded. Currently this is 500. unexpected EOF An end-of-file was reached before the macro definition was terminated. filename: cant open For some reason, the file specified could not be opened. This is an unlikely error to occur; if it does show up it probably indicates a problem with the low-level primitives being used by the system. AUTHORS From "Software Tools" by Kernighan and Plauger, with minor modifications by Debbie Scherrer. BUGS/DEFICIENCIES There can be no space between the "define" and the left-parenthesis following it. Keywords (e.g. define, ifelse, etc.) in the input file must be surrounded by brackets if they are not part of a macro--otherwise they will be stripped out by the processor. Likewise, if brackets are desired anywhere in the input file other than in a macro, they must be surrounded by brackets themselves. The error messages generated by the ratfor compiler when processing macros do not seem to show up in this processor. Examples are "definition too long", "missing comma in define", -4- MACRO 05/20/78 MACRO and "non-alphanumeric name". -5-