3
FWEB version 1.62 (September 25, 1998)
5
Based on version 0.5 of S. Levy's CWEB [copyright (C) 1987 Princeton University]
7
@x-----------------------------------------------------------------------------
10
\Title{MACS.WEB} % Macro processing for FTANGLE
14
@* MACROS. In the C~version of \WEB, namely \CWEB, the macro processor was
15
removed since C~has its own preprocessor. However, there are advantages to
16
having an internal processor when several languages are involved, even when
17
one wants to run a macro preprocessor on each language separately. For
18
example, the internal processor can modify the text of the outer macros, so
19
that setting one switch can affect conditional compilation in several
22
Here we collect the routines dealing with WEB's macro processor, which is
25
(Parts of this code are inelegant; the first goal was to achieve the
26
desired functionality. Some of the difficulties stemmed from attempting to
27
integrate this code into \CWEB. In any event, although one might achieve
28
somewhat more compact and elegant code by rewriting the macro processor
29
from scratch, that's not a trivial job.)
36
@<Typedef declarations@>@;
38
@<Global variables@>@;
40
@I typedefs.hweb /* Declarations common to both \FTANGLE\ and \FWEAVE. */
48
@i macs.hweb /* Macro definitions. */
54
@ The function prototypes must appear before the global variables.
57
#include "t_type.h" /* Prototypes for \.{ftangle.web}, etc. */
59
@ A token list of the current macro arguments is allocated dynamically.
63
IN_COMMON sixteen_bits HUGE *args; /* Token list of current macro arguments.
64
Allocated in |predefine_macros| just below. */
65
IN_COMMON BUF_SIZE max_margs; // Allocated length of |args|.
67
@ There may be predefined macros. These must be inserted into the
68
|macrobuf| during |common_init|.
71
predefine_macros(VOID)
73
new_mbuf(); // Here is the first, top-level allocation of the macro buffer.
75
@<Define internal macros@>; /* We accrete to this from various places, as
76
it becomes convenient to discuss the particular macro. */
77
t_macros(); // Internal macros from \.{ftangle.web}.
78
e_macros(); // Internal macros from \.{eval.web}.
81
@ We also introduce the concept of {\it internal macros}. These are
82
identifiers prefaced by `\.{\#\&}'. The identifier corresponds to a
83
function that is executed during macro expansion; the function places stuff
84
into the macro buffer. Internal macros are intended to be used only by the
85
designer of \FWEB, not by the user.
91
const char *name; // Identifier.
92
int len; // Length of identifier. Filled in by |ini_internal_fcns|.
93
SRTN (*expnd)PROTO((int,unsigned char **));
94
/* Function that expands this token. This prototype really
95
should read |(int,PARGS)|, but that didn't work on the DECstation. The
96
name |expand| also seemed special to the DECstation. */
101
sixteen_bits id; // The id code returned from |id_lookup|.
104
@ Here are all the internal functions and the associated names that invoke
108
INTERNAL_FCN internal_fcns[] = {
109
{"$$ASCII", 0, i_ascii_, 0xF, 1, NO, NO},
110
{"$ASSERT", 0, i_assert_, 0xF, 1, NO, NO},
111
{"$$CONST", 0, i_const_, 0xF, 2, YES, NO},
112
{"$DEFINE", 0, i_define_, 0xF, 1, NO, NO},
113
{"_DUMPDEF", 0, i_dumpdef_, 0xF, 0, YES, NO},
114
{"$DUMPDEF", 0, i_dumpdef_, 0xF, 0, YES, NO},
115
{"$$ERROR", 0, i_error_, 0xF, 1, NO, NO},
116
{"$$EVAL", 0, i_eval_, 0xF, 1, NO, NO},
117
{"$$GETENV", 0, i_getenv_, 0xF, 1, NO, NO},
118
{"$IF", 0, i_if_, 0xF, 3, NO, YES},
119
{"$IFCASE", 0, i_ifcase_, 0xF, 1, YES, YES},
120
{"$IFDEF", 0, i_ifdef_, 0xF, 3, NO, YES},
121
{"$IFNDEF", 0, i_ifndef_, 0xF, 3, NO, YES},
122
{"$IFELSE", 0, i_ifelse_, 0xF, 4, NO, YES},
123
{"_INPUT_LINE", 0, i_inp_line_, 0xF, 0, NO, NO},
124
{"$INPUT_LINE", 0, i_inp_line_, 0xF, 0, NO, NO},
125
{"$$KEYWORD", 0, i_keyword_, 0xF, 1, NO, NO},
126
{"_LANGUAGE", 0, i_lang_, 0xF, 0, NO, NO},
127
{"$LANGUAGE", 0, i_lang_, 0xF, 0, NO, NO},
128
{"$$LC", 0, i_lowercase_, 0xF, 1, NO, NO},
129
{"$$LEN", 0, i_len_, 0xF, 1, NO, NO},
130
{"$$LOG", 0, i_log_, 0xF, 2, NO, NO},
131
{"_LANGUAGE_NUM", 0, i_lnum_, 0xF, 0, NO, NO},
132
{"$LANGUAGE_NUM", 0, i_lnum_, 0xF, 0, NO, NO},
133
{"$M", 0, i_define_, 0xF, 1, NO, NO},
134
{"$$META", 0, i_meta_, 0xF, 1, NO, NO},
135
{"$$MIN_MAX", 0, i_min_max_, 0xF, 2, YES, NO},
136
{"$$MODULE_NAME", 0, i_mod_name_, 0xF, 0, NO, NO},
137
{"$$MODULES", 0, i_modules_, 0xF, 1, NO, NO},
138
{"$$NARGS", 0, i_nargs_, 0xF, 1, NO, NO},
139
{"_OUTPUT_LINE", 0, i_outp_line_, 0xF, 0, NO, NO},
140
{"$OUTPUT_LINE", 0, i_outp_line_, 0xF, 0, NO, NO},
141
{"$$ROUTINE", 0, i_routine_, RATFOR, 0, NO, NO},
142
{"_SECTION_NUM", 0, i_sect_num_, 0xF, 0, NO, NO},
143
{"$SECTION_NUM", 0, i_sect_num_, 0xF, 0, NO, NO},
144
{"$$SWITCH", 0, i_switch_, 0, 0, NO, NO},
145
{"$$TM", 0, i_tm_, 0xF, 1, NO, NO},
146
{"$$TRANSLIT", 0, i_translit_, 0xF, 3, NO, NO},
147
{"$UNDEF", 0, i_undef_, 0xF, 1, NO, NO},
148
{"$$UNSTRING", 0, i_unstring_, 0xF, 1, NO, NO},
149
{"$$UC", 0, i_uppercase_, 0xF, 1, NO, NO},
150
{"$$VERBATIM", 0, i_verbatim_, 0xF, 1, NO, NO},
151
{"$$VERSION", 0, i_version_, 0xF, 0, NO, NO},
152
{"_XX", 0, i_xflag_, 0xF, 1, NO, NO},
153
{"$XX", 0, i_xflag_, 0xF, 1, NO, NO},
154
{"", 0, NULL} // The null string terminates the list.
157
/* Put the internal function names into the table. */
159
ini_internal_fcns(VOID)
161
INTERNAL_FCN HUGE *s;
165
for(s=internal_fcns; (s->len=STRLEN(s->name)) != 0; s++)
167
ASCII HUGE *p = x_to_ASCII(OC(s->name));
169
s->id = ID_NUM_ptr(np,p,p+s->len);
171
np->equiv = (ASCII HUGE *)(m=text_ptr++);
172
np->macro_type = IMMEDIATE_MACRO;
174
m->tok_start = (eight_bits HUGE *)s->expnd; // NON-ANSI cast???
175
m->nbytes = 0; // Should be irrelevant.
176
m->text_link = macro;
177
m->Language = s->Language;
179
m->recursive = s->recursive;
180
m->var_args = s->var_args;
186
/* Regular macro definitions (temporarily) store the replacement text in
188
text_ptr->tok_start = tok_mem;
191
@ The |macrobuf| is maintained in |cur_state|. (See \.{stacks.hweb}.) Here
192
we allocate it. This is called both from \.{macs.web} and \.{ftangle.web}.
193
A separate copy of the macro buffer is maintained for each stack level;
194
it's allocated from |push_level| and freed from |pop_level|.
200
mp = cur_mp = macrobuf = GET_MEM("macrobuf",mbuf_size,eight_bits);
201
macrobuf_end = macrobuf + mbuf_size;
207
IN_TANGLE text_pointer cur_text; /* See \.{ftangle.web}. */
208
IN_TANGLE LINE_NUMBER nearest_line;
210
@* ARGUMENT PROCESSING.
211
On input, after the raw text of a \WEB\ macro has been tokenized, we must
212
go through and replace the dummy arguments by special tokens. The special
213
tokens consists of |MACRO_ARGUMENT| in the first byte, and the argument
214
number in the second byte.
218
argize FCN((start, end))
219
eight_bits HUGE *start C0("Beginning of the raw tokens.")@;
220
eight_bits HUGE *end C1("End.")@;
223
eight_bits HUGE *p, HUGE *last2, HUGE *start0;
224
boolean var_args; /* Whether variable arguments or not. */
226
start0 = start; /* Remember the beginning of the raw tokens. */
230
ERR_PRINT(M,"! Macro must start with identifier");
231
// SHOULD FLUSH HERE.
235
/* Determine the number~|k| of macro arguments and return starting position
236
of text after arguments. */
237
start = get_dargs(start,end,args,&k,&var_args);
238
cur_text->moffset = (unsigned char)(start - start0);
239
/* Offset to text after $(\dots)$ (or
240
to text after macro name if no arguments). */
241
cur_text->nargs = k; /* Number of macro arguments. */
242
cur_text->var_args = var_args;
244
/* Start after right paren. */
245
for(last2=p= start; p<end; p++)
251
@<Possibly argize a variable argument@>@;
259
continue; /* Skip ordinary token. */
262
/* At this point, it's a two-byte token. Search for match with argument
264
if(*p == MOD1 && *(p+1) == 0)
265
p += 5; // Skip line-number info.
268
/* The following effects |if(args[l] == *(sixteen_bits *)p)|. See the
269
analogous bit manipulations in |store_two_bytes|. */
270
if(args[l]>>8 == *p && (args[l] & 0x00FF) == *(p+1))
272
*p = MACRO_ARGUMENT; /* Mark as macro argument. */
273
*(p+1) = l; /* Store argument number in following
278
last2 = ++p; /* Advance over second byte of two-byte token.
279
Remember the position |last2| of a two-byte token so we can strip
280
off newlines properly below. */
283
@<Remove newlines and spaces from end of macro@>;
287
@ Tokenize the $n$th~variable argument, indicated by~\.{\#$n$}. The
288
counting starts with~1.
289
@<Possibly argize a var...@>=
291
int n; // The argument number; must be |int|.
292
eight_bits HUGE *q = p; // |q|~remembers the position of the number.
293
outer_char *tmp; // Temporary buffer for argument number.
296
if(*(p+1) != constant) continue; // This isn't the case \.{\#\It{n}}.
298
p += 2; // Position after |constant|.
300
for(i=0; p[i] != constant; i++)
301
; // Find the length of the constant.
303
tmp = GET_MEM("var arg buf",i+1,outer_char);
305
for(i=0; p[i] != constant; i++)
306
tmp[i] = XCHR(p[i]); // Convert to |outer_char|.
309
n = ATOI(tmp); // Eval.\ the arg.~\#, starting after |constant|.
311
/* \bfit SHOULD CHECK FOR TOO BIG HERE. */
313
FREE_MEM(tmp,"var arg buf",i+1,outer_char);
315
if(!var_args) MACRO_ERR("! #%d may only be used with variable-argument \
318
while(*p != constant) *p++ = ignore;
320
if(n < 0) MACRO_ERR("! #%d is not allowed",YES,n);
322
*(q+1) = @'0'; /* Marker for future expansion---the \# of variable
325
{/* Overwrite the \.\# and the |constant|. */
327
*(q+1) = (eight_bits)(k + (eight_bits)(n - 1));
328
// We must offset by the fixed number of arguments.
335
@ We must be careful not to interpret the second byte of a |sixteen_bits|
336
as a newline or a space.
337
@<Remove newlines...@>=
339
for(last2++; p > last2; )
340
if(*(p-1) == @'\n' || *(p-1) == @' ')
345
@ Here we determine the number of arguments, and return an array of the
346
identifier tokens of the dummy arguments. The function value is the
347
starting position of the token text after the arguments.
349
The macro |MAKE_16| makes a |sixteen_bits| from the two |eight_bits|
350
starting at |start|. It effectively does |*(sixteen_bits *)start|.
352
@d MAKE_16(start) (((sixteen_bits)(*start)<<8) + (sixteen_bits)(*(start+1)))
356
get_dargs FCN((start,end,args,n,pvar_args))
357
eight_bits HUGE *start C0("Start of token string.")@;
358
eight_bits HUGE *end C0("End of token string.")@;
359
sixteen_bits HUGE *args C0("Array of argument tokens, to be returned.")@;
360
eight_bits *n C0("Number of arguments found.")@;
361
boolean *pvar_args C1("Return whether variable arguments")@;
363
eight_bits k; // Counts the arguments.
364
sixteen_bits id_token; // Identifier for this macro.
366
*pvar_args = NO; // To begin, assume no variable arguments.
368
id_token = IDENTIFIER(*start, *(start+1));
369
start +=2; // After initial identifier.
374
return end; // No arguments and no replacement text.
377
{ /* No args; nothing exciting to do. */
378
while(start != end && *start == @' ')
379
start++; // Skip possible white space.
384
/* At this point, we've found the left paren of an argument list. */
385
for(k=0,++start; start != end && *start != @')'; ++k)
389
@<Check for |ellipsis| and |break| if found@>@;
391
err_print(M,"Invalid macro parameter in definition of macro \
392
\"%s\". Token %s is invalid; \
393
can only have identifiers and commas between (...)",
394
name_of(id_token), type1(*start));
398
if(k >= (eight_bits)max_margs)
401
args[k] = MAKE_16(start); // Store the argument token.
403
start += 2; /* After argument token, positioned now either on comma
407
start++; // Skip comma.
410
/* Usually get here when we've found the right paren. */
411
*n = k; // Number of arguments found.
414
{ /* Got to the end prematurely. */
415
err_print(M,"Missing right paren in definition of macro \"%s\"",
420
/* Special case of no argument list. We assume this means one dummy
422
if(*start == @')' && k == 0 && !*pvar_args)
425
return start + 1; // Position after right paren.
429
@<Check for |ellipsis|...@>=
431
if(*start == ellipsis)
433
if(*++start != @')') ERR_PRINT(M,"Expected ')' after ellipsis");
434
else *pvar_args = YES;
442
mac_args FCN((id_token))
443
sixteen_bits id_token C1("")@;
447
sprintf(temp, "arguments to macro \"%s\"", (char *)name_of(id_token));
448
OVERFLW(temp, ABBREV(max_margs));
451
@ For error processing, we have a function that returns a string describing
452
the value and kind of single-byte token.
454
@d TYPE_DESCR_LEN 20 /* Should be long enough to hold the reasonable type
455
descriptions that are constructed below. */
460
eight_bits c C1("")@;
462
outer_char *p = NULL;
463
static outer_char type_descr[TYPE_DESCR_LEN];
466
{SPRINTF(TYPE_DESCR_LEN,type_descr,`"'%c'",XCHR(c)`);} /* Printable
473
p = OC("constant"); @+ break;
476
p = OC("string"); @+ break;
479
p = OC("newline"); @+ break;
483
{SPRINTF(TYPE_DESCR_LEN,type_descr,`"'%s'",p`);}
484
/* Special \WEB\ token. */
486
{SPRINTF(TYPE_DESCR_LEN,type_descr,`"0x%x",c`);}
493
@ Functions to copy and compare $n$~bytes.
510
if(*s0 != *s1) return *s0 - *s1;
517
@ This function is used during output expansion. It fills an array of
518
pointers to the token strings for the actual arguments of a macro call
519
beginning at |start|. It returns the position of the token text after the
523
get_margs0 FCN((start, end, pcur_byte, pthe_end, multilevels,
525
eight_bits HUGE *start C0("Beginning of the tokens for this \
527
eight_bits HUGE *end C0("Maximum possible end.")@;
528
eight_bits HUGE **pcur_byte C0("Pointer to |cur_byte|.")@;
529
eight_bits HUGE **pthe_end C0("End of the current buffer.")@;
530
boolean multilevels C0("")@;
531
boolean var_args C0("Does macro have variable arguments?")@;
532
PARGS pargs C0("Array of pointers to the actual arguments, \
534
eight_bits *n C1("Number of arguments found.")@;
537
int bal, bbal; // Balance for parens and brackets.
538
boolean mac_protected;
539
sixteen_bits id_token; // Identifier for this macro.
541
id_token = IDENTIFIER(*start, *(start+1)); // Remember for error processing.
542
start +=2; // After initial identifier.
544
/* Read more arguments into buffer if necessary. */
545
if(start == end && pthe_end != NULL)
546
end = args_to_macrobuf(end, pcur_byte, pthe_end, multilevels, var_args);
548
/* Does a parenthesized list follow identifier? */
549
if(start==end || *start != @'(')
551
return pargs[*n = 0] = start; /* No args; nothing to do. Position
552
after macro name identifier. */
555
pargs[k=0] = start++; /* Beginning of first actual argument
556
token string. (Actually, this is the position of the left paren,
557
one less than the position of the first token. This is so the ending
558
position, which will point to a comma, can be used as the start of
559
the next argument. The value~1 is added in |x0macro|.) */
561
bal = 1; // Keep track of balanced parens. Already past the opening one.
562
bbal = 0; // Also keep track of balanced brackets.
563
mac_protected = NO; // Reverse accent protects commas, etc.
567
eight_bits c = *start;
574
if(start+1 < end && *(start+1) == @',')
575
{ /* Skip over `\.{\#,}'. */
576
*start = '\0'; // Replace '\.\#' by null.
584
for(start++; *start++ != c; );
593
mac_protected = BOOLEAN(!mac_protected);
594
*start++ = '\0'; /* Replace the protection
595
character by a null. */
598
/* The following scheme needs to be generalized. Doesn't check for syntax
599
such as `\.{[(]}' or `\.{([)}'. Probably must stack counters. */
606
MACRO_ERR("Unexpected ')' in macro argument",YES);
607
else if(bal > 0) bal--;
616
MACRO_ERR("Unexpected ']' in macro argument",YES);
617
else if(bbal > 0) bbal--;
621
if(!mac_protected && ( (bal==1 && bbal==0 && (c == @','))
623
{/* Found end of argument token list. Record the
628
pargs[k] = start++; /* Count the argument, skip
629
over comma or paren. */
630
if(bal==0) break; // End of arguments.
632
else start++; // Skip over one-byte token.
635
start += (c < MOD0 ? 2 : 4+4*1);
636
// Skip over two-byte token. (`1' for |line_info|.)
640
return start; // Positioned after right paren.
643
@* MACRO LOOKUP, etc.
644
Here we determine whether the |cur_val| computed during the output phase
645
corresponds to a \WEB\ macro. We return the appropriate |text_pointer|, or
646
|NULL| if it's not a macro. The function |mac_lookup| is an interface to
647
independently compiled modules.
651
mac_lookup FCN((cur_val))
652
sixteen_bits cur_val C1("Current id token.")@;
654
return (void *)MAC_LOOKUP(cur_val);
657
@ Corresponding to |MAC_LOOKUP|, there is an internal macro |_DEFINED|
658
that expands to~1 if its argument is a defined macro, or~0 otherwise. This
659
macro, however, essentially is obsolete since the advent of the |defined|
661
@<Define internal...@>=
663
SAVE_MACRO("$DEFINED(macro)$EVAL(defined #!macro)");
665
@ Furthermore, the macro |$IFDEF(a,b,c)| returns the expansion of~\.b if the
666
macro~\.a is defined; otherwise, it returns the expansion of~\.c.
668
@m DEF_RTN(name, cond)
670
i_##name##_ FCN((n,pargs))
676
eight_bits HUGE *p0 = pargs[0] + 1;
679
CHK_ARGS("$IFDEF", 3);
683
MACRO_ERR("! First argument of $IFDEF or $IFNDEF must be a macro", YES);
687
id = IDENTIFIER(p0[0], p0[1]);
688
e = ((m=mac_lookup(id)) != NULL && !(m->built_in));
698
DEF_RTN(ifndef, !e)@;
700
@ A similar macro implements the four-argument version of |ifelse|. Here,
701
we want to compare two strings that need not evaluate to numbers. Thus, we
702
can't use |_IF|, but must do it explicitly.
704
The following function compares its first two arguments on a byte-by-byte
705
basis. If they agree, the third argument is copied into the macro buffer;
706
otherwise, the fourth argument is copied.
709
i_ifelse_ FCN((n,pargs))
714
eight_bits HUGE *pp0, HUGE *pp1, HUGE *mp0, HUGE *mp1;
715
boolean args_identical = YES;
717
CHK_ARGS("$IFELSE", 4);
719
pp0 = xmac_text(mp0=mp, pargs[0] + 1, pargs[1]);
720
mp1 = mp; // |expr0| is now in |(pp0,mp1)|.
722
pp1 = xmac_text(mp, pargs[1] + 1, pargs[2]);
723
// |expr1| is now in |(pp1,mp)|.
725
/* Are the arguments identical? For speed, first check just the length of
726
the arguments; then compare byte by byte. */
727
if(mp-pp1 != mp1-pp0)
737
COPY_ARG(2,_ifelse_)@;
739
COPY_ARG(3,_ifelse_)@;
742
@ A general mechanism handles almost all such cases. (We use a \WEB\ macro
743
so we can pretty it up with |$EVAL|.)
744
Given the expression evaluator, |_IF| can be implemented enormously simply.
746
@m COPY_ARG(n,reason) {MCHECK(pargs[$EVAL(n+1)]-pargs[n]-1,#reason);
747
for(p0=pargs[n]+1; p0<pargs[$EVAL(n+1)]; ) *mp++ = *p0++;}
756
eight_bits HUGE *mp0;
762
pp = xmac_text(mp0=mp, p0=pargs[0]+1, pargs[1]); // Expand the expr.
772
@ A related routine |$IFCASE| behaves like \TeX's \.{\\ifcase}.
773
Expanding the first argument of the |$IFCASE| is a bit tricky, since
774
we're doing this from within a macro expansion. We use recursion;
775
watch out for resetting~|mp|.
778
i_ifcase_ FCN((n,pargs))
779
int n C0("Total number of arguments")@;
783
eight_bits HUGE *mp0;
786
CHK_ARGS("$IFCASE", -1);
787
pp = xmac_text(mp0=mp, pargs[0]+1, pargs[1]); // Expand the |ncase|.
788
ncase = neval(pp, mp);
790
copy_nth_arg(ncase, n-3, pargs); // Evaluate the |ncase|.
793
@ This function copies the $n0$th~argument (after the very first) to the
794
macro buffer. The cases are numbered 0--$n$, with case~$n+1$ being the default.
797
copy_nth_arg FCN((n0,n,pargs))
798
int n0 C0("Should be a non-negative integer")@;
799
int n C0("Cases are numbered 0--n, default")@;
804
if(n0 < 0 || n0 > n) n0 = n+1; /* Do the default case. */
806
n0++; /* Don't count the index argument. */
807
MCHECK(pargs[n0+1]-pargs[n0]-1,"copy_nth_arg");
808
for(p0=pargs[n0]+1; p0<pargs[n0+1]; ) *mp++ = *p0++;
811
@ We have not yet implemented a |_SWITCH| statement.
814
i_switch_ FCN((n,pargs))
819
@ Here are some things one can do with |_IF|.
820
@<Define internal...@>=
822
SAVE_MACRO("$ABS(a)$IF((a) > 0,$EVAL(a),$EVAL(-(a)))");
824
@ We need a facility to undefine macros. This must be done implicitly
825
before a new macro is defined; and may also be done explicitly through the
826
\.{@@\#undef} command.
830
undef FCN((cur_val, warning))
831
sixteen_bits cur_val C0("Token to be undefined.")@;
832
boolean warning C1("Complain is there's an error?")@;
834
name_pointer np = name_dir + cur_val;
837
if(np->macro_type == NOT_DEFINED)
840
MACRO_ERR("WARNING: \"%s\" is already undefined",YES,
847
if(np->equiv == NULL)
849
if(np->macro_type == IMMEDIATE_MACRO)
851
MACRO_ERR("Attempting to @@#undef deferred macro \"%s\" \
852
during phase 1; consider using $UNDEF(%s)",
853
YES, name_of(cur_val), name_of(cur_val));
857
MACRO_ERR("Missing equivalence field while undefining \"%s\"; \
858
this shouldn't happen!",YES,name_of(cur_val));
860
np->macro_type = NOT_DEFINED;
866
np->macro_type = NOT_DEFINED;
868
m = (text_pointer)np->equiv;
869
m->nargs = UNDEFINED_MACRO;
870
FREE(m->tok_start); // Should be |FREE_MEM|.
871
m->nbytes = m->moffset = 0;
877
We maintain a stack of macro id tokens that we are in the middle of
878
expanding. This is to prevent recursion.
882
XIDS HUGE *pids[MAX_XLEVELS];
885
@ Simple macros push or pop the id stack. We also need a routine to see if
886
an id is on the stack.
888
@d save_name(a) {if(xids->level >= MAX_XLEVELS)
890
MACRO_ERR("! Macro inner recursion depth exceeded",YES);
891
FATAL(M, "!! BYE.", "");
893
xids->token[slevel=xids->level++] = a;
896
@d unsave_name xids->level = slevel
899
boolean recursive_name FCN((a,xids,last_level))
900
sixteen_bits a C0("")@;
901
XIDS HUGE *xids C0("")@;
902
int last_level C1("")@;
906
/* Hunt through levels lower than the present one. */
907
for(i=0; i<last_level; i++)
908
if(xids->token[i] == a) return YES;
913
@ Macro error messages can print the recursion stack as an indication of
918
macro_err FCN(VA_ALIST((s, trail VA_ARGS)))
920
CONST outer_char s[] C0("Error message about macro expansion.")@;
921
int trail C2("Do we print out the expansion trail?")@;)@;
924
outer_char HUGE *temp, HUGE *temp1, HUGE *t, HUGE *near_line;
926
#if(NUM_VA_ARGS == 1)
927
CONST outer_char s[];
931
/* We allocate dynamically to keep the size of the stack down. */
932
temp = GET_MEM("macro_err:temp", N_MSGBUF, outer_char);
933
temp1 = GET_MEM("macro_err:temp1", N_MSGBUF, outer_char);
934
near_line = GET_MEM("macro_err:near_line", N_MSGBUF, outer_char);
936
VA_START(arg_ptr, trail);
937
vsprintf_((char *)temp1, (CONST char *)s, arg_ptr)@;
941
SPRINTF(N_MSGBUF, near_line, `"; near input l. %u", nearest_line`);
943
/* We surround the message that we construct with double quotes. These are
944
printed into the file, but not to the terminal. This is to help out
945
preprocessors that parse the message prematurely and get confused by
947
SPRINTF(N_MSGBUF, temp, `"\"%s. (%s l. %u in %s%s.) %s",
949
phase==1 ? "Input" : "Output",
950
phase==1 ? cur_line : OUTPUT_LINE,
951
phase==1 ? cur_file_name : params.OUTPUT_FILE_NAME,
953
trail && (xlevel > 0) ? "Expanding " : ""`);
955
t = temp + STRLEN(temp);
957
/* `Print out' levels associated with each invocation of |xmac_buf| by
958
attaching them to end of |temp|. */
959
if(trail && (xlevel > 0))
961
see_xlevel(&t, pids[i]);
963
ntemp = STRLEN(temp);
965
temp[ntemp+1] = '\0';
967
/* Message to file. */
968
OUT_MSG(to_ASCII(temp), NULL);
970
/* Message to terminal. */
971
temp[ntemp] = '\0'; // Kill off final quote.
972
printf("\n%s\n", (char *)to_outer((ASCII HUGE *)temp)+1);
976
FREE_MEM(temp, "macro_err:temp", N_MSGBUF, outer_char);
977
FREE_MEM(temp1, "macro_err:temp1", N_MSGBUF, outer_char);
978
FREE_MEM(near_line, "macro_err:near_line", N_MSGBUF, outer_char);
981
@ Print out all names stored at some recursive invocation of |xmac_buf|.
984
see_xlevel FCN((pt,p))
985
outer_char HUGE **pt C0("")@;
986
XIDS HUGE *p C1("")@;
990
level = p->level; /* Total number at this level. */
993
i++,sprintf((char *)(*pt),"%s",i==level ? ". " : ", "),(*pt)+=2)
994
prn_mname(pt,p->token[i]);
997
/* Print one name. */
999
prn_mname FCN((pt,token))
1000
outer_char HUGE **pt C0("")@;
1001
sixteen_bits token C1("")@;
1005
CONST ASCII HUGE *end;
1007
np = name_dir + token;
1011
for(p=np->byte_start; p<end; )
1012
*(*pt)++ = XCHR(*p++);
1018
i_inp_line_ FCN((n,pargs))
1020
PARGS pargs C1("")@;
1022
num_to_mbuf(n,pargs,"$INPUT_LINE",0,"nearest line",nearest_line);
1026
i_outp_line_ FCN((n,pargs))
1028
PARGS pargs C1("")@;
1030
num_to_mbuf(n,pargs,"$OUTPUT_LINE",0,"output line",OUTPUT_LINE);
1036
num_to_mbuf FCN((n,pargs,built_in_name,num_args,num_descr,num))
1038
PARGS pargs C0("")@;
1039
CONST char *built_in_name C0("")@;
1040
int num_args C0("")@;
1041
CONST char *num_descr C0("")@;
1044
CHK_ARGS(built_in_name,num_args);
1046
MCHECK0(20,num_descr);
1049
sprintf((char *)mp,"%d",num);
1050
to_ASCII((outer_char HUGE *)mp); // Convert the number in place to |ASCII|.
1056
@* EXPANDING a BUFFER.
1057
Here we actually expand a buffer possibly containing macros. The first
1058
call to |x0macro| will be a macro name itself, possibly with arguments.
1059
After that expansion, |x0macro| is called again repeatedly until nothing
1060
more can be expanded. The expansion will end when no |paste| tokens
1061
appeared during the previous cycle. The expansion is put into the next
1062
available position of |macrobuf|, which is pointed to by |mp|.
1066
x0macro FCN((p, end, xids, pcur_byte, pthe_end, multilevels))
1067
eight_bits HUGE *p C0("Present position in the input buffer.")@;
1068
eight_bits HUGE *end C0("Last filled position of the input \
1070
XIDS HUGE *xids C0("")@;
1071
eight_bits HUGE **pcur_byte C0("Pointer to |cur_byte|.")@;
1072
eight_bits HUGE **pthe_end C0("End of buffer.")@;
1073
boolean multilevels C1("")@;
1075
boolean expanded; /* Was a macro expanded in this pass? */
1077
eight_bits a0,a1; /* Left and right parts of |sixteen_bits| token. */
1078
text_pointer m; /* Points to info about current macro being expanded. */
1079
eight_bits HUGE *p0, HUGE *p1;
1080
eight_bits HUGE * HUGE *pargs = GET_MEM("pargs",max_margs,eight_bits HUGE *);
1081
boolean must_paste = NO,pasting = NO;
1082
int level0 = xids->level;
1083
boolean mac_protected = NO; /* Protection flag flipped by left quote. */
1085
expanded = NO; /* If no macros were expanded in this pass, then we're done. */
1087
/* |p| is current position in input buffer. */
1090
a0 = *p++; // The next token to be examined.
1092
if(p==end && a0==@'\n') break;
1094
if(TOKEN1(a0)) @<Process |eight_bits| token@>@;
1095
else @<Process identifier token@>@;
1098
/* Get directly to here from |MACRO_ERR|. */
1100
FREE_MEM(pargs, "pargs", max_margs, eight_bits HUGE *);
1101
return expanded; /* Return flag to say whether any macro was
1102
expanded. If nothing was, then we're done. */
1105
@ As we scan through the |macro_buf|, we either encounter |eight_bits|
1106
tokens, or identifiers (|sixteen_bits|). Here we process the single-byte
1107
tokens. If it's a left quote, we flip the protection flag. If it's
1108
|stringg|, we copy the entire contents to and including the concluding
1109
|stringg|. Otherwise, we just copy over the token.
1111
@<Process |eight_bits| token@>=
1116
mac_protected = BOOLEAN(!mac_protected);
1122
*mp++ = a0; // |stringg| or |constant| token.
1127
if(!TOKEN1(*mp=*p++))
1129
MCHECK(1,"id prefix");
1132
MCHECK(1,"8-bit token");
1136
if(a0 == stringg) @<Check for string concatenation@>@;
1141
case begin_language:
1142
MCHECK(2,"dot_const");
1149
*mp++ = a0; /* Copy over ASCII token to the macro buffer. */
1154
@ We implement an ANSI type of string concatenation feature.
1155
@<Check for string concat...@>=
1157
eight_bits HUGE *p00;
1159
/* Scan over possible white space. */
1160
for(p00=p; p < end; p++)
1161
if(*p != @' ' && *p != @'\t') break;
1163
if(p < end && *p == stringg)
1165
eight_bits mchar = *(mp-2);// Quote character from last string.
1166
eight_bits pchar = *(p+1);// Quote character from next string.
1168
if((mchar == @'\'' || mchar == @'\"') &&
1169
(pchar == @'\'' || pchar == @'\"'))
1171
mp -= 2; // Back over |stringg| and quote char.
1172
p += 2; // Move over |stringg| and quote char.
1176
else p = p00; // Didn't find another string.
1179
@ Deal with identifier while scanning through |macro_buf|.
1180
@<Process identifier token@>=
1182
a = IDENTIFIER(a0,a1= *p++);
1186
@<Copy |defined| and its argument@>@;
1190
/* If it's a macro token, we must decide whether to expand it. If this
1191
token is already on the |xids| stack from an earlier level of recursive
1192
expansion, then we don't expand. If we haven't encountered this name
1193
before, then we expand the macro. */
1194
if((m=MAC_LOOKUP(a)) != NULL)
1197
MCHECK(2,"protected macro token");
1201
else if(recursive_name(a,xids,level0))
1202
@<Don't expand macro.@>@;
1205
int slevel = ignore;
1208
save_name(a); // To prevent recursion.
1211
dbg_macs(a, p, end);
1214
@<Expand a macro@>@;
1220
{/* Copy a nonmacro 2-byte token to the output buffer (pointed to
1222
MCHECK(2,"ordinary id");
1226
/* If we're actually dealing with a module name, we punt here and don't
1227
expand it at this time; it will be expanded on output. */
1230
int n = 2 + 4*1; // `1' for |line_info|.
1232
MCHECK(n,"module defn");
1242
dbg_macs FCN((n, start, end))
1243
sixteen_bits n C0("")@;
1244
eight_bits HUGE *start C0("")@;
1245
eight_bits HUGE *end C1("")@;
1247
printf("%lu = (0x%x->0x%x) <<%lu>>: ",
1248
end - start, start, end, start - macrobuf);
1252
@ In macro expansions, the token |defined| gets special treatment. If it's
1253
followed by an identifier, that identifier should not be expanded.
1255
@d DEFINED_ERR(s) {MACRO_ERR(s,YES); goto done_expanding;}
1257
@d ERR_IF_DEFINED_AT_END if(p >= end)
1258
DEFINED_ERR("! `defined' ends prematurely")@;
1260
@<Copy |defined|...@>=
1262
MCHECK(6,"defined stuff");
1264
/* Copy the |defined| token. */
1268
ERR_IF_DEFINED_AT_END;
1269
if(TOKEN1(a0= *p++)) /* Possible parenthesis */
1271
if(a0 != @'(') DEFINED_ERR("! Invalid token after `defined'")@;
1274
ERR_IF_DEFINED_AT_END;
1275
if(TOKEN1(a0 = *p++)) DEFINED_ERR("! Invalid argument of `defined'")@;
1277
{ /* Copy parenthesized id token. */
1282
ERR_IF_DEFINED_AT_END;
1283
if(TOKEN1(a0 = *p++))
1284
if(a0 != @')') DEFINED_ERR("! Missing ')' after `defined'")@;
1288
{ /* Copy non-parenthesized id token. */
1295
@ The flag |keep_intact| is used with stringizing; it is set with the
1296
\.{\#*}~operation. It means that if the parameter is a string, just pass it
1297
through unchanged; don't add extra quotes arounds it.
1299
Other flags are used in conjunction with the~`\.{\#'}' and~`\.{\#"}'
1304
static boolean keep_intact;
1305
IN_COMMON boolean single_quote, double_quote;
1307
@ We endow the preprocessor with ANSI-C's stringize operation. Parameter
1308
tokens preceded by `\.{\#}' are converted into strings. We must follow the
1309
rest of \TANGLE's conventions; the string must be bracketed with |stringg|.
1310
@<Stringize parameter@>=
1312
eight_bits HUGE *begin;
1317
for(begin=pargs[*p0]+1; *begin == '\0'; begin++)
1318
; /* Skip over leading nulls (that possibly replace protection
1321
@<String token to |macrobuf|. @>;
1323
do_quote = BOOLEAN(!keep_intact || *begin != stringg || begin[1] != CUR_QUOTE);
1326
@<Quote token to |macrobuf|. @>@;
1328
str_to_mb(begin,pargs[*p0 + 1], YES);
1329
p0++; /* Don't put this into previous stmt, because order of evaluation is
1333
@<Quote token...@>@;
1335
@<String token...@>;
1337
single_quote = double_quote = NO;
1340
@ We must preface and end all strings with |stringg| tokens.
1341
@<String token...@>=
1342
MCHECK(1,"stringg"); @+ *mp++ = stringg@;
1344
@ The string delimiter depends in general on the language, but it can be
1345
overridden by the commands~`\.{\#'} or~`\.{\#"}, which set the flags
1346
|single_quote| or |double_quote|.
1348
@d CUR_QUOTE ((eight_bits)(single_quote || (!double_quote && R77_or_F) ?
1357
@ Now we prepare to copy/translate a token string into the |macrobuf|. To
1358
get the spacings right, we use an |OUTPUT_STATE| flag.
1360
OUTPUT_STATE copy_state;
1362
@ This function is analogous to |out_op|: It copies a string to the
1363
|macro_buf|, and set |copy_state|.
1367
CONST outer_char HUGE *s C1("String such as \.{++}.")@;
1374
copy_state = MISCELLANEOUS;
1377
@ When copying strings, certain intermediate characters must be escaped,
1378
depending on the language:
1381
str_to_mb FCN((begin_arg, end_arg, esc_chars))
1382
CONST eight_bits HUGE *begin_arg C0("Beginning of string.")@;
1383
CONST eight_bits HUGE *end_arg C0("End of string.")@;
1384
boolean esc_chars C1("Insert escape characters?")@;
1386
eight_bits HUGE *mp0 = mp;
1389
copy_state = MISCELLANEOUS;
1391
while(begin_arg < end_arg)
1393
if(TOKEN1(c= *begin_arg++))
1395
@<Flip copy state and escape certain characters@>@;
1401
if(copy_state == NUM_OR_ID)
1404
if(c == MACRO_ARGUMENT)
1405
@<Fill in argument number@>@;
1407
@<Handle identifier-like token@>@;
1409
copy_state = NUM_OR_ID;
1420
outer_char temp[10];
1423
n = NSPRINTF(temp,"$%d",*begin_arg++);
1432
@<Handle identifier-like...@>=
1434
c = IDENTIFIER(c,*begin_arg++);
1436
switch(c/MODULE_NAME)
1438
case 0: /* Ordinary identifier. */
1440
@<Copy possibly truncated identifier to macro buffer@>@;
1443
case 1: /* Module name. */
1444
MCHECK(5, "macro name");
1453
if(np->equiv != (EQUIV)text_info)
1454
@<Copy possibly truncated id...@>@;
1455
else if(c != UNNAMED_MODULE)
1457
// Temporary kludge; should actually write out the name.
1465
begin_arg += 4*1; // `1' for |line_info|.
1466
// Skip over line number info.
1471
@ Stringize an id token by copying the actual name into the |macro_buf|.
1473
@<Copy actual name to macro buffer@>=
1475
end = proper_end(np);
1478
MCHECK(end - p,"id name");
1479
while(p<end) *mp++ = *p++;
1482
@ Here we just copy a space into the |macro_buf|.
1485
MCHECK(1,"' '"); @+ *mp++ = @' ';
1488
@ Here we process a single-byte token during stringizing. We have to do
1489
many of the same operations that are done during output expansion.
1491
@<Flip copy state...@>=
1498
@<Copy cases like \.{!=}@>@;
1501
copy_state = UNBREAKABLE;
1505
if(copy_state==NUM_OR_ID)
1507
@<Copy stuff between |constant| or |stringg|@>@;
1508
copy_state = NUM_OR_ID;
1512
@<Copy stuff between |constant|...@>@;
1513
copy_state = MISCELLANEOUS;
1519
@<Make semi into string@>;
1524
esc_certain_chars(c,esc_chars);
1525
if(copy_state != VERBATIM) copy_state = MISCELLANEOUS;
1530
@<Make semi into string@>=
1538
@ Expand various internal codes during stringizing.
1540
@d CPY_OP(token,trans) case token: cpy_op(OC(trans)); break@;
1542
@<Copy cases like \.{!=}@>=
1544
CPY_OP(plus_plus,"++");
1545
CPY_OP(minus_minus,"--");
1546
CPY_OP(minus_gt,C_LIKE(language) ? "->" : ".EQV.");
1552
CPY_OP(not_eq,"!=");
1553
CPY_OP(and_and,"&&");
1555
CPY_OP(star_star,"**");
1556
CPY_OP(slash_slash,"//");
1557
CPY_OP(ellipsis,C_LIKE(language) ? "..." : ".XOR.");
1562
ASCII *symbol = dots[*begin_arg++].symbol;
1564
cpy_op(to_outer(symbol));
1565
to_ASCII((outer_char *)symbol);
1570
@ During stringizing, we must just copy verbatim constants or strings.
1571
(This assumes that no id tokens are buried inside strings.)
1572
@<Copy stuff between |constant|...@>=
1574
if(!keep_intact && c==stringg) esc_certain_chars(*begin_arg++,YES);
1575
/* Escape the opening quote. */
1577
while(*begin_arg != (eight_bits)c)
1579
MCHECK(1,"constant");
1580
*mp++ = *begin_arg++;
1583
if(!keep_intact && c==stringg)
1584
esc_certain_chars((sixteen_bits)*(--mp),YES); /* Escape the closing
1587
begin_arg++; /* Skip the closing |stringg| or |constant|. */
1590
@ During stringizing and certain other places, if the flag |esc_chars|
1591
is on, we should convert things like a bare double quote to the appropriate
1592
escaped form. This is language-dependent.
1596
esc_certain_chars FCN((c,esc_chars))
1597
sixteen_bits c C0("Character to be maybe escaped.")@;
1598
boolean esc_chars C1("Do we escape them?")@;
1601
if(C_LIKE(language))
1603
if(c==@'\\' || c==@'"')
1613
MCHECK(1,"doubled quote");
1614
*mp++ = (eight_bits)c; /* Double the quote in Fortran
1623
*mp++ = (eight_bits)c;
1627
/* We've added the escape character. Now copy the character itself. */
1628
MCHECK(1,"escaped character");
1629
*mp++ = (eight_bits)c;
1632
@ Associated with stringizing is a predefined macro that creates a string
1633
from an expanded argument.
1634
@<Define internal...@>=
1636
SAVE_MACRO("$STRING(expr)$STRING0(`expr`)"); /* Expand the argument.
1637
Quotes take care of possible commas in |expr|. */
1639
SAVE_MACRO("$STRING0(expr)#*expr");
1641
@ Here's a macro that takes the length of a string.
1642
@<Define internal...@>=
1644
SAVE_MACRO("$LEN(s)$$LEN(#*s)"); // Don't expand argument.
1646
@ The internal function that determines the length of a string.
1649
i_len_ FCN((n,pargs))
1651
PARGS pargs C1("")@;
1657
m = (int)(pargs[1] - pargs[0] - 5);
1658
/* 5: 1 from |pargs[0]|, 2 from |constant|, 2 from quotes.
1659
Should this be |unsigned|? */
1661
num = NSPRINTF((outer_char HUGE *)mp, "%d", m);
1662
MCHECK(num, "_len_");
1663
to_ASCII((outer_char HUGE *)mp);
1667
@ The inverse of |_STRING| just removes the quotes from a string, so that
1668
the string contents go verbatim to the output. We also introduce a special
1669
notation for the preprocessor symbol~'\.\#', namely~|$P|.
1671
@<Define internal...@>=
1673
SAVE_MACRO("$VERBATIM(s)$$VERBATIM(s)"); // Possibly expand the argument.
1675
SAVE_MACRO("$UNQUOTE(s)$$VERBATIM(s)"); // Alternative name.
1677
@% SAVE_MACRO("_P $VERBATIM(\"#\")"); // Preprocessor symbol.
1678
SAVE_MACRO("$P $VERBATIM($IF($LANGUAGE_NUM==2 || $LANGUAGE_NUM==4, \
1679
'#', \"#\"))"); // Preprocessor symbol; different quotes for \Fortran.
1681
SAVE_MACRO("$PP $UNSTRING($P)"); // A character, not a string; use for \Fortran.
1686
i_verbatim_ FCN((n,pargs))
1688
PARGS pargs C1("")@;
1690
eight_bits HUGE *p, delim[2];
1691
eight_bits quote_char[3];
1693
CHK_ARGS("$VERBATIM", 1);
1695
if(*(p = pargs[0]+1) != stringg)
1697
MUST_QUOTE("$VERBATIM", p, pargs[1]);
1701
STRNCPY(delim, @"\0\0", 2);
1702
STRNCPY(quote_char, @"\"\0\0", 3);
1704
/* At this point, |quote_char[0]| is initialized to a double quote. */
1708
quote_char[0] = @'\'';
1712
quote_char[1] = @'\''; // Two possibilities for \Fortran--90.
1722
/* Beginning |stringg| token. */
1723
MCHECK(1, "string token");
1726
/* Check to ensure it's really a quoted string. */
1727
delim[0] = *p; // Make the quote character into a string.
1729
if(STRSPN(delim, quote_char))
1730
p++; // Advance over the quote.
1734
while(*p != stringg)
1736
MCHECK(1, "verbatim token");
1740
/* Kill off the final quote, replacing it by |stringg|. */
1741
if(STRSPN(delim, quote_char))
1742
*(mp-- -1) = stringg;
1745
@ |$UNSTRING| strips off the |stringg| and possible quotes from a string.
1747
@<Define internal...@>=
1749
SAVE_MACRO("$UNSTRING(s)$$UNSTRING(s)"); // Possibly expand the argument.
1754
i_unstring_ FCN((n,pargs))
1756
PARGS pargs C1("")@;
1758
eight_bits HUGE *p,delim[2];
1759
eight_bits quote_char[3];
1761
CHK_ARGS("$UNSTRING", 1);
1763
if(*(p = pargs[0]+1) != stringg)
1765
MUST_QUOTE("$UNSTRING", p, pargs[1]);
1769
STRNCPY(delim, @"\0\0", 2);
1770
STRNCPY(quote_char, @"\"\0\0", 3);
1772
/* At this point, |quote_char[0]| is initialized to a double quote. */
1776
quote_char[0] = @'\'';
1780
quote_char[1] = @'\''; // Two possibilities for \Fortran--90.
1790
/* Skip beginning |stringg| token. */
1793
/* Check to ensure it's really a quoted string. */
1794
delim[0] = *p; // Make the quote character into a string.
1796
if(STRSPN(delim, quote_char))
1797
p++; // Advance over the quote.
1801
while(*p != stringg)
1803
MCHECK(1,"verbatim token");
1807
/* Kill off the final quote */
1808
if(STRSPN(delim, quote_char))
1812
@ An error routine for built-ins that don't get a quoted string as argument.
1814
@d MUST_QUOTE(name,p,p1) must_quote(OC(name),p,p1)
1818
must_quote FCN((name,p,p1))
1819
CONST outer_char *name C0("")@;
1820
eight_bits HUGE *p C0("")@;
1821
eight_bits HUGE *p1 C1("")@;
1823
MACRO_ERR("! Argument of %s must be a quoted string",YES,name);
1825
/* Just copy over the argument. */
1826
MCHECK(p1 - p,"copy quotes");
1827
while(p < p1) *mp++ = *p++;
1830
@ Here is another string-related macro, patterned after the
1831
\.{m4}~|translit|. The call ``|$TRANSLIT(s,from to)|'', where all three
1832
arguments are strings, modifies~|s| by replacing any character found in
1833
|from| with the corresponding character of~|to|. If |to|~is shorter
1834
than~|from|, characters that don't have an entry are deleted.
1836
@<Define internal...@>=
1838
SAVE_MACRO("$TRANSLIT(s,from,to)$$TRANSLIT(#*s,#*from,#*to)"); /* Make
1839
strings from the arguments (but do nothing if they're already strings). */
1844
i_translit_ FCN((n,pargs))
1846
PARGS pargs C1("")@;
1850
CHK_ARGS("$TRANSLIT",3);
1853
if(*(pargs[k]+1) != stringg) MACRO_ERR("! Argument %d of $TRANSLIT \
1854
must be a string",YES,k);
1856
translit((ASCII HUGE *)(pargs[0]+2),
1857
(ASCII HUGE *)(pargs[1]+2),
1858
(ASCII HUGE *)(pargs[2]+2));
1861
@ This function actually does the transliteration.
1863
@d CHECK_QUOTE(var,n) if(*var++ != end_char) MACRO_ERR("! Argument %d of \
1864
$TRANSLIT doesn't begin with '%c'",YES,n,end_char)@;
1868
translit FCN((s,from,to))
1869
CONST ASCII HUGE *s C0("String to be transliterated")@;
1870
CONST ASCII HUGE *from C0("Characters to replace")@;
1871
CONST ASCII HUGE *to C1("Replace by")@;
1873
short code[128],i,n;
1874
ASCII end_char = *s++;
1876
ASCII esc_achar PROTO((CONST ASCII HUGE * HUGE *));
1878
CHECK_QUOTE(from,1);
1881
@<String token...@>;
1883
/* First, construct the identity. */
1884
for(i=0; i<128; i++)
1887
/* Put the new characters into the table. */
1888
while(*(to+1) != stringg)
1890
if(*(from+1) == stringg) break; // Stop when the |from| characters end.
1892
/* We must watch out for escaped characters. */
1893
if((cfrom= *from++) == @'\\') cfrom = esc_achar(&from);
1894
if((cto= *to++) == @'\\') cto = esc_achar(&to);
1899
/* If there are more |from| characters than replacement ones, give the
1900
extra ones a special delete code of~|-1|. */
1901
if(*(from+1) != stringg)
1902
while(*(from+1) != stringg)
1904
if((cfrom= *from++) == @'\\') cfrom = esc_achar(&from);
1906
code[cfrom] = -1; // Delete code.
1909
/* Now translate the string. */
1910
while(*(s+1) != stringg)
1912
if((c= *s++) == @'\\') c = esc_achar(&s);
1914
if( (n=code[c]) == -1) continue; // Skip deleted characters.
1915
MCHECK(1,"_translit_");
1916
*mp++ = (eight_bits)n; // Put the translation into the |macrobuf|.
1919
@<String token...@>;
1922
@ This built-in returns an environmental variable.
1923
@<Define internal...@>=
1925
SAVE_MACRO("$GETENV(var)$STRING($$GETENV(#*var))");
1927
SAVE_MACRO("$HOME $GETENV(HOME)"); /* An important special case: the
1928
user's home directory. */
1930
@ First we make a string out of the argument. Then we query the
1931
environment for the requested variable. If we get |NULL|, we return the
1932
empty string; otherwise, we return the answer as an unquoted string of
1937
@d SAVE_ENV(aval) if(t < temp_end) *t++ = XCHR(aval);
1938
else OVERFLW("Env_buf","")@;
1942
i_getenv_ FCN((n,pargs))
1944
PARGS pargs C1("")@;
1947
outer_char *pvar, HUGE *t;
1948
outer_char HUGE *temp, HUGE *temp_end; /* Holds the name of the requested
1952
MACRO_ERR("Sorry, this machine doesn't support getenv",YES);
1955
CHK_ARGS("$GETENV",1);
1958
temp = GET_MEM("_getenv_:temp",N_ENVBUF,outer_char);
1959
temp_end = temp + N_ENVBUF;
1961
for(p=(ASCII HUGE *)(pargs[0]+3),t=temp; *(p+1) != stringg; )
1966
if( (pvar=GETENV((CONST char *)temp)) != NULL) mcopy(pvar);
1968
FREE_MEM(temp,"_getenv_:temp",N_ENVBUF,outer_char);
1970
#endif // |HAVE_GETENV|
1973
@ If the macro name is recursive, we don't expand it; we just copy the name
1975
@<Don't expand...@>=
1978
CONST ASCII HUGE *end;
1983
copy_id(np->byte_start,end,"recursive macro name");
1985
/* Can't do this; infinite recursion! */
1987
MCHECK(2,"recursive macro name");
1988
*mp++ = LEFT(a,ID0);
1995
@* EXPANDING a MACRO.
1996
Here is the heart of the macro processor. We must actually replace an
1997
expandable macro token by the replacement text. While processing the
1998
replacement text, the tokens~'\.\#' and |MACRO_ARGUMENT| have special
2003
eight_bits n = 0; // Number of actual arguments found.
2004
eight_bits HUGE *mp0=NULL, HUGE *mp1, HUGE *m_start, HUGE *m_end;
2005
boolean xpn_argument = YES;
2006
boolean last_was_paste;
2007
long max_n = 0; // Maximum statement label offset encountered.
2010
/* Get pointers to $n$~actual argument tokens. */
2011
if(m->nargs > 0 || m->var_args)
2012
p = get_margs0(p-2, end, pcur_byte, pthe_end, multilevels,
2013
(boolean)(m->var_args), pargs, &n);
2015
if( (!m->var_args && n != m->nargs) || (m->var_args && n < m->nargs) )
2017
MACRO_ERR("! Actual number of WEB macro arguments (%u) does not match \
2018
number of def'n (%u); %s",YES,n,m->nargs,
2019
n < m->nargs ? "missing ones assumed to be NULL" :
2020
"extra ones discarded");
2022
/* If there are too many, we'll just ignore the remainder. However, if
2023
there are too few, we'll essentially supply null arguments by fleshing out
2024
the pointer list. */
2027
pargs[n+1] = pargs[n] + 1;
2032
/* Copy macro text, substituting arguments. */
2033
m_start = mp; /* Remember the beginning. */
2034
last_was_paste = NO; /* Remember whether last token was |paste|. */
2038
(*(SRTN (*)(int,unsigned char **))(m->tok_start))(n,pargs);
2041
@<Expand ordinary macro@>@;
2043
/* If any |paste| tokens were encountered, implement them. */
2045
@<Paste expansion.@>@;
2050
xpn_before(m_start, xids, pcur_byte, pthe_end, multilevels);
2054
expanded = YES; /* If we pasted something, a new macro may
2055
have been created. */
2059
@<Expand ordinary macro@>=
2061
/* Beginning and end of the text for this macro. */
2062
p0 = m->tok_start + m->moffset;
2063
p1 = m->tok_start + m->nbytes;
2067
if(TOKEN1(a = *p0++))
2068
@<``Expand'' a one-byte token@>@;
2070
@<Copy two-byte macro token@>@;
2075
@<Copy two-byte macro...@>=
2077
eight_bits k = *p0++; // Second of the two bytes.
2079
if(a == MACRO_ARGUMENT)
2081
pasting = cp_macro_arg(pargs, k, n, &xpn_argument,
2082
last_was_paste, (boolean)(*p0 == paste));
2085
{/* Copy nonargument two-byte macro token. */
2086
last_was_paste = NO;
2088
MCHECK(2, "nonargument macro token");
2090
*mp++ = (eight_bits)a;
2093
if(a == MOD1 && k == '\0')
2094
{ /* Line-number info. */
2095
MCHECK(4, "line info");
2103
@ While processing a one-byte token, we must remember if the |paste| token
2104
appeared, because that means we have more work to do.
2107
if(!(a==@'#' && *p0==@'.')) last_was_paste = NO;
2109
if(p0==p1 && a==@'\n') break;
2114
@<Perform stringize or related cases@>@;
2119
*mp++ = (eight_bits)a; // |stringg| token.
2123
if(!TOKEN1(*mp=*p0++))
2125
MCHECK(1,"id prefix");
2128
MCHECK(1,"8-bit token");
2130
while(*mp++ != (eight_bits)a);
2135
case begin_language:
2136
MCHECK(2,"dot_const");
2137
*mp++ = (eight_bits)a;
2142
/* Copy over single-byte token; remember if it was |paste|. */
2143
MCHECK(1,"single-byte token");
2144
if( (*mp++ = (eight_bits)a) == paste)
2145
last_was_paste = must_paste = YES;
2150
@ Here we deal with a macro argument. (The argument number is in |*p0|,
2151
immediately after the token |MACRO_ARGUMENT|.)
2153
boolean cp_macro_arg FCN((pargs,k,n,pxpn_argument,
2154
last_was_paste,next_is_paste))
2155
PARGS pargs C0("")@;
2156
eight_bits k C0("Current argument to process")@;
2157
eight_bits n C0("")@;
2158
boolean HUGE *pxpn_argument C0("")@;
2159
boolean last_was_paste C0("")@;
2160
boolean next_is_paste C1("")@;
2163
eight_bits HUGE *begin_arg, HUGE *end_arg, HUGE *mp0=NULL;
2165
/* Check for requested argument number bigger than the maximum actually
2166
used in the call. */
2168
{ // Make it of zero length.
2169
pargs[k] = pargs[n];
2170
pargs[k +1] = pargs[n] + 1;
2173
begin_arg = pargs[k] + 1; /* The next byte (|k|) after the marker token
2174
has the argument number. Make
2175
|begin_arg| point to the token list of the appropriate actual
2177
while(*begin_arg==@'\n') begin_arg++;
2179
end_arg = pargs[k + 1]; /* The end is in the next element of |pargs|. */
2181
/* Check if the last (already copied to |macrobuf|) or next token to this
2182
parameter is |paste|. */
2183
if(last_was_paste || next_is_paste) pasting = YES;
2187
mp0 = mp; /* Remember where this argument text started. */
2190
/* Copy the tokens of the argument. If it's a null argument to be pasted,
2191
explicitly insert a null character to avoid a warning message and/or to
2192
prevent the paste from pasting the previous identifier. */
2193
if(begin_arg == end_arg)
2197
MCHECK(1,"null character");
2202
{/* Copy the argument. */
2203
MCHECK(end_arg - begin_arg,"argument tokens");
2204
while(begin_arg < end_arg) *mp++ = *begin_arg++;
2207
/* If the parameter is to be pasted, the argument does not get expanded.
2208
It also doesn't get expanded if it was immediately preceded by `\.{\#!}',
2209
in which case |xpn_argument| was set to |NO|.
2210
Otherwise, the argument gets expanded before finally substituting it for
2213
*pxpn_argument = YES;
2215
xpn_before(mp0, NULL, NULL, NULL, NO);
2220
@ In the ANSI preprocessor, the token `\.{\#}' must be followed by a macro
2221
argument, when it then means stringize the argument. Here we extend the
2222
usage to encompass other cases. If `\.{\#}' is followed by a macro token,
2223
the complete expansion of that macro will be substituted immediately, on
2224
input. If the construction `\.{\#!}' is followed by a macro token, the
2225
token definition of that macro will be copied, but tokens in that
2226
definition will not be expanded; otherwise, `\.{\#!}' must be followed by a
2227
macro parameter, which will be substituted but not expanded. The
2228
construction `\.{\#\&}' means execute the internal function whose id
2229
follows. `\.{\#:}$nnn$' is related to automatic generation of labels, where
2230
when $nnn = 0$ the statement number is assigned immediately (on input), and
2231
when $nnn > 0$ means generate the current statement number plus~$nnn$ on
2232
output, uniquely on each execution of the macro.
2234
@d DOES_ARG_FOLLOW(c)
2235
if(*p0 != MACRO_ARGUMENT)
2237
MACRO_ERR("! Macro token `#%c' must be followed by a parameter",YES,c);
2240
p0++@; // Skip over |MACRO_ARGUMENT|.
2242
@<Perform stringize or...@>=
2249
@<Expand internal function@>@; break;
2252
@<Generate statement label@>@; break;
2255
if(*p0 == MACRO_ARGUMENT) xpn_argument = NO;
2256
else MACRO_ERR("! Macro token '#!' must be followed by \
2262
DOES_ARG_FOLLOW('\'');
2267
DOES_ARG_FOLLOW('\"'); // Without the escape, bug on VAX.
2271
DOES_ARG_FOLLOW('*');
2273
/* Falls through to next case! */
2275
case MACRO_ARGUMENT:
2276
@<Stringize parameter@>@; break;
2279
@<Insert the number of variable arguments@>@;
2283
@<Insert the $n^{\rm th}$ variable argument@>@;
2287
@<Insert the $n^{\rm th}$ fixed argument@>@;
2291
@<Insert all of the variable arguments@>@;
2296
MACRO_ERR(_Xx("! Invalid token 0x%x ('%c') after '#'"),YES,
2297
*p0,isprint(*p0) ? *p0 : '.');
2303
@<Insert the number of var...@>=
2305
eight_bits HUGE *mp0; // For converting the number to |ASCII|.
2307
p0 += 2; // Skip over null tokens.
2309
MCHECK(4,"tokens for number of variable arguments");
2312
mp += NSPRINTF((outer_char *)mp0,"%d",n - m->nargs);
2313
to_ASCII((outer_char HUGE *)mp0);
2317
@ Format \.{\#[$n$]}: Insert the $n$-th fixed argument.
2319
@d INS_ARG_LIST pargs,m,n,&p0,&pasting,&xpn_argument,last_was_paste
2321
@<Insert the $n^{\rm th}$ fixed argument@>=
2322
expanded |= ins_arg(@'[',@']',INS_ARG_LIST);
2324
@ Format \.{\#[$n$]}: Insert the $n$-th variable argument.
2325
@<Insert the $n^{\rm th}$ variable argument@>=
2326
expanded |= ins_arg(@'{',@'}',INS_ARG_LIST);
2330
boolean ins_arg FCN((cleft,cright,
2331
pargs,m,n,pp0,ppasting,pxpn_argument,last_was_paste))
2332
ASCII cleft C0("")@;
2333
ASCII cright C0("")@;
2334
PARGS pargs C0("")@;
2335
text_pointer m C0("")@;
2336
eight_bits n C0("")@;
2337
eight_bits HUGE * HUGE *pp0 C0("")@;
2338
boolean *ppasting C0("")@;
2339
boolean *pxpn_argument C0("")@;
2340
boolean last_was_paste C1("")@;
2343
boolean next_is_paste = BOOLEAN(*(*pp0) == paste);
2344
eight_bits HUGE *pp;
2345
eight_bits HUGE *mp0 = mp;
2346
eight_bits HUGE *p00 = (*pp0);
2347
boolean fixed = BOOLEAN(cleft == @'[');
2350
if(*(*pp0) == cright)
2354
else if(TOKEN1(*(*pp0))) (*pp0)++;
2357
pp = xmac_text(mp0,p00,(*pp0)++);
2375
{ /* Insert the total number of arguments. */
2378
NSPRINTF(temp,"#%c0%c",5,XCHR(cleft),XCHR(cright));
2382
mp += NSPRINTF((outer_char *)mp0,"%d",n - (fixed ? 0 : m->nargs));
2383
to_ASCII((outer_char HUGE *)mp0);
2387
*ppasting = cp_macro_arg(pargs, (eight_bits)(k-1 + (fixed ? 0 : m->nargs)),
2388
n, pxpn_argument, last_was_paste, next_is_paste);
2393
@ Here we insert the complete list of variable arguments, separated by
2394
commas, as in~$a,b,c$.
2395
@<Insert all of the var...@>=
2398
boolean next_is_paste = BOOLEAN(*p0 == paste);
2400
for(k=m->nargs; k<n; k++)
2402
pasting = cp_macro_arg(pargs,k,n,&xpn_argument,
2403
(boolean)(last_was_paste && k==m->nargs),
2404
(boolean)(next_is_paste && k==(eight_bits)(n-1)) );
2408
if(*(mp-1) == @',') mp--;
2409
// If we inserted at least one arg, kill off last comma.
2415
eight_bits HUGE *begin_arg, HUGE *end_arg;
2417
begin_arg = pargs[k] + 1;
2418
while(*begin_arg==@'\n') begin_arg++;
2420
end_arg = pargs[k+1];
2422
MCHECK(end_arg - begin_arg+1,"variable argument tokens");
2423
while(begin_arg < end_arg) *mp++ = *begin_arg++;
2426
@ Here we append the tokens of a macro definition, without expanding them.
2430
MACRO_ERR("! Macro after #! may not have arguments",YES);
2433
eight_bits HUGE *q0, HUGE *q1;
2435
q0 = m->tok_start + m->moffset;
2436
q1 = m->tok_start + m->nbytes;
2438
/* Just copy the definition without expanding. */
2439
MCHECK(q1-q0,"unexpanded definition");
2445
@ Here we expand an argument exhaustively before final substitution.
2448
xpn_before FCN((mp0, xids, pcur_byte, pthe_end, multilevels))
2449
eight_bits HUGE *mp0 C0("Remember this end of |macro_buf|.")@;
2450
XIDS HUGE *xids C0("")@;
2451
eight_bits HUGE **pcur_byte C0("Pointer to |cur_byte|.")@;
2452
eight_bits HUGE **pthe_end C0("End of buffer.")@;
2453
boolean multilevels C1("")@;
2455
eight_bits HUGE *mp1;
2457
mp1 = xmac_buf(mp0, xids, pcur_byte, pthe_end, multilevels);
2458
// Expand argument before substitution.
2462
// Copy the expansion back to original place.
2464
mp = mp0; // Current end of |macrobuf|.
2467
@ When we encounter the juxtaposition `\.{\#\&}', the next identifier must
2468
correspond to an internal macro function. We get the address of that
2469
function, then execute it.
2470
@<Expand internal...@>=
2475
if(p0 == p1) MACRO_ERR("! Missing internal function name after #&",YES);
2478
if(TOKEN1(a = *p0++)) MACRO_ERR("! Identifier must follow #&",YES);
2479
else if(!x_int_fcn(id=IDENTIFIER(a,*p0++),n,pargs))
2480
MACRO_ERR("! Internal function name \"%s\" not defined",
2485
@ Here we expand a generic internal function.
2491
x_int_fcn FCN((id,n,pargs))
2492
sixteen_bits id C0("Token for internal function.")@;
2493
int n C0("Number of arguments")@;
2494
PARGS pargs C1("Array of pointers to arguments.")@;
2496
INTERNAL_FCN HUGE *f;
2498
for(f=internal_fcns; f->len != 0; f++)
2501
(*f->expnd)(n,pargs); /* Feed the internal function the list
2502
of (pointers to) arguments; put the expansion into the |macrobuf|. */
2506
return NO; /* Function not found. */
2509
@ The combination~`\.{\#:}$nnn$', where $nnn$~is a non-negative integer,
2510
expands to the next available automatic statement label plus~$nnn - 1$.
2511
@<Generate statement label@>=
2514
long n; // Label increment.
2515
outer_char *tmp; // Temporary buffer for the number.
2521
MACRO_ERR("Expected constant after \"#:\"",YES);
2525
p0++; // Position after |constant|.
2527
for(i=0; p0[i] != constant; i++)
2528
; // Find size of the constant.
2530
tmp = GET_MEM("stmt number",i+1,outer_char);
2532
/* Convert to |outer_char|, and also position to after |constant|. */
2533
for(i=0; *p0 != constant; i++, p0++)
2538
n = ATOL(tmp); // Convert the following number.
2540
FREE_MEM(tmp,"stmt number",i+1,outer_char);
2544
MACRO_ERR("! Invalid statement number offset (%ld) after #:; 1 assumed",YES,n);
2548
if(n > max_n) max_n = n; // Remember the maximum offset.
2550
MCHECK(2,"|constant|");
2553
m = NSPRINTF((outer_char *)mp,"%lu",max_stmt + n - 1);
2554
MCHECK(m,"stmt label");
2555
to_ASCII((outer_char HUGE *)mp);
2562
@ Pasting an expansion is rather complicated. We hunt through the tokens
2563
looking for |paste|. When we find it, the last and the next objects must be
2564
expanded side-by-side into their character representations in a buffer.
2565
Then this expansion must be re-tokenized and substituted for the original
2567
@<Paste expansion...@>=
2569
m_end = mp; /* End of the macro tokens to be scanned for pasting; beginning
2570
of the new, pasted expansion. */
2572
/* Copy from |mp0| to |mp|. If we find |paste|, execute that operation. */
2573
copy_and_paste(m_start,m_end);
2575
/* Copy pasted expansion back to start of this macro. */
2576
for(mp1=mp,mp=m_start,mp0=m_end; mp0<mp1; )
2580
@ Here we copy tokens into the |macrobuf| beginning at |mp|. If we find
2581
|paste|, we execute that operation.
2584
copy_and_paste FCN((m_start,m_end))
2585
eight_bits HUGE *m_start C0("Start of range.")@;
2586
eight_bits HUGE *m_end C1("End of range.")@;
2588
eight_bits HUGE *mp0;
2590
eight_bits HUGE *m_last = m_start; // Remember start of last token.
2592
for(mp0=m_start; mp0 < m_end; )
2596
if(a0 == paste) @<Juxtapose left and right.@>@;
2601
mp0++; // Just skip any nulls that sneak in.
2611
MCHECK(1,"|constant| or |stringg|");
2618
|constant| or |stringg|");
2620
while (*mp++ != a0);
2625
case begin_language:
2626
MCHECK(2,"dot_const");
2631
default: /* Copy ASCII token. */
2632
MCHECK(1,"ASCII token");
2639
{ /* Copy two-byte token. */
2641
MCHECK(2,"two-byte token");
2642
*mp++ = *mp0++; *mp++ = *mp0++;
2649
@ To do token-pasting, we must first juxtapose the expansions of the tokens
2650
to the left and right of the |paste| token. Then we must retokenize the
2659
p = mp; /* Beginning of the juxtaposition. */
2661
paste1(m_last,m_start); /* Paste tokens to left of `\.{\#\#}'. */
2662
mp0 = paste1(++mp0,m_end); /* Paste tokens to right. */
2664
/* Tokenize the juxtaposition. */
2665
divert((ASCII HUGE *)p, (ASCII HUGE *)mp, STOP); /* Make the next |scan_repl|
2666
read from |macrobuf| between~|p| and~|mp|. */
2667
scan_repl(macro, STOP);
2669
/* Copy tokenized stuff back into |macrobuf|, overwriting the juxtaposition. */
2671
m_last = copy_and_paste(cur_text->tok_start, tok_ptr);
2673
/* Back up the text buffer. */
2674
text_ptr = cur_text;
2675
mx_tok_ptr = tok_ptr;
2676
tok_ptr = text_ptr->tok_start;
2679
@ Here we expand the tokens beginning at~|p0| into the |macrobuf|. The
2680
routine returns the next position in the input buffer.
2683
paste1 FCN((p0,begin_or_end))
2684
eight_bits HUGE *p0 C0("Beginning of tokens to be expanded.")@;
2685
eight_bits HUGE *begin_or_end C1("")@;
2690
if(p0 == begin_or_end)
2692
MACRO_ERR("! Missing argument to token-paste operation. Null assumed",
2697
if(TOKEN1(a0=*p0++))
2704
/* Copy the stuff sandwiched between tokens. */
2705
while( (a1=*p0++) != a0)
2707
MCHECK(1,"stuff between tokens");
2713
case begin_language:
2714
MCHECK(2,"dot_const");
2720
MCHECK(1,"default ASCII token");
2721
*mp++ = a0; /* Copy ASCII token. */
2726
a = IDENTIFIER(a0,*p0++);
2733
@<Copy possibly truncated identifier to macro buffer@>@;
2742
@<Copy possibly truncated id...@>=
2745
ASCII HUGE *pc = np->byte_start;
2747
if(*pc != BP_MARKER)
2748
{ /* Not truncated. */
2749
CONST ASCII HUGE *end;
2752
copy_id((CONST ASCII HUGE *)pc,end,"copied id");
2756
s = ((BP HUGE *)pc)->Root;
2757
copy_id(s->id,s->id_end,"copied id");
2761
@ Copy an identifier into the macro buffer.
2764
copy_id FCN((start,end,descr))
2765
CONST ASCII HUGE *start C0("Beginning of identifier name.")@;
2766
CONST ASCII HUGE *end C0("End of identifier name.")@;
2767
CONST char *descr C1("")@;
2769
CONST ASCII HUGE *j;
2771
MCHECK(end - start,descr);
2773
for (j=start; j<end; )
2774
*mp++ = (eight_bits)(*j++);
2777
@ Report macro buffer overflow, and abort.
2781
mbuf_full FCN((n,reason))
2782
unsigned long n C0("Number of bytes requested.")@;
2783
CONST outer_char reason[] C1("Reason for request.")@;
2785
MACRO_ERR("! Macro buffer full; %lu byte(s) requested for %s",YES,n,reason);
2786
OVERFLW("macro buffer bytes",ABBREV(mbuf_size));
2789
/* Interface from independently compiled modules. */
2791
mcheck0 FCN((n,reason))
2792
unsigned long n C0("Number of bytes requested.")@;
2793
CONST outer_char reason[] C1("Reason for request.")@;
2798
@ Do the complete, recursive expansion of a macro.
2801
xmacro FCN((macro_text, pcur_byte, pthe_end, multilevels, mp0))
2802
text_pointer macro_text C0("")@;
2803
eight_bits HUGE **pcur_byte C0("Pointer to |cur_byte|.")@;
2804
eight_bits HUGE **pthe_end C0("End of buffer.")@;
2805
boolean multilevels C0("Read args through many levels?")@;
2806
eight_bits HUGE *mp0 C1("Build the expansion beginning here in \
2809
eight_bits HUGE *macro_start;
2810
extern long cur_val;
2812
/* Copy the token of this macro. */
2813
mp = mp0; /* Current position in |macrobuf|. */
2815
MCHECK(2,"macro token");
2817
if(macro_text->built_in)
2819
*mp++ = LEFT(cur_val,ID0);
2820
*mp++ = RIGHT(cur_val);
2824
macro_start = macro_text->tok_start;
2825
*mp++ = *macro_start++; *mp++ = *macro_start++;
2828
/* If there are arguments, must get more tokens, through end of
2829
parens. Put all these into beginning of |macrobuf|. */
2830
if(macro_text->nargs > 0 || macro_text->var_args)
2831
mp = args_to_macrobuf(mp, pcur_byte, pthe_end, multilevels,
2832
(boolean)(macro_text->var_args));
2834
return xmac_buf(mp0, NULL, pcur_byte, pthe_end, multilevels);
2835
/* Start at expansion level~0;
2836
return pointer to start of final expansion. */
2839
@ The following routine places all the argument tokens into the
2840
|macro_buf|, ready for expansion. We must watch out for nested parentheses.
2842
Warning: the |pop_level| command below resets the value of |cur_byte| and
2843
|cur_end|. When |multilevels==YES|, |pcur_byte| and |pthe_end| must be
2844
pointing to |cur_byte| and |cur_end|!!!
2848
args_to_macrobuf FCN((mp, pcur_byte, pthe_end,
2849
multilevels, var_args))
2850
eight_bits HUGE *mp C0("Next available position in |macro_buf|.")@;
2851
eight_bits HUGE **pcur_byte C0("Pointer to |cur_byte|.")@;
2852
eight_bits HUGE **pthe_end C0("End of buffer.")@;
2853
boolean multilevels C0("Read through many levels?")@;
2854
boolean var_args C1("Does macro have variable args?")@;
2856
eight_bits c; // First token of identifier.
2857
sixteen_bits id_token; // Name of this macro.
2858
int bal = 0; // Keep track of balanced parens.
2860
id_token = IDENTIFIER(*(mp-2),*(mp-1));
2861
// Name of the macro; remember for error processing.
2865
if(*pcur_byte == *pthe_end)
2867
if(!(multilevels && pop_level()))
2869
MACRO_ERR("! No ')' in call to macro \"%s\"",YES,
2875
MCHECK(1,"arg to macrobuf");
2876
c = *mp++ = *(*pcur_byte)++;
2879
@<Copy single character of argument@>@;
2881
{/* Copy second token of identifier, or stuff relating to
2882
module name and line number. */
2883
int n; /* Number of remaining bytes to copy. */
2885
n = (c < MOD0 ? 1 : 3 + 4*1); // `1' for |line_info|.
2886
MCHECK(n,"second id token");
2887
while(n-- > 0) *mp++ = *(*pcur_byte)++;
2894
return mp; /* New end. */
2898
@<Copy single character of arg...@>=
2905
MCHECK(1,"string arg");
2906
*mp = *(*pcur_byte)++;
2908
while(*mp++ != stringg);
2912
case begin_language:
2913
MCHECK(1,"dot const");
2914
*mp++ = *(*pcur_byte)++;
2922
if(bal == 0 && !var_args)
2924
MACRO_ERR("! Missing '(' in call to macro \"%s\"",YES,
2934
@ Expand the macro buffer. Keep expanding until nothing more. The original
2935
thing to be expanded, either just a macro token or the token plus its
2936
argument list, starts off in the beginning of |macrobuf|. Successive
2937
translations are put after that, until on the final pass no macros were
2938
expanded. |mp|~points to the next free position in |macrobuf|.
2940
(Some of the code here may be archaic and/or redundant, because of
2941
changes made in the order of recursive expansion. In some cases, |x0macro|
2942
may be called one more time than necessary. Fixing this up might save some
2943
time in macro-bound codes.)
2946
xmac_buf FCN((mp0, old_xids, pcur_byte, pthe_end, multilevels))
2947
eight_bits HUGE *mp0 C0("Text to be expanded begins here.")@;
2948
XIDS HUGE *old_xids C0("")@;
2949
eight_bits HUGE **pcur_byte C0("Pointer to |cur_byte|.")@;
2950
eight_bits HUGE **pthe_end C0("End of buffer.")@;
2951
boolean multilevels C1("")@;
2953
eight_bits HUGE *p, HUGE *p1;
2959
if(xlevel >= MAX_XLEVELS)
2961
MACRO_ERR("! Macro outer recursion depth exceeded",YES);
2962
FATAL(M, "!! BYE.", "");
2965
pid = pids[xlevel++] = old_xids ? old_xids : &xids; /* Store the address of
2966
this bunch of recursive names. */
2969
x0macro(p, p1, pid, pcur_byte, pthe_end, multilevels);
2972
xlevel--; // Pop the outer recursion stack.
2974
return p1; // Return beginning of the expanded text.
2977
@ Copy unexpanded text to the macro buffer, expand it, and return the
2978
location of the expanded stuff.
2981
xmac_text FCN((mp0,start,end))
2982
eight_bits HUGE *mp0 C0("")@;
2983
eight_bits HUGE *start C0("")@;
2984
eight_bits HUGE *end C1("")@;
2986
/* Copy the text to the macrobuf. */
2987
for(mp=mp0; start < end; )
2990
/* Expand the contents and return pointer. */
2991
return xmac_buf(mp0, NULL, NULL, NULL, NO);
2994
@* BUILT-IN FUNCTIONS.
2995
Generate a comment in the output.
2996
@<Define internal...@>=
2998
SAVE_MACRO("$COMMENT(cmnt)$$META(#*cmnt)");
3002
@d arg_must_be_constant(name)
3003
MACRO_ERR("Argument of \"%s\" must be constant or string",YES,name);
3007
i_meta_ FCN((n,pargs))
3009
PARGS pargs C1("")@;
3013
CHK_ARGS("$COMMENT",1);
3015
IS_IT_CONSTANT($COMMENT);
3017
@<Write begin-comment token to |macrobuf|@>;
3019
*(p+1) = *(pargs[1]-2) = @' '; /* Change quotes to blanks. */
3023
MCHECK0(1,"_meta_");
3026
while(p < pargs[1]);
3028
@<Write end-comment token to |macrobuf|@>;
3031
@ In the initialization of |begin_C_meta|, we use the octal definition of
3032
|constant| (see \.{t\_codes}). This is necessary since otherwise a space is
3033
inserted between~'\./' and~'\.*' to handle expressions such as \.{x / *p}.
3035
@<Write begin-comment...@>=
3037
static eight_bits begin_C_meta[] = {constant,@'/',@'*',constant,'\0'};
3041
if(C_LIKE(language))
3043
MCHECK0(4,"begin_C_meta");
3044
for(p=begin_C_meta; *p; ) *mp++ = *p++;
3048
MCHECK0(2,"begin_meta");
3055
@<Write end-comment...@>=
3057
static eight_bits end_C_meta[] = @"*/";
3061
if(C_LIKE(language))
3063
MCHECK0(2,"end_C_meta");
3064
for(p=end_C_meta; *p; ) *mp++ = *p++;
3068
MCHECK0(1,"end_meta");
3074
@m IS_IT_CONSTANT(name)
3076
if(!(*p == constant || *p == stringg))
3078
arg_must_be_constant(#name);
3082
@ Assert a preprocessor condition.
3085
i_assert_ FCN((n,pargs))
3087
PARGS pargs C1("")@;
3090
eight_bits HUGE *pp;
3091
eight_bits HUGE *mp0;
3094
CHK_ARGS("$ASSERT",1);
3096
pp = xmac_text(mp0=mp, p=pargs[0]+1, pargs[1]); // Expand the expression.
3103
mp = str_to_mb(p, pargs[1], YES);
3105
MACRO_ERR("! $ASSERT(%s) failed",NO,to_outer((ASCII HUGE *)mp));
3106
FATAL(M, "", "Processing ABORTED!");
3109
@ Generate error message.
3110
@<Define internal...@>=
3112
SAVE_MACRO("$ERROR(text)$$ERROR(#*text)");
3117
i_error_ FCN((n,pargs))
3119
PARGS pargs C1("")@;
3122
eight_bits HUGE *t, HUGE *p, HUGE *temp;
3124
CHK_ARGS("$ERROR",1);
3126
IS_IT_CONSTANT($ERROR);
3128
temp = GET_MEM("_error_:temp",N_MSGBUF,eight_bits);
3130
for(c=*p++,t=temp; *p != c; ) *t++ = *p++;
3133
MACRO_ERR("%cUSER ERROR: %s",NO, beep(1),to_outer((ASCII HUGE *)temp));
3134
FREE_MEM(temp,"_error_:temp",N_MSGBUF,eight_bits);
3137
@ The internal macro |$ROUTINE| generates a string containing the name of
3138
the current routine. This macro is associated with the internal function
3141
@<Define internal macros@>=
3143
SAVE_MACRO("$ROUTINE $STRING($$ROUTINE)");
3145
@ The internal function |_routine_| expands |cur_fcn| into the |macro_buf|.
3148
i_routine_ FCN((n,pargs))
3150
PARGS pargs C1("")@;
3153
CONST ASCII HUGE *f, HUGE *end;
3155
CHK_ARGS("$ROUTINE",0);
3157
if(!(is_RATFOR_(language))) return; // So far, only \Ratfor\ is active.
3158
if(!RAT_OK("")) CONFUSION("_routine_","Language shouldn't be Ratfor here");
3160
if(cur_fcn == NO_FCN)
3167
np = name_dir + cur_fcn;
3168
end = proper_end(np);
3170
MCHECK0(end - np->byte_start,"_routine_");
3171
for(f = np->byte_start; f < end; )
3176
@ Case conversion of macro argument.
3177
@<Define internal macros@>=
3179
SAVE_MACRO("$L(name)$$LC(name)"); // Possibly expand the argument.
3181
SAVE_MACRO("$U(name)$$UC(name)");
3186
i_lowercase_ FCN((n,pargs))
3188
PARGS pargs C1("")@;
3190
eight_bits HUGE *p = pargs[0] + 1, HUGE *p1 = pargs[1];
3196
MUST_QUOTE("$L",p,p1);
3200
MCHECK(p1 - p,"lowercase");
3203
*mp++ = A_TO_LOWER(*p); // Watch out for side effects in |A_TO_LOWER|!
3207
i_uppercase_ FCN((n,pargs))
3209
PARGS pargs C1("")@;
3211
eight_bits HUGE *p = pargs[0] + 1, HUGE *p1 = pargs[1];
3217
MUST_QUOTE("$U",p,p1);
3221
MCHECK(p1 - p, "uppercase");
3224
*mp++ = A_TO_UPPER(*p); // Watch out for side effects in |A_TO_LOWER|!
3228
@<Define internal macros@>=
3230
SAVE_MACRO("$NARGS(mname)$$NARGS(#!mname)");
3232
@ Determining the number of fixed arguments.
3235
i_nargs_ FCN((n,pargs))
3237
PARGS pargs C1("")@;
3240
eight_bits *pa = pargs[0] + 1;
3242
if((m=MAC_LOOKUP(IDENTIFIER(pa[0],pa[1]))) == NULL)
3244
MACRO_ERR("! Argument of $NARGS is not a WEB macro",YES);
3247
else put_long((long)m->nargs);
3250
@ Put a long integer into the macro buffer as a constant.
3256
outer_char temp[100];
3259
n = NSPRINTF(temp,"%ld",l);
3268
@ The code for checking the correct number of arguments in a built-in macro
3269
call isn't complete yet, since most of them go through an intermediate
3273
chk_args FCN((name,proper_num,actual_num,pargs))
3274
outer_char *name C0("")@;
3275
int proper_num C0("")@;
3276
int actual_num C0("")@;
3277
PARGS pargs C1("")@;
3281
if(actual_num != proper_num)
3282
MACRO_ERR("Built-in macro %s should be called with %d \
3283
argument(s), not %d",NO,name,proper_num,actual_num);
3287
@ This code is used for debugging; it displays the token list for a macro
3288
in a slightly translated form. This function can be called from the debugger.
3292
@d SAVE_MTEXT(val) if(p < mtext_end) *p++ = (eight_bits)(val);
3293
else OVERFLW("Mtext","")@;
3297
see_macro FCN((p0,p1))
3298
CONST eight_bits HUGE *p0 C0("Beginning of token list.")@;
3299
CONST eight_bits HUGE *p1 C1("End of token list.")@;
3303
sixteen_bits HUGE *tokens;
3306
num_tokens = PTR_DIFF(int, p1, p0); // Why is this |int|?
3308
tokens = GET_MEM("see_macro:tokens",num_tokens,sixteen_bits);
3309
mtext = GET_MEM("see_macro:mtext",MTEXT_SIZE,ASCII);
3311
k = rcvr_macro(mtext,tokens,p0,p1);
3315
printf(_Xx("%x "),tokens[l]);
3317
printf("\"\n== \"");
3318
for(q0=mtext; q0<mtext+k; ++q0)
3322
FREE_MEM(mtext,"see_macro:mtext",MTEXT_SIZE,ASCII);
3323
if(num_tokens) FREE_MEM(tokens,"see_macro:tokens",num_tokens,sixteen_bits);
3326
@ Translate a macro into readable form.
3329
rcvr_macro FCN((mtext,tokens,p0,p1))
3330
ASCII HUGE *mtext C0("Holds readable translation of the text.")@;
3331
sixteen_bits HUGE *tokens C0("Slightly translated tokens.")@;
3332
CONST eight_bits HUGE *p0 C0("")@;
3333
CONST eight_bits HUGE *p1 C1("")@;
3335
ASCII HUGE *mtext_end = mtext + MTEXT_SIZE;
3336
ASCII HUGE *p; // Current position in output text buffer.
3339
sixteen_bits a; // The current token.
3341
for(k=0,p=mtext; p0 < p1; k++)
3343
if(TOKEN1(a = *p0++))
3347
SAVE_MTEXT(@'#'); @+ SAVE_MTEXT(@'#');
3354
else if(a == MACRO_ARGUMENT)
3357
a = (sixteen_bits)(-(*p0));
3358
SAVE_MTEXT(*p0++ + @'0'); // Only for 9 or less???
3362
a = IDENTIFIER(a,*p0++);
3366
CONST ASCII HUGE *end;
3367
name_pointer np = name_dir + a;
3371
for(j=np->byte_start; j<end; ++j)
3380
if(tokens) tokens[k] = a; // Should have special color marker for ids.
3386
@ For manipulating the behavior of various macros, we set a global variable
3387
|xflag| with the aid of the |$XX| macro.
3395
i_xflag_ FCN((n,pargs))
3397
PARGS pargs C1("")@;
3399
eight_bits HUGE *p = pargs[0] + 1;
3400
outer_char temp[100],*t=temp;
3404
if(*p++ != constant)
3406
MACRO_ERR("Argument of $XX is not a numerical constant",NO);
3410
while(*p != constant)
3421
i_dumpdef_ FCN((n,pargs))
3423
PARGS pargs C1("")@;
3426
eight_bits HUGE *p,HUGE *mp0,HUGE *mp1,HUGE *mp2;
3428
extern long cur_val;
3429
eight_bits HUGE *q0,HUGE *q1;
3430
ASCII HUGE *mtext = GET_MEM("rcvr_macro:mtext",MTEXT_SIZE,ASCII);
3431
ASCII HUGE *mx, HUGE *mx0;
3434
CHK_ARGS("$DUMPDEF",INT_MIN);
3437
{ /* Print translation of $k^{{\rm th}}$ macro. */
3445
p = pargs[k] + 1; // Start of argument.
3447
while(IS_WHITE(*p) || *p==@'\n') p++;
3449
a = IDENTIFIER(*p,*(p+1));
3451
if( (m=MAC_LOOKUP(a)) == NULL)
3452
{ /* Not a valid WEB macro. */
3453
str_to_mb(p,pargs[k+1],NO);
3454
printf("NOT WEB MACRO: %s\n",(char *)to_outer((ASCII *)mp0));
3457
@<Dump a valid \WEB\ macro@>@;
3462
FREE_MEM(mtext,"_dumpdef_:mtext",MTEXT_SIZE,ASCII);
3466
@<Dump a valid...@>=
3470
/* Copy the name. */
3473
for(mx=mtext,mx0=np->byte_start; mx0<(np+1)->byte_start; )
3479
/* Translate the definition. */
3483
STRCPY(mp0,"<built-in>");
3484
mp = mp0 + STRLEN(mp0) + 1;
3488
q0 = m->tok_start + m->moffset;
3489
q1 = m->tok_start + m->nbytes;
3491
str_to_mb(q0,q1,NO);
3493
to_outer((ASCII *)mp0);
3496
/* Print the definition. */
3497
printf("%s", (char *)mtext);
3499
if(m->nargs || m->var_args)
3504
for(n=0; n<m->nargs; n++)
3505
printf("$%d%s",(int)n,
3506
CHOICE(n==(eight_bits)(m->nargs-1), "", ","));
3507
if(m->var_args) printf("%s...",
3508
CHOICE(m->nargs,",",""));
3512
printf(" = %s\n", (char *)(mp=mp0));
3516
/* Convert arguments to readable form. */
3518
str_to_mb(p,pargs[k+1],NO);
3520
to_outer((ASCII *)mp0);
3522
/* Expand the macro. */
3523
mp1 = xmacro(m, &p, &pargs[k+1], NO, mp);
3526
str_to_mb(mp1,mp,NO);
3528
to_outer((ASCII *)mp2);
3530
printf("%s%s = %s\n", (char *)mtext, (char *)mp0, (char *)(mp=mp2));
3533
ERR_PRINT(M,"Extra text after macro call");
3538
@ The expansion of \.{\$KEYWORD(keyword)} is the text associated with the
3539
global keyword, which was declared between \.{@@z}\dots\.{@@x} like
3540
`\.{\$keyword:\ text\ \$}'.
3542
@<Define internal...@>=
3544
SAVE_MACRO("$KEYWORD(s)$$KEYWORD(#*s)");
3546
SAVE_MACRO("$AUTHOR $KEYWORD(Author)");
3547
SAVE_MACRO("$DATE_TIME $KEYWORD(Date)");
3548
SAVE_MACRO("$HEADER $KEYWORD(Header)");
3549
SAVE_MACRO("$ID $KEYWORD(Id)");
3550
SAVE_MACRO("$LOCKER $KEYWORD(Locker)");
3551
SAVE_MACRO("$NAME $KEYWORD(Name)");
3552
SAVE_MACRO("$RCSFILE $KEYWORD(RCSfile)");
3553
SAVE_MACRO("$REVISION $KEYWORD(Revision)");
3554
SAVE_MACRO("$SOURCE $KEYWORD(Source)");
3555
SAVE_MACRO("$STATE $KEYWORD(State)");
3557
@ The |i_keyword_| function is called during the output phase, when it is
3558
being sent a string delimited by |stringg|. It builds a
3559
|stringg|-delimited string into the macro buffer that is the contents of
3560
the relevant RCS-like keyword. As a nucleus, it calls |x_keyword|, which
3561
expands without the |stringg| delimiters.
3565
i_keyword_ FCN((n, pargs))
3567
PARGS pargs C1("")@;
3569
eight_bits HUGE *p = pargs[0] + 1, HUGE *p1 = pargs[1];
3571
CHK_ARGS("$KEYWORD", 1);
3575
MUST_QUOTE("$KEYWORD", p, p1);
3579
MCHECK(1, "stringg0");
3582
x_keyword(&mp, macrobuf_end, p, p1-1, YES, YES, WEB_FILE);
3584
MCHECK(1, "stringg1");