# remove_definition --- delete a previous definition subroutine remove_definition include "rp_com.i" integer skip_whitespace, lookup character id (MAXTOK), text (MAXTOK) untyped info (SYMINFOSIZE) if (skip_whitespace (id) ~= IDSYM) { SYNERR ("Identifier must follow 'undefine'"p) return } call delete_underscores (id, id) if (skip_whitespace (text) ~= ')'c) { SYNERR ("Right paren must follow identifier in 'undefine'"p) return } if (lookup (id, info, Id_table) == NO || info (SYMBOLTYPE) ~= DEFID_SYMBOLTYPE) return call dsfree (info (SYMBOLDATA)) call delete (id, Id_table) return end # invoke_macro --- process invocation of a macro subroutine invoke_macro (info) untyped info (SYMINFOSIZE) include "rp_com.i" integer i, np, j integer ctoc character defn (MAXDEF) pointer table (MAXPARAMS) np = 0 if (info (SYMBOLVAL) > 0) # this define requires parameters call get_actual_parameters (table, np) DEBUG call print (ERROUT, "invoke_macro: *i actual parameters*n"p, np) j = 1 for (i = info (SYMBOLDATA); Mem (i) ~= EOS; i += 1) { if (Mem (i) ~= IDSYM) { defn (j) = Mem (i) j += 1 } else { i += 1 if (np >= Mem (i)) # if it was specified j += ctoc (Mem (table (Mem (i))), defn (j), MAXDEF - j + 1) } if (j >= MAXDEF - 1) { SYNERR ("result of define invocation too long"p) break } } defn (j) = EOS DEBUG call print (ERROUT, "invoke_macro: define string: '*s'*n"p, defn) call putback_str (defn) for (i = 1; i <= np; i += 1) call dsfree (table (i)) return end # enter_definition --- enter name and definition of macro subroutine enter_definition include "rp_com.i" character id (MAXTOK), text (MAXTOK) integer t, np integer skip_whitespace, get_formal_parameters, lookup pointer params, p pointer get_definition untyped info (SYMINFOSIZE) t = skip_whitespace (id) if (t ~= IDSYM) { SYNERR ("only identifiers may be defined"p) return } call delete_underscores (id, id) t = skip_whitespace (text) if (t == '('c) { # are there formal parameters? if (get_formal_parameters (params, np) == ERR) return t = skip_whitespace (text) } else { np = 0 params = 0 } DEBUG call print (ERROUT, "enter_definition: *i formal parameters*n"p, np) if (t ~= ','c) { SYNERR ("define identifer must be followed by a comma"p) if (params ~= 0) call rmtabl (params) return } p = get_definition (params) if (p == ERR) # he found an error return if (lookup (id, info, Id_table) == YES # deallocate old definition && info (SYMBOLTYPE) == DEFID_SYMBOLTYPE) call dsfree (info (SYMBOLDATA)) info (SYMBOLTYPE) = DEFID_SYMBOLTYPE info (SYMBOLVAL) = np info (SYMBOLDATA) = p DEBUG call print (ERROUT, "enter_definition: entered: *s, *i, *i*n"p, DEBUG id, np, p) call enter (id, info, Id_table) return end # dgetsym --- get a symbol for the define processor character function dgetsym (text) character text (ARB) integer tl character c include "rp_com.i" ngetch (c) if (IS_LETTER (c)) { text (1) = c tl = 1 ngetch (c) while (IS_LETTER (c) || IS_DIGIT (c) || c == '_'c || c == '$'c) { if (tl >= MAXTOK) { SYNERR ("token too long"p) break } text (tl + 1) = c tl += 1 ngetch (c) } text (tl + 1) = EOS call putback (c) DEBUG call print (ERROUT, "dgetsym: returning *i '*s'*n"p, IDSYM, text) return (IDSYM) } text (1) = c text (2) = EOS DEBUG call print (ERROUT, "dgetsym: returning *i '*s'*n"p, c, text) return (c) end # get_formal_parameters --- place the formal parameter list in a table integer function get_formal_parameters (table, number) pointer table integer number integer t integer skip_whitespace character text (MAXTOK) pointer mktabl untyped info (SYMINFOSIZE) table = mktabl (SYMINFOSIZE) number = 0 repeat { t = skip_whitespace (text) if (t ~= IDSYM) { SYNERR ("define formal parameters must be identifiers"p) call rmtabl (table) return (ERR) } call delete_underscores (text, text) number += 1 info (SYMBOLVAL) = number # put it in the table call enter (text, info, table) t = skip_whitespace (text) if (t ~= ','c && t ~= ')'c) { SYNERR ("commas must separate define formal parameters"p) call rmtabl (table) return (ERR) } } until (t == ')'c) return (OK) end # skip_whitespace --- get next symbol and skip NEWLINES & blanks integer function skip_whitespace (text) character text (ARB) integer t integer dgetsym repeat t = dgetsym (text) until (t ~= NEWLINE && t ~= ' 'c) return (t) end # get_definition --- collect a definition & stuff it into dynamic storage pointer function get_definition (table) pointer table include "rp_com.i" integer nlpar, buflen, l integer dgetsym, lookup, length character defn (MAXDEF), text (MAXTOK), id (MAXTOK), inquote pointer sdupl untyped info (SYMINFOSIZE) nlpar = 0 inquote = ' 'c buflen = 1 defn (1) = EOS repeat { select (dgetsym (text)) when ('('c) if (inquote == ' 'c) nlpar += 1 when (')'c) if (inquote == ' 'c) { nlpar -= 1 if (nlpar < 0) break } when ('"'c) { if (inquote == ' 'c) inquote = '"'c else if (inquote == '"'c) inquote = ' 'c } when ("'"c) { if (inquote == ' 'c) inquote = "'"c else if (inquote == "'"c) inquote = ' 'c } when (EOF) { SYNERR ("Missing right paren or EOF in define text"p) break } when (IDSYM) { call delete_underscores (text, id) if (table ~= 0 && lookup (id, info, table) == YES) { text (1) = IDSYM text (2) = info (SYMBOLVAL) text (3) = EOS } } l = length (text) if (buflen + l >= MAXDEF) { SYNERR ("definition too long"p) break } call scopy (text, 1, defn, buflen) buflen += l } # end repeat if (table ~= 0) call rmtabl (table) DEBUG call print (ERROUT, "get_definition: text: '"p) DEBUG for (l = 1; defn (l) ~= EOS; l += 1) DEBUG if (defn (l) ~= IDSYM) DEBUG call putch (defn (l), ERROUT) DEBUG else { DEBUG l += 1 DEBUG call print (ERROUT, "[*i]"p, defn (l)) DEBUG } DEBUG call print (ERROUT, "'*n"p) return (sdupl (defn)) end # get_actual_parameters --- collect an actual parameter list subroutine get_actual_parameters (table, np) pointer table (MAXPARAMS) integer np integer t integer dgetsym, collect_actual_parameter character buf (MAXDEF), text (MAXTOK) pointer sdupl repeat t = dgetsym (text) until (t ~= ' 'c) if (t ~= '('c) { np = 0 call putback_str (text) return # this is legal, but frowned upon } # (possible shouldn't be legal) for (np = 1; np <= MAXPARAMS; np += 1) { t = collect_actual_parameter (buf) table (np) = sdupl (buf) if (t == EOF) return } SYNERR ("Too many actual parameters specified"p) np = MAXPARAMS return end # collect_actual_parameter --- collect a single actual parameter; # returns EOF *and* a string on last call integer function collect_actual_parameter (buf) character buf (MAXDEF) integer i, nlpar character c, inquote include "rp_com.i" i = 1 inquote = ' 'c nlpar = 0 repeat { ngetch (c) select (c) when ('('c) if (inquote == ' 'c) nlpar += 1 when (')'c) if (inquote == ' 'c) { nlpar -= 1 if (nlpar < 0) break } when ('"'c) { if (inquote == ' 'c) inquote = '"'c else if (inquote == '"'c) inquote = ' 'c } when ("'"c) { if (inquote == ' 'c) inquote = "'"c else if (inquote == "'"c) inquote = ' 'c } when (','c) if (inquote == ' 'c && nlpar <= 0) break when (EOF) { SYNERR ("unbalanced paren or EOF in define actual parameter list"p) break # don't give up; upper routine up cleans up table for us } buf (i) = c i += 1 if (i >= MAXDEF) { SYNERR ("define actual parameter too long"p) break } } # end of repeat buf (i) = EOS DEBUG call print (ERROUT, "collect_actual_parameter: '*s'*n"p, buf) if (c == ','c) return (OK) return (EOF) end # delete_underscores --- remove underscores from an identifier # ('in' and 'out' can be the same string) subroutine delete_underscores (in, out) character in (ARB), out (ARB) include "rp_com.i" integer i, j integer mapdn j = 1 for (i = 1; in (i) ~= EOS; i += 1) { if (in (i) ~= '_'c) { if (ARG_PRESENT (m)) out (j) = mapdn (in (i)) else out (j) = in (i) j += 1 } } out (j) = EOS return end