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{FWEAVE.WEB} % The FWEAVE processor.
14
@* INTRODUCTION. \WEAVE\ has a fairly straightforward outline. It
15
operates in three phases: first it inputs the source file and stores
16
cross-reference data, then it inputs the source once again and produces the
17
\TeX\ output file, and finally it sorts and outputs the index. It can be
18
compiled with the optional flag |DEBUG| (defined in \.{typedefs.web}).
20
Some compilers may not be able to handle a module this big. In that case,
21
compile this twice, defining from the compiler's command line the macro
22
|part| to have the value of either~1 or~2: e.g., `\.{-Dpart=1}'. See the make
23
file for complete details.
25
For the text of the modules that aren't printed out here, such as
26
\.{typedefs.web}, see \.{common.web}.
28
@m _FWEAVE_ // Identify the module for various \FWEB\ macros.
33
@<Possibly split into parts@>@; // Defines |part|.
36
@<Typedef declarations@>@;
38
@<Global variables@>@;
40
/* For pc's, the file is split into three compilable parts using the
41
compiler-line macro |part|, which must equal either~1, 2, or~3. */
42
#if(part == 0 || part == 1)
46
#if(part == 0 || part == 2)
50
#if(part == 0 || part == 3)
54
@ Here is the main program. See the user's manual for a detailed
55
description of the command line.
59
int main FCN((ac, av))
60
int ac C0("Number of command-line arguments.")@;
61
outer_char **av C1("Array of pointers to command-line arguments.")@;
63
/* --- Various initializations --- */
65
ini_timer(); /* Start timing the run. */
68
argc=ac; @~ argv=av; /* Remember the arguments as global variables. */
73
@<Set initial values@>;
75
/* --- Do the processing --- */
76
phase1(); /* read all the user's text and store the cross-references */
77
phase2(); /* read all the text again and translate it to \TeX\ form */
78
phase3(); /* output the cross-reference index */
80
return wrap_up(); /* We actually |exit| from here. */
85
@ Here we open the \.{.tex} output file. This routine is called from
93
if(STRCMP(tex_fname, "stdout") == 0)
97
@<Open \.{.tex} file for reading, if it exists; check for valid
100
if((tex_file=FOPEN(tex_fname, "w"))==NULL)
104
"Can't open output file %s.",
108
@<Print header information to beginning of output file@>@;
112
@ The following code is intended to catch the embarrassing situation when
113
\FWEAVE's output tries to overwrite an already existing \TeX\ file. For
114
example, one has a paper called \.{test.tex}, then later creates a file
115
\.{test.web} for entirely different purposes. Only if the existing file
116
has a valid header indicating it was created by \FWEAVE\ will we continue.
118
@<Open \.{.tex} file for reading...@>=
120
if(tex_file=FOPEN(tex_fname, "r"))
124
fgets((char *)buf, STRLEN(FWEAVE_HDR)+1, tex_file);
126
if(STRCMP(buf, FWEAVE_HDR))
128
if(!verify(OC("\n%c!!! Attempting to write FWEAVE's output \
129
into %s%s%s, a file apparently not created by FWEAVE. Continue"),
131
SSET_COLOR(out_file),
133
SSET_COLOR(warning)))
136
"Didn't overwrite %s%s%s.",
137
SSET_COLOR(out_file),
150
@ The command line was formatted up with newlines; these must be followed
151
by a \TeX\ comment character.
153
@d FWEAVE_HDR "% FWEAVE"
157
fprintf(tex_file, "%s v%s (%s)\n\n",
158
FWEAVE_HDR, (char *)version, (char *)release_date);
165
@<Allocate dynamic memory@>@;
167
@ The function prototypes must appear before the global variables.
170
#include "w_type.h" /* Function prototypes for \FWEAVE. */
172
@i xrefs.hweb /* Declarations for cross-referencing. */
177
ALLOC(xref_info,xmem,ABBREV(max_refs),max_refs,0);
178
xmem_end = xmem + max_refs - 1;
183
name_dir->xref = (XREF_POINTER)(xref_ptr=xmem);
184
xref_switch = mod_xref_switch = defd_switch = index_short = NO;
185
xmem->num = 0; // Cross-references to undefined modules.
187
@ A new cross-reference for an identifier is formed by calling |new_xref|,
188
which discards duplicate entries and ignores non-underlined references to
189
one-letter identifiers or reserved words.
191
If the user has sent the |no_xref| flag (the \.{-x} option of the command
192
line), it is unnecessary to keep track of cross-references for identifers.
193
If one were careful, one could probably make more changes around module~100
194
(??) to avoid a lot of identifier looking up.
199
new_xref FCN((part0,p))
201
name_pointer p C1("")@;
203
xref_pointer q; // Pointer to previous cross-reference.
204
sixteen_bits m, n; // New and previous cross-reference value.
208
SET_TYPE(p,DEFINED_TYPE(p) | 0x80);
209
index_flag = BOOLEAN(!(language==LITERAL));
212
/* Do nothing if we're not supposed to cross-reference. Also do nothing if
213
we're inside a \&{format} statement. This is a bit kludgy, but it works. */
214
if (!index_flag || !(output_on || index_hidden) || in_format
215
|| (unnamed_section && !xref_unnamed) )
216
return; /* The |output_on| flag here prevents index entries for
217
modules skipped with~\.{-i}. */
219
index_flag = BOOLEAN(!(language==LITERAL));
221
/* Say where the identifier is defined (but not if it's a reserved word). */
222
if(defd_switch && (part0 == DEFINITION
224
|| is_reserved(p) || is_intrinsic(p) || is_keyword(p))))
226
sixteen_bits mod_defined = p->defined_in(language);
228
if(mod_defined && mod_defined != module_count && language!=C_PLUS_PLUS)
230
err_print(W,"Identifier in %s was already explicitly \
232
marked via @@[ as defined in %s",
233
MOD_TRANS(module_count), MOD_TRANS(mod_defined));
237
p->defined_in(language) = module_count;
241
if(defd_type != NEVER_DEFINED)
242
SET_TYPE(p,defd_type); // Used to be up in previous block.
244
defd_type = NEVER_DEFINED;
248
|| ((!(index_short || index_one)) && (length(p)==1))) )
251
/* The following code needs to be attached to a flag. */
262
return; // The result of the \.{-x} flag.
264
m = module_count + xref_switch;
266
q = (xref_pointer)p->xref;
268
if(!(do_inside || all_includes || (quoted_includes && qtd_file)))
269
goto check_implicit; // Skip if reading an include file.
272
{ /* There's already an entry. */
275
if (n==m || n==m+def_flag)
277
// Discard duplicates within the same module.
278
else if (m==n+def_flag)
280
q->num = m; /* Update the entry to be defined instead of
286
/* There's no entry yet; make a new cross-reference. */
289
/* Link in; highest module number is first. */
290
xref_ptr->xlink=q; p->xref = (XREF_POINTER)xref_ptr;
294
@<Execute an implicit \.{@@f}@>@;
297
@ When the |typd_switch| is on, due to an~\.{@@`}, we execute an implicit
298
format statement that formats~|p| as a reserved word.
299
@<Execute an implicit...@>=
302
name_pointer lhs = p, rhs = &rs_wd;
305
rhs->reserved_word = rhs->Language = BOOLEAN(language);
306
rhs->intrinsic_word = rhs->keyword = NO;
308
@<Format the left-hand side@>@;
311
/* Mark as defined in this module. */
312
if(mark_defined.imp_reserved_name)
314
p->defined_in(language) = module_count;
315
SET_TYPE(p,IMPLICIT_RESERVED);
319
/* Make all previous entries register as defined, not just used. */
320
for(q=(xref_pointer)p->xref; q>xmem; q = q->xlink)
321
if(q->num < def_flag) q->num += def_flag;
326
@ The cross-reference lists for module names are slightly different.
327
Suppose that a module name is defined in modules~$m_1$, \dots, $m_k$ and
328
used in modules~$n_1$, \dots, $n_l$. Then its list will contain
329
$m_1+|def_flag|$, $m_k+|def_flag|$, \dots, $m_2+|def_flag|$, $n_l$, \dots,
330
$n_1$, in this order. After Phase II, however, the order will be
331
$m_1+|def_flag|$, \dots, $m_k+|def_flag|$, $n_1$, \dots, $n_l$.
336
new_mod_xref FCN((p))
337
name_pointer p C1("")@;
339
xref_pointer q,r; /* pointers to previous cross-references */
342
if(!output_on) return; /* Don't bother with references if the module is
343
skipped with \.{-i}. */
346
q = (xref_pointer)p->xref; r=xmem;
350
if (mod_xref_switch==NO)
351
{ /* ``Used in module...'' Scan past all the definitions. */
352
while (q->num>=def_flag)
360
if (q->num>=def_flag)
368
if(mod_xref_switch == NO)
369
{ /* Not defining. */
370
p->mod_info->params.uses++; // Count number of uses.
372
if(q->num == module_count)
373
return; // Discard duplicate ``used in'' xref.
376
append_xref(module_count+mod_xref_switch);
377
xref_ptr->xlink=q; mod_xref_switch=NO;
380
p->xref = (XREF_POINTER)xref_ptr;
385
@i tokens.hweb /* Declarations for |token| storage. */
390
ALLOC(Token,tok_mem,ABBREV(max_toks_w),max_toks,1);
391
tok_mem++; /* In some unusual circumstances, there may be references to
392
|tok_mem[-1]|, so be sure it exists. */
393
tok_m_end = tok_mem+max_toks-1; // End of |tok_mem|./
395
ALLOC(token_pointer,tok_start,ABBREV(max_texts),max_texts,0);
396
tok_end = tok_start+max_texts-1; // End of |tok_start|.
401
@<Initialize |tok_ptr|, |tok_start|, and |text_ptr|@>@;
402
mx_tok_ptr=tok_ptr; mx_text_ptr=text_ptr;
405
@<Initialize |tok_ptr|...@>=
407
tok_ptr = tok_mem + 1;
408
tok_start[0] = tok_start[1] = tok_ptr;
409
text_ptr = tok_start + 1;
412
@ The |names_match| function is called from |id_lookup| in \.{common.web}
413
when deciding whether to put a name into the table.
418
names_match FCN((p,first,l,t))
419
name_pointer p C0("Points to the proposed match.")@;
420
CONST ASCII HUGE *first C0("Position of first character of string.")@;
421
int l C0("Length of identifier.")@;
422
eight_bits t C1("Desired ilk.")@;
424
if (length(p)!=l) return NO; /* Speedy return. */
426
if ( (p->Language&(boolean)language) && (p->ilk!=t) && !(t==normal &&
430
return (boolean)(!STRNCMP(first,p->byte_start,l));
433
@ The following two functions are used in initializations; they are called
440
name_pointer p C0("")@;
441
eight_bits t C1("")@;
445
p->ilk=t; p->xref = (XREF_POINTER)xmem;
447
/* Check if identifier is all upper-case. */
448
p->info.upper_case = NO;
450
for(k = p->byte_start; k<byte_ptr; k++)
451
if(isAlpha(*k) && !isAupper(*k))
454
p->info.upper_case = YES;
457
SRTN ini_node FCN((node))
458
CONST name_pointer node C1("")@;
460
node->xref = (XREF_POINTER)xmem;
462
@<Initialize |mod_info| and |Language|@>@;
465
@i ccodes.hweb /* Category codes for the reserved words. */
467
@* LEXICAL SCANNING. Let us now consider the subroutines that read the
468
\.{WEB} source file and break it into meaningful units. There are four such
469
procedures: |skip_limbo| simply skips to the next `\.{@@\ }' or `\.{@@*}'
470
that begins a module; |skip_TeX| passes over the \TeX\ text at the
471
beginning of a module; |copy_comment| passes over the \TeX\ text in a \cee\
472
comment; and |get_next|, which is the most interesting, gets the next token
473
of a \cee\ text. They all use the pointers |limit| and |loc| into the line
474
of input currently being studied.
476
Control codes in \.{WEB}, which begin with~`\.{@@}', are converted into a
477
numeric code designed to simplify \WEAVE's logic; for example, larger
478
numbers are given to the control codes that denote more significant
479
milestones, and the code of |new_module| should be the largest of all. Some
480
of these numeric control codes take the place of ASCII control codes that
481
will not otherwise appear in the output of the scanning routines.
484
The following table shows the assignments:
485
$$\def\:{\char\count255\global\advance\count255 by 1}
486
\def\Hrule{\noalign{\hrule}}\def\HHrule{\noalign{\hrule height2pt}}
490
\hbox{\hbox to \Width{\it\hfill0\/\hfill}%
491
\hbox to \Width{\it\hfill1\/\hfill}%
492
\hbox to \Width{\it\hfill2\/\hfill}%
493
\hbox to \Width{\it\hfill3\/\hfill}%
494
\hbox to \Width{\it\hfill4\/\hfill}%
495
\hbox to \Width{\it\hfill5\/\hfill}%
496
\hbox to \Width{\it\hfill6\/\hfill}%
497
\hbox to \Width{\it\hfill7\/\hfill}}
500
\def\!{\vrule height 10.5pt depth 4.5pt}
501
\halign{\hbox to 0pt{\hskip -24pt\WO{\~#}\hfill}&\!
502
\hbox to \Width{\hfill$#$\hfill\!}&
503
&\hbox to \Width{\hfill$#$\hfill\!}\cr
504
00&\\{ignore}&\WMM &\\{verbatim}&\\{force\_line}&\WW &** &\WCC &\\{bell}\cr\Hrule
505
01&\dots &\\{begin\_cmnt}&\\{lf} &\WPP &\\{ff} &\\{cr}
506
&\\{begin\_lang} &\\{cmpd\_assgn} \cr\Hrule
507
02&\WGG &\WLS &\WLL &\.{.DOT.}&; &\WSR &\WSlSl & \cr\Hrule
508
03&\\{stmt\_label}&\WMG &\WI &\WL &\WNN &\WG &\WS &\WV \cr\HHrule
509
04& &\WR & &\# & &\WMOD &\amp & \cr\Hrule
510
05& & &\ast &+ & &- & &/ \cr\Hrule
511
06& & & & & & & & \cr\Hrule
512
07& & & & &< &= &> &? \cr\Hrule
513
10&\Wcp &\Wcm &\Wcs &\Wcv &\Wcd &\Wcx &\Wca &\Wco \cr\Hrule
514
11&\Wcg &\Wcl & & & & & & \cr\Hrule
515
12& & & & & & & & \cr\Hrule
516
13& & & & & & &\^ & \cr\Hrule
517
14& & & & & & & & \cr\Hrule
518
15& & & & & & & & \cr\Hrule
519
16& & & & & & & & \cr\Hrule
520
17& & & & &\WOR &\.{@@\$}&\.{@@\_},\WTL&\\{param}\cr\HHrule
521
20&\.{L$l$}&\.{C} &\.{R} &\.{N} &\.{M} &\.{X} & & \cr\Hrule
522
21&\WNP &\WNC &\.{\#<}&\WPtr &\WCC & & &
524
22& & & & & & & & \cr\Hrule
525
23&\\{constant}&\\{stringg}&\\{identifier}&\.{@@\^}&\.{@@9} &\.{@@.} &\.{@@t} &\.{@@'} \cr\Hrule
526
24&\.{@@\&}&\.{@@,} &\.{@@\char'174}&\.{@@/} &\.{@@\#} &\.{@@~} &\.{@@;}& \cr\Hrule
527
25&\.{@@(} &\.{@@)} &\.{\ } &\\{copy\_mode}&\\{toggle\_output}&\.{@@e}&\.{@@:}&
529
26& & &\.{@@!} & & &\.{@@0} &\.{@@1} &\.{@@2} \cr\Hrule
530
27&\.{@@f} &\.{@@\%}& & &\.{@@l} &\.{@@o} &\.{@@d} &\.{@@m} \cr\Hrule
531
30&\.{@@\#ifdef}&\.{@@\#ifndef}&\.{@@\#if}&\.{@@\#else}&\.{@@\#elif}&\.{@@\#endif}
532
&\.{@@\#pragma} &\.{@@\#undef}\cr\Hrule
533
31&\.{@@a} &\.{@@<} &\.{@@\ }& & & & & \cr\Hrule
534
32& & & & & & & & \cr\Hrule
535
33& & & & & & & & \cr\Hrule
542
37& & & & & & &\\{begin\_cmnt0}& \cr}
543
\hrule width 480pt}$$
546
@d ignore 0 // Control code of no interest to \WEAVE.
547
@d verbatim OCTAL(2) // Extended |ASCII| alpha will not appear.
548
@d force_line OCTAL(3) // Extended |ASCII| beta will not appear.
550
@d begin_comment0 HEX(FE) // Sent from |input_ln|.
551
@d begin_comment1 HEX(FD)
552
@d begin_comment OCTAL(11) // |ASCII| tab mark will not appear.
554
@d compound_assignment OCTAL(17) // Things like `\.{*=}'.
555
@% @d param OCTAL(177) // |ASCII| delete will not appear.
557
/* Language codes. */
558
@d L_switch OCTAL(200) // The generic language switch \.{@@L$l$}.
559
@d begin_C OCTAL(201)
560
@d begin_RATFOR OCTAL(202)
561
@d begin_FORTRAN OCTAL(203)
562
@d begin_LITERAL OCTAL(204)
563
@d begin_TEX OCTAL(205)
565
@d begin_nuweb OCTAL(206) // Strictly speaking, not a language code.
567
/* More two-byte combinations that couldn't be fitted below printable
569
@d dont_expand OCTAL(210) // Control code for `\.{\#!}'.
570
@d auto_label OCTAL(211) // Control code for `\.{\#:}'.
571
@d all_variable_args OCTAL(212) // Control code for `\.{\#.}'.
572
@d macro_module_name OCTAL(213) // Control code for `\.{\#<\dots@@>}'.
573
@d eq_gt OCTAL(214) // Control code for `\.{=>}'.
574
@d colon_colon OCTAL(215) /* Control code for `\.{::}'. */
576
/* Control codes for \FWEB\ commands beginning with \.{@@}. */
578
/* The following two codes will be intercepted without confusion, because
579
they're processed immediately after an \.{@@}, not returned from
581
@d switch_math_flag OCTAL(175)
582
@d underline OCTAL(176)
584
@d next_expr OCTAL(226) // Control code for `\.{@@E}' */
585
@d next_reserved OCTAL(227) // Control code for `\.{@@R}' */
587
@d xref_roman OCTAL(233) /* control code for `\.{@@\^}' */
588
@d xref_wildcard OCTAL(234) /* control code for `\.{@@9}' */
589
@d xref_typewriter OCTAL(235) /* control code for `\.{@@.}' */
590
@d TeX_string OCTAL(236) /* control code for `\.{@@t}' */
591
@d ascii_constant OCTAL(237) /* control code for `\.{@@'}' */
592
@d join OCTAL(240) /* control code for `\.{@@\&}' */
593
@d thin_space OCTAL(241) /* control code for `\.{@@,}' */
594
@d math_break OCTAL(242) /* control code for `\.{@@\char'174}' */
595
@d line_break OCTAL(243) /* control code for `\.{@@/}' */
596
@d ln_break_outdent OCTAL(244) // Control code for `\.{@@\\}'.
598
@d big_line_break OCTAL(245) /* control code for `\.{@@\#}' */
599
@d no_line_break OCTAL(246) /* control code for `\.{@@~}' */
600
@d pseudo_semi OCTAL(247) /* control code for `\.{@@;}' */
601
@d defd_at OCTAL(250) // Control code for `\.['.
603
@d begin_meta OCTAL(251) /* Control code for |"@@("|. */
604
@d end_meta OCTAL(252) /* Control code for |"@@)"|. */
606
@d macro_space OCTAL(253) /* Space token during preprocessing. */
607
@d copy_mode OCTAL(254) /* Are we copying comments? */
609
@d toggle_output OCTAL(255) // Turns on and off Weave's output.
610
@d turn_output_on OCTAL(255) // Appended to the scraps for code.
611
@d turn_output_off OCTAL(256)
612
@d Turn_output_on OCTAL(257)
613
@d Turn_output_off OCTAL(260)
615
@d left_preproc OCTAL(261) // Begins a preprocessor command.
616
@d right_preproc OCTAL(262) // Ends a preprocessor command.
618
@d Cont_Char OCTAL(263) // Represents continuation char.\ during preprocessing.
620
@d Compiler_Directive OCTAL(264) /* Control code for `\.{@@?}' */
621
@d new_output_file OCTAL(265) // Control code for `\.{@@o}'.
623
@d implicit_reserved OCTAL(266) // Control code for `\.{@@]}'.
625
@d trace OCTAL(267) /* control code for `\.{@@0}', `\.{@@1}', and `\.{@@2}' */
627
/* 270 and 271 are related to |trace| above and are introduced implicitly. */
629
@d invisible_cmnt OCTAL(272) /* Control code for `\.{@@\%}' */
631
@d pseudo_expr OCTAL(273) /* Control code for `\.{@@e}' */
632
@d pseudo_colon OCTAL(274) /* Control code for `\.{@@:}' */
634
@d begin_bp OCTAL(275) // Control code for `\.{@@B}'.
635
@d insert_bp OCTAL(276) // Control code for `\.{@@b}'.
637
@d no_index OCTAL(277) // Control code for `\.{@@-}'.
638
@d yes_index OCTAL(300) // Control code for `\.{@@~}'.
640
@d no_mac_expand OCTAL(301) // Control code for `\.{@@!}'.
641
@d protect_code OCTAL(302) // Control code for `\.{@@p}'.
642
@d set_line_info OCTAL(303) // Control code for `\.{@@q}'.
644
@d short_fcn OCTAL(304) // Control code for `\.{@@\lb}'.
645
@d keyword_name OCTAL(305) // Control code for `\.{@@k}'.
647
/* Definition section begun by codes $\ge$~|formatt|. */
648
@d formatt OCTAL(310) /* control code for `\.{@@f}' */
650
@d limbo_text OCTAL(313) /* Control code for `\.{@@l}' */
651
@d op_def OCTAL(314) /* Control code for `\.{@@v}' */
652
@d macro_def OCTAL(315) // Control code for `\.{@@w}'.
654
@d definition OCTAL(320) /* control code for `\.{@@d}' */
655
@d undefinition OCTAL(321) // Control code for `\.{@@u}'.
656
@d WEB_definition OCTAL(322) /* Control code for `\.{@@M}' */
658
/* --- Preprocessor commands --- */
659
@d m_ifdef OCTAL(330)
660
@d m_ifndef OCTAL(331)
664
@d m_endif OCTAL(335)
666
@d m_endfor OCTAL(337)
668
@d m_undef OCTAL(341)
670
/* --- Module names --- */
671
@d begin_code OCTAL(350) /* control code for `\.{@@a}' */
672
@d module_name OCTAL(351) /* control code for `\.{@@<}' */
674
/* --- Beginning of new module --- */
675
@d new_module OCTAL(352) /* control code for `\.{@@\ }' and `\.{@@*}' */
677
/* For more tokens beginning with |OCTAL(360)|, see \.{output.web}. */
679
@ Control codes are converted from ASCII to \WEAVE's internal
680
representation by means of the table |ccode|. Codes that are used only by
681
\FTANGLE\ get the special code~|ignore| (see \.{typedefs.hweb}; these are
682
just skipped. Codes that are used by neither processor are initialized
683
to~|'0xFF'|; that can be used to trigger an error message.
687
IN_STYLE eight_bits ccode[128];
688
/* Meaning of an |ASCII| char following '\.{@@}'. */
690
@ The control codes are set up in \.{style.web}.
692
@m TANGLE_ONLY(d,c) INI_CCODE(d,USED_BY_OTHER)
693
@m WEAVE_ONLY(d,c) INI_CCODE(d,c)
697
zero_ccodes(); // See \.{style.web}.
698
ccode[@'/'] = line_break; /* The commenting style is also fundamental, and
699
for technical convenience the \.{@@/} command is also inviolate. */
701
@<Set the changable codes@>@;
704
@ Here are the default values for the things that are allowed to be
706
@<Set the changable...@>=
708
SAME_CCODE(" \t*", new_module); // Either space, tab, or asterisk.
710
SAME_CCODE("aA", begin_code);
711
SAME_CCODE("<", module_name);
713
SAME_CCODE("dD", definition);
714
SAME_CCODE("uU", undefinition);
715
SAME_CCODE("mM", WEB_definition);
716
SAME_CCODE("fF", formatt);
718
WEAVE_ONLY("\001", toggle_output); // This command is for internal use only!
720
SAME_CCODE("'\"", ascii_constant);
721
REASSIGNABLE("=", verbatim);
722
WEAVE_ONLY("\\", ln_break_outdent);
724
REASSIGNABLE("tT", TeX_string);
726
SAME_CCODE("L", L_switch);
727
SAME_CCODE("c", begin_C);
728
SAME_CCODE("r", begin_RATFOR);
729
SAME_CCODE("n", begin_FORTRAN);
730
SAME_CCODE("N", begin_nuweb);
731
SAME_CCODE("x", begin_TEX);
733
SAME_CCODE("&", join);
734
WEAVE_ONLY("_", underline);
735
WEAVE_ONLY("[", defd_at);
736
WEAVE_ONLY("`]", implicit_reserved);
738
SAME_CCODE("%", invisible_cmnt);
739
SAME_CCODE("?", Compiler_Directive);
740
SAME_CCODE("{", short_fcn);
741
SAME_CCODE("kK", keyword_name);
743
WEAVE_ONLY("$", switch_math_flag);
745
WEAVE_ONLY("E", next_expr);
746
WEAVE_ONLY("R", next_reserved);
748
REASSIGNABLE("^", xref_roman);
749
REASSIGNABLE(".", xref_typewriter);
750
REASSIGNABLE("9", xref_wildcard);
755
sprintf(temp, ";%c", XCHR(interior_semi));
756
WEAVE_ONLY(temp, pseudo_semi);
759
WEAVE_ONLY("e", pseudo_expr);
760
WEAVE_ONLY(":", pseudo_colon);
762
SAME_CCODE("l", limbo_text);
763
SAME_CCODE("vV", op_def);
764
SAME_CCODE("wW", macro_def);
766
WEAVE_ONLY(",", thin_space);
767
WEAVE_ONLY("|", math_break);
768
SAME_CCODE("#", big_line_break);
769
WEAVE_ONLY("~", no_line_break);
771
SAME_CCODE("(", begin_meta);
772
SAME_CCODE(")", end_meta);
774
SAME_CCODE("oO", new_output_file);
776
SAME_CCODE("B", begin_bp);
777
TANGLE_ONLY("}b", insert_bp);
778
SAME_CCODE("!", no_mac_expand);
779
TANGLE_ONLY("q", set_line_info);
781
WEAVE_ONLY("-", no_index);
782
WEAVE_ONLY("+", yes_index);
784
WEAVE_ONLY("p", protect_code);
786
@<Special control codes allowed only when debugging@>@;
789
@ If \WEAVE\ is compiled with debugging commands, one can write~\.{@@2},
790
\.{@@1}, and~\.{@@0} to turn tracing fully on, partly on, and off,
792
@<Special control codes...@>=
795
WEAVE_ONLY("012",trace);
798
@ At this point |loc|~is positioned after a language command like~\.{@@c},
799
or on the~$l$ in~\.{@@L$l$}.
801
@f @<Cases to set |language| and |break|@> case
803
@<Cases to set |language| and |break|@>=
805
@<Specific language cases@>:
806
loc--; /* Position to letter after \.{@@}. Falls
807
through to general case |L_switch|. */
810
@<Set the |language| and maybe kill rest of line@>@;
814
nuweb_mode = !NUWEB_MODE;
816
if(module_count == 0)
817
global_params = params;
821
@<Set the |language| and maybe kill...@>=
825
if(module_count == 0)
826
global_params = params;
829
@<Kill rest of line; no |auto_semi|@>@;
832
@ The |skip_limbo| routine is used on the first pass to skip through
833
portions of the input that are not in any modules, i.e., that precede the
834
first module. Language commands may be encountered at any time; these reset
835
the current language from whatever was specified on the command line. When
836
the first module is found, the global language is set to the current
839
After this procedure has been called, the value of |input_has_ended| will
840
tell whether or not a module has actually been found.
849
if (loc > limit && !get_line())
852
*(limit+1) = @'@@'; // Guard character.
854
/* Look for '@@', then skip two chars. */
855
while (*loc != @'@@')
858
/* |loc| now on the \.{@@}. */
860
switch(ccode[*loc++])
861
{ /* Process any language change
862
commands; skip any other @@~commands. */
863
@<Cases to set |language| and |break|@>@:@;
870
return; // End of limbo section.
874
if (loc <=limit) if (ccode[*loc++]==new_module) return;
879
@ The |skip_TeX| routine is used on the first pass to skip through the
880
\TeX\ code at the beginning of a module. It returns the next control code
881
or~`\v' found in the input. A |new_module| is assumed to exist at the very
891
if (loc>limit && !get_line())
894
*(limit+1)=@'@@'; // Marker to curtail the scan.
896
while (*loc!=@'@@' && *loc!=@'|')
900
return @'|'; // Have hit beginning of code mode.
905
return ccode[*(loc++)];
912
@* INPUTTING the NEXT TOKEN.
913
As stated above, \.{WEAVE}'s most interesting lexical scanning routine is the
914
|get_next| function that inputs the next token of \cee\ input. However,
915
|get_next| is not especially complicated.
917
The result of |get_next| is either an ASCII code for some special
918
character, or it is a special code representing a pair of characters (e.g.,
919
`\.{!=}'), or it is the numeric value computed by the |ccode| table, or it
920
is one of the following special codes:
922
\yskip\hang |identifier|: In this case the global variables |id_first| and
923
|id_loc| will have been set to the beginning and ending-plus-one locations
924
in the buffer, as required by the |id_lookup| routine.
926
\yskip\hang |string|: The string will have been copied into the array
927
|mod_text|; |id_first| and |id_loc| are set as above (now they are
928
pointers into |mod_text|).
930
\yskip\hang |constant|: The constant is copied into |mod_text|, with slight
931
modifications; |id_first| and |id_loc| are set.
933
\yskip\noindent Furthermore, some of the control codes cause |get_next| to
934
take additional actions:
936
\yskip\hang |xref_roman|, |xref_wildcard|, |xref_typewriter|, |TeX_string|,
937
|verbatim|: The values of |id_first| and |id_loc| will have been set to the
938
beginning and ending-plus-one locations in the buffer.
941
\yskip\hang |module_name|: In this case the global variable |cur_module| will
942
point to the |byte_start| entry for the module name that has just been scanned.
944
\yskip\noindent If |get_next| sees `\.{@@\_}' it sets |xref_switch| to
945
|def_flag| and goes on to the next token.
947
\yskip\noindent If |get_next| sees `\.{@@\$}' it sets |math_flag| to
948
|!math_flag| and goes on to the next token.
950
@d constant OCTAL(230) /* \cee\ string or \.{WEB} precomputed string */
951
@d stringg OCTAL(231) /* \cee\ string or \.{WEB} precomputed string */
952
@d identifier OCTAL(232) /* \cee\ identifier or reserved word */
956
EXTERN name_pointer cur_module; // Name of module just scanned.
957
EXTERN int math_flag SET(NO);
958
EXTERN boolean chk_end SET(YES); // Do we check for end of line?
959
EXTERN boolean last_was_cmnt SET(NO); /* Helps with interchanging
960
semicolons and comments. */
961
EXTERN boolean lst_ampersand SET(NO); /* For continuations in
962
free-form syntax \Fortran-90. */
963
EXTERN boolean eat_blank_lines SET(NO); // For Nuweb mode.
964
EXTERN boolean just_inserted SET(NO); // For inserting extra token by |get_next|.
965
EXTERN boolean empty_line SET(NO); // Status of last line read.
967
EXTERN ASCII c; // The current character for |get_next|.
969
@ As one might expect, |get_next| consists mostly of a big switch that
970
branches to the various special cases that can arise. This function has
971
been broken into multiple function calls to |prs_TeX_code| and
972
|prs_regular_code| in order to make it fit on personal computers.
977
get_next(VOID) /* produces the next input token */
979
boolean terminate = NO;
981
GOTO_CODE pcode; // Return from the parsing functions. 0~means |continue|.
985
@<Check if we're at the id part of a preprocessor command@>;
986
@<Check if we're at the end of a preprocessor command@>;
990
@<Get another line of input if necessary@>@;
991
@<Get next character; skip blanks and tabs@>@;
993
/* Handle an (effectively) empty line. (Don't move this statement upwards.) */
994
if(limit == cur_buffer || (at_beginning && loc > limit))
997
return big_line_break;
1003
if((pcode=prs_TeX_code()) == MORE_PARSE)
1005
else if((int)pcode < 0)
1006
CONFUSION("prs_TEX_code", "Negative pcode %i", pcode);
1008
goto found_something;
1011
if((pcode=prs_regular_code(MORE_PARSE)) == MORE_PARSE)
1013
else if((int)pcode < 0)
1014
CONFUSION("prs_regular_code",
1015
"Negative pcode %i", pcode);
1017
goto found_something;
1022
/* We need the following stuff to handle the |INNER| parsing mode properly.
1023
(|at_beginning| doesn't correspond to physical beginning of line, so can't
1024
be reset by |get_line()|.) */
1026
switch((eight_bits)pcode)
1028
case begin_language:
1036
return (eight_bits)pcode;
1039
@ Get another line of input if necessary. We raise the special flag
1040
|at_beginning| to help us with statement labels and preprocessor commands.
1041
Normally this flag is set when we get a new line. However, it must also be
1042
set after we enter code mode by encountering vertical bars.
1044
@<Get another line...@>=
1050
terminator[0] = *limit; terminator[1] = *(limit+1);
1053
@<Insert a semicolon at end of free-format \Fortran-90 line @>@;
1058
return new_module; // End of file.
1061
{ /* Avoid empty stuff at end of module in Nuweb mode. */
1062
@<Skip blank lines@>@;
1063
eat_blank_lines = NO;
1066
if(parsing_mode == OUTER)
1067
at_beginning = YES; // Start of new line.
1071
*limit = terminator[0]; *(limit+1) = terminator[1];
1075
else if(parsing_mode == OUTER)
1079
@ Doing auto-semi insertion for free-format \Fortran-90 turns out to be
1080
surprisingly easy. Fundamentally, the end-of-line wants a semicolon. If
1081
the line ends while scanning a long comment, the comment is absorbed by
1082
other code, not the |get_line| immediately following this segment. Both
1083
long and short comments become an |ignore| scrap, so can be followed by the
1084
pseudo-semi at the end of the line terminating the comment.
1086
@<Insert a semi...@>=
1092
if(free_Fortran && auto_semi && !empty_line && the_part==CODE)
1094
just_inserted = YES;
1095
return auto_pseudo_semis ? ccode[@';'] : @';';
1096
/* Insert pseudo-semi or semicolon at eol. */
1101
@ In Nuweb mode, blank lines at the end of the module are significant,
1102
unless `\.{@@\%\%}' is used. That turns on |eat_blank_lines|.
1104
@<Skip blank lines@>=
1109
eat_blank_lines = NO;
1114
@ Here we obtain the next character, advancing~|loc| in the process.
1115
Depending on the situation, we also skip blanks and tabs.
1117
@<Get next char...@>=
1120
@<Compress string of blanks into one; if any found, return
1123
@<Skip white space at beginning of line@>@;
1125
if(c==cont_char && loc==limit)
1127
if(preprocessing || free_Fortran)
1137
@<Compress string of blanks...@>=
1141
if((c=*loc++) != @' ' || c != tab_mark)
1146
if(c==@' ' || c==tab_mark)
1151
@<Skip white space at beg...@>=
1157
ASCII HUGE *loc0 = loc; // Remember starting point for nuweb mode.
1160
{ /* Skip beginning white space. */
1163
while(loc<=limit && (c==@' ' || c==tab_mark) );
1167
if(!(c == @'@@' && *loc == @'#'))
1168
{ /* Go back to beginning. */
1171
if(phase == 1 && c == tab_mark)
1179
@ \TeX\ syntax differs significantly from that of the other languages.
1180
First of all, \TeX\ comments (beginning with~'\.\%') are always short. Next,
1181
in phase~1, we must look at the text identifier by identifier in order to make
1182
cross-references properly. In phase~2, however, we can absorb whole
1183
collections of identifiers, until a comment or control code comes along.
1185
In order to deal with changing category codes, we translate letters through
1186
the array~|TeX|, which contains the most up-to-date category codes.
1192
GOTO_CODE icode; // Return code from |get_control_code|.
1198
{ // The next call takes care of a branch to |mistake|.
1199
if((icode=get_control_code()) == GOTO_MISTAKE)
1200
return prs_regular_code(GOTO_MISTAKE);
1204
else if(TeX[c] == TeX_comment)
1206
long_comment = YES; // Since we may concatenate lines.
1207
return begin_comment;
1209
else if(c == @'|' && parsing_mode == INNER)
1214
if(TeX[c] == TeX_escape)
1215
@<Get \TeX\ identifier@>@;
1220
@<Get \TeX\ string@>@;
1222
@% return MORE_PARSE; // This means to continue to top of |get_next|.
1225
@ If the identifier doesn't begin with a letter, it's a single-character
1226
macro such as~`\.{\\<}'.
1228
@<Get \TeX\ identifier@>=
1230
id_first = id_loc = mod_text + 1;
1232
*id_loc++ = *(loc-1); // The beginning backslash.
1234
if(TeX[*loc] != TeX_letter)
1235
{ /* Single-character macro, such as~`\.{\\<}'. */
1238
if(*(loc+1) != @'@@') ERR_PRINT(W,"You should say `\\@@@@'");
1241
*id_loc++ = *loc++; // The single character.
1243
else while(TeX[*loc] == TeX_letter)
1244
{ /* Scan over the macro name. */
1247
if(*(loc+1) != @'@@') ERR_PRINT(W,"You should say `@@@@'");
1256
@ \TeX\ strings are everything on a single line, up to a comment or, if
1257
we're inside vertical bars, up to a terminating bar. It looks nicer if we
1258
leave spaces alone instead of displaying them as~`\.{\ }'.
1260
@d ordinary_space 01 /* Inserted after ctrl sequences, to avoid many
1263
@<Get \TeX\ string@>=
1266
id_first = id_loc = mod_text + 1;
1271
if(*(loc+1)==@'@@') *id_loc++ = *loc++;
1272
else break; // Scan ended by control code.
1274
if(TeX[*loc] == TeX_comment) break;
1275
if(*loc==@'|' && parsing_mode==INNER) break; // End of internal mode.
1277
if(TeX[*loc] == TeX_escape)
1279
if(TeX[*(loc+1)] != TeX_letter)
1280
{ // One-character control sequence.
1281
if(*(loc+1) == @'@@')
1282
if(*(loc+2) != @'@@')
1283
ERR_PRINT(W,"You should say \\@@@@");
1284
else *id_loc++ = *loc++;
1289
{ // Ordinary control sequence.
1292
while (TeX[*loc] == TeX_letter);
1296
if(TeX[*loc] != TeX_space) break;
1298
*id_loc++ = ordinary_space;
1312
@ Parse everything but \TeX.
1316
prs_regular_code FCN((iswitch))
1317
GOTO_CODE iswitch C1("")@;
1319
GOTO_CODE icode; // Return code from |get_control_code|.
1323
case GOTO_MISTAKE: goto mistake;
1324
case GOTO_GET_IDENTIFIER: goto get_identifier;
1328
/* --- ELLIPSIS: `\.{...}' --- */
1329
if(c==@'.' && *loc==@'.' && *(loc+1)==@'.')
1335
/* --- DOT CONSTANT: `\.{.FALSE.}' --- */
1336
else if(FORTRAN_LIKE(language) && dot_constants &&
1337
(c == wt_style.dot_delimiter.begin) && !isDigit(*loc))
1338
@<Get a dot constant@>@;
1340
/* --- CONSTANT: `\.{123}', `\.{.1}', or `\.{\\135}' --- */
1341
else if (isDigit(c) || c==@'\\' || c==@'.' || (upcoming_kind && c==@'_'))
1342
@<Get a constant@>@;
1344
/* --- BOZ-CONSTANT --- */
1345
else if (in_data && Fortran88 && (*loc==@'"' || *loc==@'\'') &&
1346
(c==@'B' || c==@'O' || c==@'Z') )
1347
return get_string(*loc++,c);
1349
/* --- IDENTIFIER --- */
1350
else if (is_identifier(c))
1351
@<Get an identifier@>@;
1353
/* --- STRING: `\.{"abc"}', `\.{'\\n'}', `\.{<file\_name>}' --- */
1354
else if (c==@'\'' || c==@'"'
1355
|| (sharp_include_line && !in_comment &&
1356
(c==@'(' || (C_LIKE(language) && c==@'<') ) ))
1357
return get_string(c,'\0');
1359
/* --- CONTROL CODE --- */
1362
if((icode=get_control_code()) == GOTO_MISTAKE)
1368
/* --- WHITE SPACE --- */
1369
/* Blanks were skipped above. */
1370
else if (c==@' ' || c==tab_mark)
1372
if(preprocessing) /* What is this statement for? */
1374
id_first = mod_text + 1;
1375
id_loc = id_first + 1;
1379
else /* JAK to here */
1382
return c; @%(c==tab_mark ? bell : c);
1384
return MORE_PARSE; // Ignore spaces and tabs; continue.
1386
/* --- C PREPROCESSOR STATEMENT: `\.{\#include}' --- */
1387
if (c==@'#' && at_beginning && C_LIKE(language))
1388
@<Raise preprocessor flag@>@;
1389
/* If |'#'| is first character in line, it's a C~preprocessor statement. */
1391
/* --- END A |@r format| STATEMENT: `\.{format(\dots);}' --- */
1392
else if (in_format && c==@';')
1393
{ /* End a |@r format| statement. */
1395
return end_format_stmt;
1398
/* --- TWO-SYMBOL OPERATOR --- */
1399
mistake: @<Compress two-symbol operator@>@;
1400
return (eight_bits)c;
1403
@ For FORTRAN, we allow ``dot constants'', like ~\.{.true.}\ or~\.{.or.}.
1404
This routine scans between the dots, then looks up the identifier in a
1405
table to see if it's valid and to get its token translation. This procedure
1406
has a tendency to run away if an unexpected dot finds its way into the
1407
input (either because of a syntactical mistake, or because \Weave\ is
1408
missing the relevant rule). Thus, we limit the search to no more than
1409
|MAX_DOT_LENGTH == 31| characters, the maximum possible length of a dot
1412
@<Get a dot constant@>=
1417
ASCII dot_end = wt_style.dot_delimiter.end;
1420
/* At this point, |loc| is positioned to the first position after the dot. */
1421
for(p0=loc, n=0; n<MAX_DOT_LENGTH; n++,loc++)
1422
if(*loc == dot_end || !isAlpha(*loc))
1423
break; // Found end of dot constant, or something not allowed.
1426
{/* Didn't find end. */
1427
loc = p0; // Reset position back to beginning.
1431
if((dcode=dot_code(dots,uppercase(p0,n),loc,dot_const)) != 0)
1434
upcoming_kind = BOOLEAN(loc[1] == @'_');
1436
compress(dcode); // Search for match in table.
1439
/* Invalid dot constant. */
1444
@ Because preprocessor commands do not fit in with the rest of the syntax
1445
of C, we have to deal with them separately. One solution [Levy] is to enclose
1446
such commands between special markers. Thus, when a~'\.\#' is seen as the
1447
first character of a line, |get_next| returns a special code
1448
\\{left\_preproc} and raises a flag |preprocessing|.
1450
(Unfortunately, Levy's solution didn't work in certain situations, and when
1451
the preprocessor language was installed a different method was adopted.
1452
Thus, parts of the code are asymmetrical. This should eventually be
1453
improved, but it was considered more important to make it work at all.)
1458
IN_COMMON ASCII HUGE *pinclude, HUGE *ppragma;
1459
/* Strings for tokens |include| and |pragma|. */
1462
preprocessing = YES;
1463
@<Check if next token is |include| or |pragma|@>;
1464
return left_preproc;
1467
@ An additional complication is the freakish use of~'\.<' and~'\.>' to delimit
1468
a file name in lines that start with \&{\#include}. We must treat this file
1469
name as a string, and use the flag |sharp_include_line| to help.
1471
Also, |#pragma|s can have arbitrary syntax, so we don't want to typeset it
1472
as usual. For those, we set |sharp_pragma_line|. (Not yet used for anything.)
1474
@<Check if next token is |include|...@>=
1476
/* According to ANSI, white space may be skipped at beginning of line. */
1477
while (*loc==@' ' || *loc==@'\t')
1480
if(STRNCMP(loc, pinclude, 7)==0)
1481
sharp_include_line = YES;
1482
else if(STRNCMP(loc, ppragma, 7) == 0)
1483
sharp_pragma_line = YES;
1486
@ Since the preprocessor has different reserved words than C~itself, we
1487
include the preprocessor token with the identifier if it's first on a
1490
@<Check if we're at the id...@>=
1492
if(preprocessing && at_beginning)
1496
/* Preprocessor directives can have white space between the '\.\#' and the
1498
for( ; loc < limit; loc++)
1499
if(!(*loc==@' ' || *loc==tab_mark))
1502
*(loc-1) = @'#'; /* Now we're positioned on an identifier beginning
1503
with~|'#'|, with no intervening blanks. */
1505
return (eight_bits)prs_regular_code(GOTO_GET_IDENTIFIER);
1509
@ When we get to the end of a preprocessor line, we lower the flag and send
1510
a code \\{right\_preproc}, unless the last character was the continuation
1513
@<Check if we're at the end...@>=
1518
/* Continue to next line; also (for \Fortran) skip all lines that have
1519
continuation character in column~1. */
1520
while (*loc==cont_char && loc==limit-1 && (preprocessing || free_Fortran))
1522
return new_module; // Still in preprocessor mode.
1523
else if(preprocessing)
1524
return Cont_Char; /* For C, ensure that the escape character is
1525
printed and a new line is begun. */
1527
/* Now we've gotten to the end of line, but it's not continued. */
1531
chk_end=preprocessing=sharp_include_line=sharp_pragma_line=NO;
1532
return right_preproc;
1535
&& parsing_mode == OUTER
1536
&& (auto_semi && !free_Fortran) && (limit > cur_buffer)
1537
&& !(limit[0] == @'@@' && limit[1] == @'m'))
1542
{ // Comment has already been appended.
1545
{ // Deal with continuation before comment.
1550
ERR_PRINT(W,"Section ended in middle of Fortran-90 continuation");
1553
APP_STR("\\indent");
1558
@% else return @'\n'; // or @';' ??? or nothing???
1562
@ The following code assigns values to the combinations~\.{++}, \.{--},
1563
\.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, and~\.{\&\&}. (For
1564
FORTRAN, we also have~\.{//} and~\.{\^}.) The compound assignment
1565
operators in~C are indexed, all under the aegis of |compound_assignment|.
1567
@d compress(c) if (loc++<=limit) return (eight_bits)c@;
1569
@d COMPOUND(c,n) if(loc <= limit) {loc += n; assignment_token=c;
1570
return (eight_bits)compound_assignment;}
1572
@d CA_START OCTAL(100) /* The index into |op| is |CA_START + assignment_token|,
1573
where |assignment_token| is one of the following. See |valid_op()| for
1589
EXTERN eight_bits assignment_token; /* The particular one of the above
1590
compound assignment tokens. */
1593
@<Compress two...@>=
1597
case (ASCII)begin_comment0:// Comment sent from FORTRAN or Ratfor |input_ln|.
1599
return begin_comment;
1601
case (ASCII)begin_comment1: // As above, but short comment.
1603
return begin_comment;
1606
if(*loc==@'/' && !in_format && FORTRAN_LIKE(language))
1608
compress(slash_slash); // `\.{\\/}' $\to$ `|@r \/|'.
1613
@<Cases for \.{\slashstar}, \.{//}, \.{/)}, and~\.{/=}@>@;
1617
if(*loc == @'/' && !in_format) compress(left_array);
1621
if (*loc==@'+') {compress(plus_plus); // `\.{++}' $\to$ `|++|'.
1623
else if(*loc==@'=') {COMPOUND(plus_eq,1);
1624
// `\.{+=}' $\to$ `|+=|'.
1629
if (*loc==@'-') {compress(minus_minus); // `\.{--}' $\to$ `|--|'.
1631
else if (*loc==@'>') {compress(minus_gt);
1632
// `\.{->}' $\to$ `|->|'.
1634
else if(*loc==@'=') {COMPOUND(minus_eq,1);
1635
// `\.{-=}' $\to$ `|-=|'.
1640
if (*loc==@'=') {compress(eq_eq); // `\.{==}' $\to$ `|==|'.
1642
else if(*loc==@'>') {compress(eq_gt);
1643
// `\.{=>}' $\to$ `$\WPtr$'.
1644
} /* \FORTRAN-88's pointer assignment statement. */
1648
if (*loc==@'=') {compress(gt_eq); // `\.{>=}' $\to$ `|>=|'.
1650
else if (*loc==@'>')
1651
if(*(loc+1)==@'=') {COMPOUND(gt_gt_eq,2);
1652
// `\.{>>=}' $\to$ `|>>=|'.
1654
else {compress(gt_gt); // `\.{>>}' $\to$ `|>>|'.
1659
if (*loc==@'=') {compress(lt_eq); // `\.{<=}' $\to$ `|<=|'.
1661
else if (*loc==@'<')
1663
{COMPOUND(lt_lt_eq,2);
1664
// `\.{<<=}' $\to$ `|<<=|'.
1666
else {compress(lt_lt); // `\.{<<}' $\to$ `|<<|'.
1668
else if(*loc==@'>') {compress(not_eq);
1669
// `\.{<>}' $\to$ `|!=|'.
1674
if(*loc==@'=') {COMPOUND(mod_eq,1); // `\.{\%=}' $\to$ `|%=|'.
1679
if (*loc==@'&') {compress(and_and); // `\.{\&\&}' $\to$ `|&&|'.
1683
COMPOUND(and_eq,1); // `\.{\&=}' $\to$ `|&=|'.
1692
COMPOUND(or_or_or,2); // `\.{\vb\vb\vb}' $\to$ `|||||'.
1694
else compress(or_or); // `\.{\vb\vb}' $\to$ `||| |'.
1696
else if(*loc==@'=' && !FORTRAN_LIKE(language))
1698
COMPOUND(or_eq,1); // `\.{\vertbar=}' $\to$ `||=|'.
1703
if(!in_format && (point_comments || *loc == @'!') )
1705
if(*loc != @'!') loc--;
1707
compress(begin_comment); // \.{! Comment} or \.{!! Comment}.
1709
else if (*loc==@'=') {compress(not_eq); // `\.{!=}' $\to$ `|!=|'.
1714
if(FORTRAN_LIKE(language) && (*loc == @'*') )
1715
{compress(star_star); // `\.{x**y}' $\to$ `|@r x**y|'.
1716
} /* Exponentiation. */
1717
else if(*loc==@'=') {COMPOUND(star_eq,1); // `\.{*=}' $\to$ `|*=|'.
1722
if(*loc == @'^') {compress(star_star);}
1723
else if(FORTRAN_LIKE(language) && (loc < limit) )
1724
return star_star; // `\.{x\^y}' $\to$ `|@r x^y|'.
1725
else if(*loc==@'=') {COMPOUND(xor_eq,1); // `\.{\^=}' $\to$ `|^=|'.
1730
if(*loc==@':') compress(colon_colon); // `\.{::}' $\to$ `|::|'.
1734
@<Cases for \.{\#\#}, \.{\#!}, \.{\#:}, \.{\#.}, and~\.{\#<}@>@;
1740
@<Cases for \.{\slashstar}...@>=
1745
compress(begin_comment); // \.{\slashstar\dots/starslash}
1747
else if(*loc == @'/')
1749
if(C_LIKE(language) || language==TEX || (Cpp_comments &&
1750
!in_format && FORTRAN_LIKE(language)))
1751
{ /* Short comments are recognized in both~C and
1752
\Cpp, and also in |TEX|. */
1753
long_comment = NO; /* \Cpp-style comment. */
1754
compress(begin_comment); // \.{//\dots}
1758
compress(slash_slash); /* Concatenation
1759
operator~|@r \/|. Multiple slashes in |format| statements are just left
1763
else if(*loc == @')' && !in_format)
1764
{compress(right_array); // `\.{/)}' $\to$ `$\WSR$'.
1766
else if(*loc == @'=')
1767
{COMPOUND(slash_eq,1); // `\.{(/}' $\to$ `$\WLS$'.
1771
@<Cases for \.{\#\#}...@>=
1776
compress(paste); // `\.{\#\#}' $\to$ token `\.{\#\#}'.
1780
compress(dont_expand); // `\.{\#!}' $\to$ token `\.{\#!}'.
1784
compress(auto_label); // `\.{\#:}' $\to$ token `\.{\#:}'.
1788
compress(all_variable_args); // `\.{\#.}' $\to$ token `\.{\#.}'.
1794
@<Scan the module name and make |cur_module| point to it@>;
1795
return macro_module_name;
1799
if(phase == 1) loc++; // Skip over so string scanner doesn't complain.
1803
@ Different conventions are followed by \TeX\ and \cee\ to express octal
1804
and hexadecimal numbers; it is reasonable to stick to each convention
1805
withing its realm. Thus the \cee\ part of a \.{WEB} file has octals
1806
introduced by~\.0 and hexadecimals by~\.{0x}---e.g., \.{0377} or
1807
\.{0xFF}---but \.{WEAVE} will print in italics or typewriter font,
1808
respectively, and introduced by single or double quotes---e.g., |0377| or
1809
|0xFF|. \FWEB\ also adds binary constants, written as \.{0b10101} and
1810
printed as |0b10101|. In order to simplify the \TeX\ macro used to print
1811
such constants, we replace some of the characters. (If you don't like the
1812
way these constants look, you can easily change the macro; see
1815
Notice that in this section and the next, |id_first| and |id_loc| are
1816
pointers into the array |mod_text|, not into |cur_buffer|.
1818
The next definitions correspond to the macros in \.{fwebmac.tex}.
1820
@d BINARY_CODE @'&' /* `\.{0b10101}' $\to$ `|0b10101|' */
1821
@d OCTAL_CODE @'~' /* `\.{0377}' $\to$ `|0377|' */
1822
@d HEX_CODE @'`' /* `\.{0xabc}' $\to$ `|0xabc|' */
1824
@d CONSTANT_CODE @'#' // Various kinds of constants.
1825
@d FLOAT_CODE @'0' // `\.{50000F}' $\to$ `|50000F|'.
1826
@d LONG_CODE @'1' /* `\.{50000L}' $\to$ `|50000L|' */
1827
@d UNSIGNED_CODE @'2' // `\.{50000U}' $\to$ `|50000U|'.
1828
@d ULONG_CODE @'3' // `\.{50000UL}' $\to$ `|50000UL|'.
1830
@d EXP_CODE @'^' /* `\.{(x+y)\^(a+b)}' $\to$ `|@r (x+y)^(a+b)|' */
1831
@d HOLLERITH_CODE @'%' /* `\.{5Hhello}' $\to$ `|@r 5Hhello|' */
1835
boolean decimal_point = NO;
1839
id_first = id_loc = mod_text + 1;
1844
/* Might be replaced later by a left brace, if there' a
1848
loc--; // Position on underscore.
1856
{ /* Probably octal---e.g., `\.{\\107}' */
1860
goto mistake; // It's really `\.{\\/}'.
1862
*id_loc++ = OCTAL_CODE; // \.{WEBMAC} control code for octal.
1865
while (isOdigit(*loc))
1869
return (eight_bits)c; // Not octal!
1872
@<Get an octal, hex, or binary constant@>@;
1874
@<Get a decimal or Hollerith constant@>@;
1876
@<Post-process constant@>@;
1878
if(!decimal_point && at_beginning &&
1879
((is_FORTRAN_(language) && !last_was_continued) ||
1880
(is_RATFOR_(language) && *loc == @':')))
1887
@<Get an octal, hex...@>=
1889
if (*loc==@'x' || *loc==@'X')
1890
{ /* Hex---e.g., `\.{0xABC}' */
1891
*id_loc++ = HEX_CODE; /* \.{WEBMAC} code for hex. */
1893
while (isXdigit(*loc))
1896
else if(*loc==@'b' || *loc==@'B') /* Binary */
1898
*id_loc++ = BINARY_CODE; /* \.{WEBMAC} code for binary. */
1900
while(isBdigit(*loc))
1903
else if (isOdigit(*loc)) /* Octal---e.g., `\.{011}' */
1905
*id_loc++ = OCTAL_CODE;
1906
while (isOdigit(*loc))
1910
goto dec; // Decimal constant.
1913
@ Decimal (\.{1.0e-5}) or \FORTRAN\ Hollerith constant (|@R 3Habc|).
1915
@<Get a decimal...@>=
1917
if (c==@'.' && !isDigit(*loc))
1918
goto mistake; // Isn't a constant like~`|.1|'.
1922
while (isDigit(*loc) || *loc==@'.')
1924
/* Optimistically, we'll include the decimal point with the constant.
1925
However, in \Fortran\ we have to check for the possibility that it's an
1926
integer followed by a dot constant. We do this immediately below. */
1928
decimal_point = BOOLEAN(*(loc-1) == @'.');
1930
if(FORTRAN_LIKE(language))
1931
if(decimal_point) /* Check for dot constant. */
1933
if(is_dot()) /* It's an integer constant
1934
followed by a dot constant. */
1941
else if(*loc == @'h' || *loc == @'H')
1942
@<Copy Hollerith constant@>;
1949
if (prec_char==@'e' || prec_char==@'E' || (FORTRAN_LIKE(language) &&
1950
(prec_char==@'d' || prec_char==@'D' ||
1951
prec_char==@'q' || prec_char==@'Q')))
1952
@<Get the exponent field@>@;
1955
@ Process the exponent part of a floating-point constant such as
1956
\.{1.5e-10} |@e = 1.5e-10|.
1958
@<Get the expon...@>=
1960
*id_loc++ = EXP_CODE; // Control character for WEB power of ten.
1961
*id_loc++ = A_TO_UPPER(prec_char);
1963
loc++; // Skip past the exponent character.
1965
if (*loc==@'+' || *loc==@'-')
1968
while (isDigit(*loc))
1972
@ Hollerith constants have the form \.{3Habc}.
1978
*id_loc = '\0'; /* Temporarily make a true terminated string. */
1979
n = ATOI(id_first); /* Convert the string to an integer constant. */
1980
*id_loc++ = HOLLERITH_CODE; /* Control character for WEB Hollerith macro. */
1981
++loc; /* Skip the |'H'|. */
1983
for(k=0; k<n; ++k) /* Copy the actual string. */
1989
@ We don't yet handle correctly things like~\.{50UL}; it comes out like~|50UL|.
1991
@<Post-process...@>=
1993
if (C_LIKE(language))
1999
*id_loc++ = CONSTANT_CODE;
2001
if(*loc == @'u' || *loc == @'U')
2003
*id_loc++ = ULONG_CODE;
2007
*id_loc++ = LONG_CODE;
2012
*id_loc++ = CONSTANT_CODE;
2014
if(*loc == @'l' || *loc == @'L')
2016
*id_loc++ = ULONG_CODE;
2019
else *id_loc++ = UNSIGNED_CODE;
2024
*id_loc++ = CONSTANT_CODE;
2025
*id_loc++ = FLOAT_CODE;
2031
@<Absorb optional kind-param@>@;
2033
@ In \Fortran-90, there can be optional kind parameters after a constant,
2034
started off by an underscore. Example: |@r9 50_4| or |@n9 1.2e45_high|.
2036
@<Absorb optional kind-param@>=
2041
// Make basic number a group, so is subscripted correctly.
2045
while(is_kind(*loc))
2049
id_first++; // Kill off the tentative blank at beginning.
2052
@ Code strings and character constants, delimited by double and single
2053
quotes, respectively, can contain newlines or instances of their own
2054
delimiters if they are protected by a backslash (for~C) or if the delimiter
2055
is repeated (for \FORTRAN). We follow this convention, but do not allow
2056
the string to be longer than |longest_name|. Special codes are inserted
2057
every |NBREAK| characters so that \TeX\ can break the strings. (The count
2058
is restarted after commas, which are also treated as discretionary breaks.)
2060
@d discretionary_break OCTAL(177)
2061
@d NBREAK 25 // \bf Put into style file?
2065
EXTERN boolean insert_breaks SET(YES); /* No breaks inserted during limbo
2068
@ Here we absorb a string. Examples: \.{"abc"}, \.{'\\n'}, or
2074
get_string FCN((c,boz))
2075
ASCII c C0("What started the string")@;
2076
ASCII boz C1("The boz character, or 0.")@;
2078
ASCII delim = c; /* what started the string */
2079
ASCII right_delim = c;
2081
boolean equal_delims;
2083
id_first = mod_text + 1;
2087
if (delim==@'\'' && *(loc-2)==@'@@') {*++id_loc=@'@@'; *++id_loc=@'@@';}
2090
@<Determine the right matching delimiter@>@;
2092
kount = 0; /* How far since last discretionary line break command. */
2095
{ /* Scan for end of string. */
2096
if (loc>=limit) @<Check for continued string@>@;
2098
if ((c=*loc++)==delim) @<Handle left-hand delimiter@>@;
2103
if (++id_loc<=mod_end) *id_loc=c;
2104
break; /* Found end of string for unequal delims. */
2107
/* Handle a final backslash. */
2108
if ((c==cont_char) &&
2109
(C_LIKE(language) || (is_FORTRAN_(language) && free_form_input)))
2110
if (loc>=limit) continue;
2111
else if (++id_loc<=mod_end)
2113
*id_loc = c; c=*loc++;
2116
/* Store the character. */
2117
if (++id_loc<=mod_end) *id_loc=c;
2119
@<Insert discretionary line-break commands@>@;
2120
} /* End of \&{while}. */
2122
if (id_loc>=mod_end)
2125
printf("\n! String too long: ");
2127
ASCII_write(mod_text+1,25);
2134
@<Check for boz constant@>@;
2140
@<Determine the right...@>=
2145
right_delim=@'>'; // for file names in |#include| lines.
2149
right_delim = @')'; // For m4 \&{include} or related functions.
2150
sharp_include_line = NO;
2154
right_delim = @']'; // For auto insertions in macro definitions.
2158
level = 1; // For searching for balanced delimiters.
2160
equal_delims = BOOLEAN(right_delim==delim);
2164
@<Check for continued string@>=
2166
if( (equal_delims || chk_ifelse) && *(limit-1)!=cont_char)
2168
err_print(W,"String %s with %s'%s%c'%s didn't end",
2170
SSET_COLOR(character),
2171
delim==@'\'' ? "\\" : "",
2175
@.String didn't end@>
2180
err_print(W,"Input ended in middle of string beginning with \
2181
'\\%c'",XCHR(delim));
2184
@.Input ended in middle of string@>
2188
/* Now the continuation of the string is in the buffer. If appropriate,
2189
skip over beginning white space and backslash. */
2190
if(bslash_continued_strings)
2192
for(; loc < limit; loc++)
2193
if(*loc != @' ' && *loc != tab_mark) break;
2195
if(*loc == cont_char) loc++; /* Move past the backslash. */
2196
else err_print(W,"Inserted '\\%c' at beginning of continued \
2197
string",XCHR(cont_char));
2203
@<Handle left-hand delim...@>=
2207
if (++id_loc<=mod_end) *id_loc=c;
2209
if(!equal_delims) continue;
2211
if(FORTRAN_LIKE(language) && (*loc == delim) )
2212
++loc; /* Copy over repeated delimiter. */
2213
else break; /* Found end of string. */
2216
@ Insert discretionary line-break command every |NBREAK|
2217
characters. Since the string macro also inserts discretionary breaks after
2218
commas, we reset the counter to~0 after a comma. As one annoyance, we don't
2219
want to insert a break immediately after an~`\.{@@}', because the output
2220
routines would otherwise get confused.
2221
@<Insert discretionary line-break...@>=
2224
if(c == @',') kount = 0;
2225
else if(++kount >= NBREAK && c != @'@@' && ++id_loc<=mod_end)
2228
*id_loc = discretionary_break;
2231
@ In \Fortran-90, we have \It{boz-constants}---binary, octal, or
2232
hexadecimal constants that look like~`\.{B'011'}', `\.{O'077'}',
2233
or~`\.{Z'FF'}'. (The single quotes may be replaced by double quotes.)
2234
These constants may appear only in |@r data| statements.
2236
@<Check for boz...@>=
2238
if(FORTRAN_LIKE(language))
2240
@<Handle boz constant@>@;
2242
@<Handle VAX extensions of hex or octal constants@>@;
2245
@ At this point we already know we're dealing with a boz constant.
2251
*id_first = BINARY_CODE;
2255
*id_first = OCTAL_CODE;
2259
*id_first = HEX_CODE;
2267
@ Handle the VAX extensions of hex or octal
2268
constants---e.g., \.{'abc'X} or \.{'123'O}.
2269
@<Handle VAX exten...@>=
2271
if(*loc==@'X' || *loc==@'x')
2273
*id_first = HEX_CODE; /* Overwrite opening delimiter. */
2274
@<Finish VAX hex/octal constant.@>@;
2276
else if(*loc==@'O' || *loc==@'o')
2278
*id_first = OCTAL_CODE; /* Octal */
2279
@<Finish VAX hex...@>@;
2284
@<Finish VAX hex...@>=
2286
loc++; /* Skip the ending signifier. */
2287
id_loc--; /* Forget closing delimiter. */
2293
EXTERN boolean doing_cdir SET(NO);
2295
@ After an \.{@@}~sign has been scanned, the next character tells us
2296
whether there is more work to do. Note that lower- and upper-case control
2297
codes are generally treated as variants of the same fundamental code; to
2298
distinguish them, we set the |upper_case_code| flag. When the code is in
2299
upper case, it does not automatically issue an implicit~\.{@@[}, for example.
2304
get_control_code(VOID)
2306
eight_bits cc; // The |ccode| value.
2310
SET_CASE(c); // Set the |upper_case_code| flag.
2312
/* Deflect a verbatim comment beginning with `\.{@@\slashstar}'. */
2313
if( (c==@'/' && (*loc==@'*' || *loc==@'/')) ||
2314
c==(ASCII)begin_comment0 || c==(ASCII)begin_comment1)
2315
return GOTO_MISTAKE;
2317
if(c == @'>' && mod_level == 0)
2319
ERR_PRINT(W, "Unmatched `@@>' ignored");
2323
switch(cc = ccode[c])
2334
if(mark_defined.generic_name)
2336
defd_switch = YES; // `\.{@@[}'.
2337
defd_type = GENERIC_NAME;
2338
} // \bf NOTE: Falls through.
2341
xref_switch = def_flag; // `\.{@@\_}'
2344
case implicit_reserved:
2345
if(mark_defined.imp_reserved_name)
2347
typd_switch = defd_switch = YES; // `\.{@@`}'.
2348
defd_type = IMPLICIT_RESERVED;
2349
xref_switch = def_flag;
2353
case switch_math_flag: math_flag=!math_flag; // `\.{@@\$}'
2357
case trace: tracing=c-@'0'; // `\.{@@0}', `\.{@@1}', `\.{@@2}'
2359
#endif /* |DEBUG| */
2361
/* For language switches, we set the |language|, then
2362
send back a single code |begin_language|. When we process this, we'll then
2363
append another 8-bit code with the language number itself. */
2365
@<Specific language cases@>:
2366
loc--; // Falls through to general case below.
2370
@<Set the |language|...@>@;
2371
return begin_language; // `\.{@@L$l$}'
2375
ERR_PRINT(W,"@@N ignored; must appear before beginning of code part");
2378
case xref_roman: case xref_wildcard: case xref_typewriter:
2379
case TeX_string: case keyword_name:
2380
@<Scan to the next \.{@@>}; |return cc|@>@;
2381
/* `\.{@@\^\dots@@>}', `\.{@@9\dots@@>}', `\.{@@.\dots@@>}', and
2382
`\.{@@t\dots@@>}'. */
2385
mac_mod_name = NO; // Used as a flag for macro processing.
2386
@<Scan the module name and make |cur_module| point to it@>@;
2387
return module_name; // `\.{@@<\dots@@>}'
2389
case new_output_file:
2390
@<Scan the output file name@>@;
2393
case invisible_cmnt:
2395
eat_blank_lines = YES;
2396
loc = limit + 1; // Skip the line.
2397
return MORE_PARSE; // `\.{@@\%}
2399
case Compiler_Directive:
2402
return begin_comment; // `\.{@@!}' or `\.{@@?}'
2404
case verbatim: @<Scan a verbatim string@>@; // `\.{@@=\dots@@>}'
2406
case ascii_constant: return get_string(c,'\0'); // `\.{@@'\dots'}'
2408
case big_line_break: // `\.{@@\#}'
2412
@<Process possible pre...@>; // In \.{typedefs.web}.
2416
return @'{'; // Ought to improve this, to mark the debugging locations.
2418
case USED_BY_NEITHER:
2420
err_print(W,"Invalid `@@%c' ignored",XCHR(c));
2426
loc++; // Skip the~0 or~1 after the \.{@@q}.
2434
@ The occurrence of a module name sets |xref_switch| to zero, because the
2435
module name might (for example) follow \&{int}.
2437
@<Scan the module name...@>=
2439
ASCII HUGE *k; // Pointer into |mod_text|.
2440
static ASCII ell[] = @"...";
2441
static ASCII bad_mod_name[] = @"!!! {\\it Incompatible} !!!";
2444
@<Put module name into |mod_text|@>@;
2446
if (k-mod_text > 3 && STRNCMP(k-2,ell,3)==0)
2447
cur_module = prefix_lookup(mod_text+1,k-3);
2448
else cur_module = mod_lookup(mod_text+1,k);
2451
cur_module = mod_lookup(bad_mod_name,bad_mod_name+STRLEN(bad_mod_name)-1);
2456
language = (LANGUAGE)cur_module->Language;
2458
params = cur_module->mod_info->params;// Restore state for this module.
2464
/* The actual return value can be either |module_name| or
2465
|macro_module_name| and is put in explicitly right after the use of this
2466
module in the code. */
2469
@ Module names are placed into the |mod_text| array with consecutive
2470
spaces, tabs, and carriage-returns replaced by single spaces. There will be
2471
no spaces at the beginning or the end. (We set |mod_text[0]=' '| to
2472
facilitate this, since the |mod_lookup| routine uses |mod_text[1]| as the
2473
first character of the name.)
2479
@ Here we copy the text of the module name, stripping off white space from
2480
the front and back. Also, we convert any real semicolons into interior
2481
semis. This helps out with language switches between \Fortran\ and~C, for
2482
example. If the global language were~C, then a module name that should be
2483
read in \Fortran\ will be first be absorbed in~C because the parser doesn't
2484
know yet which language it will be.
2486
@<Put module name...@>=
2494
if (loc>limit && !get_line())
2496
ERR_PRINT(W,"Input ended in section name");
2497
@.Input ended in section name@>
2498
loc=cur_buffer+1; break;
2502
@<If end of name, |break|@>;
2511
c=@' '; if (*(k-1)==@' ') k--; // Compress white space.
2525
printf("\n! Section name too long: ");
2526
@.Section name too long@>
2527
ASCII_write(mod_text+1,25);
2532
if (*k==@' ' && k>mod_text)
2533
k--; // Trailing blanks.
2537
@<If end of name,...@>=
2545
if(--mod_level == 0)
2550
else if(c==@'<') mod_level++;
2552
if (ccode[c]==new_module)
2554
ERR_PRINT(W,"Section name didn't end"); break;
2555
@.Section name didn't end@>
2558
*(++k) = @'@@'; loc++; // Now |c==*loc| again.
2562
@ This fragment is used for skipping over control text, such as
2565
@<Scan to the next...@>=
2567
cc = ccode[*(loc-1)]; /* Is this statement redundant? */
2568
id_first=loc; *(limit+1)=@'@@';
2570
while(*loc != @'@@')
2577
ERR_PRINT(W,"Control text didn't end");
2580
@.Control text didn't end@>
2584
ERR_PRINT(W,"Control codes are forbidden in control text");
2585
@.Control codes are forbidden...@>
2590
@ At the present point in the program we have |*(loc-1)=verbatim|; we set
2591
|id_first| to the beginning of the string itself, and |id_loc| to its
2592
ending-plus-one location in the buffer. We also set~|loc| to the position
2593
just after the ending delimiter.
2595
@<Scan a verbatim string@>=
2599
*(limit+1)=@'@@'; *(limit+2)=@'>';
2601
while (*loc!=@'@@' || *(loc+1)!=@'>') loc++;
2603
if (loc>=limit) ERR_PRINT(W,"Verbatim string didn't end");
2604
@.Verbatim string didn't end@>
2611
@* PHASE ONE PROCESSING.
2612
We now have accumulated enough subroutines to make it possible to carry out
2613
\.{WEAVE}'s first pass over the source file. If everything works right,
2614
both phase one and phase two of \.{WEAVE} will assign the same numbers to
2615
modules, and these numbers will agree with what \.{TANGLE} does.
2617
The global variable |next_control| often contains the most recent output of
2618
|get_next|; in interesting cases, this will be the control code that ended
2619
a module or part of a module.
2623
EXTERN eight_bits next_control; /* control code waiting to be acting upon */
2625
@ The overall processing strategy in phase one has the following
2626
straightforward outline.
2633
LANGUAGE language0=language;
2639
reading(web_file_name,(boolean)(tex_file==stdout));
2641
skip_limbo(); // Skip stuff before any module (but process language commands).
2644
/* Remember the language to put into force at the beginning of each module.
2645
|language| may have been set from the command line, by default (nothing on
2646
the command line), or by explicit~\.{@@c}, \.{@@r}, \.{@@n},
2647
or~\.{@@L$l$} commands during the limbo phase. */
2648
chk_override(language0);
2649
fin_language(); /* Make sure all flags are initialized properly. */
2650
global_params = params;
2652
while (!input_has_ended)
2653
@<Store cross-reference data for the current module@>;
2655
chngd_module[module_count]=change_exists;
2656
/* the index changes if anything does */
2658
@<Print error messages about unused or undefined module names, or modules
2659
with multiple uses@>@;
2663
@<Store cross-reference data...@>=
2667
if (++module_count==(sixteen_bits)max_modules)
2668
OVERFLW("section numbers",ABBREV(max_modules));
2670
chngd_module[module_count]=NO; // It will become |YES| if any line changes.
2674
/* All modules start off in the global language. */
2675
params = global_params;
2678
@<Store cross-references in the \TeX\ part of a module@>;
2679
@<Store cross-references in the definition part of a module@>;
2680
@<Store cross-references in the \cee\ part of a module@>;
2682
if(chngd_module[module_count])
2685
typd_switch = defd_switch = NO; // Don't propagate beyond one module.
2688
@ The |C_xref| subroutine stores references to identifiers in \cee\ text
2689
material beginning with the current value of |next_control| and continuing
2690
until |next_control| is~`\.\{' or~`\v', or until the next ``milestone'' is
2691
passed (i.e., |next_control>=formatt|). If |next_control>=formatt| when
2692
|C_xref| is called, nothing will happen; but if |next_control="|"| upon
2693
entry, the procedure assumes that this is the~`\v' preceding \cee\ text
2694
that is to be processed.
2696
The program uses the fact that our internal code numbers satisfy the
2697
relations |xref_roman=identifier+roman| and |xref_wildcard=identifier
2698
+wildcard| and |xref_typewriter=identifier+typewriter| and |normal=0|.
2703
C_xref FCN((part0,mode0))
2705
PARSING_MODE mode0 C1("")@;
2707
PARAMS outer_params;
2708
PARSE_PARAMS parse_params0;
2709
name_pointer p; /* a referenced name */
2711
parsing_mode = mode0;
2713
if(parsing_mode == INNER)
2715
outer_params = params; /* Store whole structure. */
2716
parse_params0 = parse_params;
2719
if(language == LITERAL)
2720
if(next_control == @'|')
2722
@<Skip a verbatim scrap@>@;
2726
next_control = begin_meta;
2730
while (next_control<formatt)
2732
switch(next_control)
2734
case begin_language:
2735
@<Handle a possible language switch in the middle of the module@>@;
2743
if(language == LITERAL)
2744
@<Skip over literal text@>@;
2746
@<Skip over meta-comment@>@;
2751
case xref_typewriter:
2752
p = id_lookup(id_first, id_loc,
2753
(eight_bits)(next_control-identifier));
2755
{ /* User entries should be insensitive to \.{@@a} vs.\
2757
boolean defd0 = defd_switch;
2762
defd_switch = defd0;
2768
p = id_lookup(id_first, id_loc,
2769
(eight_bits)(next_control-identifier));
2773
if(part0 == DEFINITION)
2774
defd_switch = NO; /* Prevent the implicit~\.{@@[}
2775
from propagating beyond the first identifier. */
2777
if(C_LIKE(language) && parsing_mode == OUTER)
2779
if(p->ilk == typedef_like)
2780
@<Mark \&{typedef} variable@>@;
2781
else if(p->ilk == class_like)
2782
@<Mark \&{class} variable@>@;
2787
if(sharp_include_line && phase == 1 && read_iformats
2788
&& C_LIKE(language))
2794
next_control = get_next();
2796
if( next_control==@'|' || next_control==begin_comment)
2801
if(parsing_mode==INNER)
2803
params = outer_params;
2805
parse_params = parse_params0;
2806
parsing_mode = OUTER;
2810
@ This is executed during cross-referencing in literal mode when a '\v' is
2811
encountered during skipping \TeX.
2813
@<Skip a verbatim scrap@>=
2821
next_control = *loc++;
2827
else if(!get_line())
2829
ERR_PRINT(W, "Missing '|'. File ended while skipping a \
2831
next_control = @'|';
2840
IN_COMMON outer_char wbprefix[MAX_FILE_NAME_LENGTH];
2841
// Possible directory prefix for the web file name.
2842
EXTERN boolean do_inside; // Cross-reference stuff inside a \&{typedef}?
2843
EXTERN boolean qtd_file; // Is the include file quoted?
2849
EXTERN outer_char temp_in[L_tmpnam], temp_out[L_tmpnam];
2850
// Names of temporary files used in |get_iformats|.
2852
@ To scan an include file for |typedef| and/or |@c++ class| statements, we
2853
use two temporary files whose names are |temp_in| and |temp_out|. These
2854
are created once, the first time |get_iformats| is called (so we don't call
2855
|tmpnam| possible many times). The include command is written into
2856
|temp_in|. By means of issuing a |system| command, the C preprocessor
2857
expands that command and writes its results to |temp_out|. Then \FWEAVE\
2858
parses that file, cross-referencing only the |typedef| and/or |@c++ class|
2861
Presently, this only works for the \.{gcc} and \.{g++} compilers.
2869
outer_char file_name[256];
2875
language==C ? wt_style.output_ext.C_ : wt_style.output_ext.Cpp_);
2877
if((ftemp_in = FOPEN(temp_in, "w")) == NULL)
2879
printf("\n! Can't open temporary file `%s'", temp_in);
2886
mktmp(temp_out, (outer_char *)"");
2887
/* We don't open the output file here, as \.{cpp} may not
2888
write into it if it's open. */
2890
preprocessing = sharp_include_line = NO;
2892
/* Copy include file name, include delimiters. */
2893
STRNCPY(file_name, id_first, n=PTR_DIFF(int, id_loc, id_first));
2894
file_name[n] = '\0';
2895
to_outer((ASCII HUGE *)file_name);
2897
qtd_file = BOOLEAN(file_name[0] == '"');
2898
// Is this file name quoted (i.e., look locally)?
2900
/* Write the include file command to temporary file, so the preprocessor
2902
fprintf(ftemp_in, "#include %s\n", file_name);
2905
@<Create a command to run the preprocessor, then execute it@>@;
2907
@<Deflect the input file to be \.{temp\_out}@>@;
2909
if(new_depth != incl_depth || !get_line())
2910
goto restore; // No file, or nothing in it.
2913
// This flag says to not xref stuff inside braces of \&{typedef}.
2915
next_control = get_next();
2917
/* Parse the preprocessed include file until EOF is reached and the
2918
|incl_depth| changes. */
2919
while(new_depth == incl_depth)
2923
switch(next_control)
2926
p=id_lookup(id_first,id_loc,
2927
(eight_bits)(next_control-identifier));
2929
if(p->ilk == typedef_like)
2930
@<Mark \&{typedef} variable@>@;
2931
else if(p->ilk == class_like)
2932
@<Mark \&{class} variable@>@;
2937
next_control=get_next();
2942
preprocessing = sharp_include_line = YES;
2945
@ We'll use \.{gcc} as the preprocessor to scan the C include files.
2949
outer_char *temp, *temp_I;
2950
BUF_SIZE temp_len, ntemp;
2951
IN_COMMON outer_char *extra_args;
2953
@<Build the \.{-I} options into |temp_I|@>@;
2955
temp = GET_MEM("temp", ntemp=temp_len + STRLEN(RUN_CPP) + 4 + 3*3 + temp_len
2956
+ sizeof(temp_out) + sizeof(temp_in) + 3, outer_char);
2958
sprintf((char *)temp, "\n%s -P%s %s -o %s %s",
2960
language==C ? "gcc" : "g++",
2964
extra_args ? (char *)extra_args : "",
2969
// Echo the |system| command that runs the preprocessor.
2971
system((CONST char *)temp);
2973
FREE_MEM(temp_I, "temp_I", temp_len, outer_char);
2974
FREE_MEM(temp, "temp", ntemp, outer_char);
2977
@ By this time, the |FWEB_HDR_INCLUDES| environment variables has been
2978
read, and possibly accreted to by the \.{-I}~options preceding~\.{-H}. We
2979
tell the preprocessor to look first in the |wbprefix| directory, then in
2980
the |FWEB_HDR_INCLUDES|, then in the current directory. Note the use of
2981
the \.{-I.}~command of \.{gcc}, which looks in the directory current when
2982
the compiler was invoked.)
2986
IN_COMMON INCL_PATHS hdr_incl;
2989
temp_len = STRLEN(wbprefix) + hdr_incl.size + 3*(hdr_incl.num + 2) + 1;
2990
// Factor of 3 is for \.{\ -I}; of 2 adds web prefix and current dir.
2992
temp_I = GET_MEM("temp_I", temp_len, outer_char);
2995
sprintf((char *)temp_I, " -I%s", wbprefix);
2998
for(p=hdr_incl.list; (p1=(outer_char *)STRCHR(p, ':')) != NULL;
3002
STRCAT(temp_I, " -I");
3007
STRCAT(temp_I, " -I."); // Finally, the current directory.
3010
@ The following commands are borrowed with slight modifications from
3015
if(++incl_depth >= (int)max_include_depth)
3018
err_print(C, "Too many nested includes; %d allowed. \
3019
Increase with `-yid'.", max_include_depth);
3020
@.Too many nested includes@>
3024
{ /* No change file name specified; obtain it from the last level. */
3025
INPUT_PRMS *p_lower = &prms[incl_depth-1];
3026
INPUT_PRMS0 *p0_lower = &p_lower->change;
3028
STRCPY(change_file_name,p0_lower->File_name);
3029
change_file = p0_lower->File;
3030
change_params = p_lower->input_params;
3033
STRCPY(cur_file_name, temp_out);
3034
new_depth = incl_depth;
3037
IN_COMMON INCL_PATHS incl;
3039
/* Is |incl.list| the right thing to have here? Does it matter? */
3040
if(ini_input_prms(CUR_FILE, incl.list, NO))
3042
if(cur_prms.change->File != prms[incl_depth-1].change.File)
3044
else *cur_prms.change = prms[incl_depth-1].change;
3045
// Still using the old change file.
3049
/* Instead of printing the names of the temporary files, we print the
3050
include file name itself. */
3051
CLR_PRINTF(SHORT_INFO, include_file, (" (%s", file_name));
3052
/* Tell the terminal where we're reading from. */
3055
{ /* Failed to open include file. */
3061
@ The following is called from |wrap_up()| in \.{common.web}.
3068
if(read_iformats && rmv_files)
3070
remove((CONST char *)temp_in);
3071
remove((CONST char *)temp_out);
3075
@ Make a temporary file name, and append an extension. We use |tempnam| if
3076
possible, because it gives more control over the directory. Otherwise, we
3077
use the ANSI |tmpnam|.
3082
mktmp FCN((file_name, ext))
3083
outer_char *file_name C0("")@;
3084
outer_char *ext C1("")@;
3089
extern char *tempnam();
3092
STRCPY(wbprefix,"./");
3094
buffer = (outer_char *)tempnam((char *)wbprefix, "FTMP");
3095
// Non-|ANSI|, but more control over directory.
3097
buffer = (outer_char *)tmpnam(NULL); // |ANSI| routine.
3100
STRCPY(file_name, buffer);
3104
STRCAT(file_name, ".");
3105
STRCAT(file_name, ext);
3112
@ When an include line of the form |#include <test.h>| is sensed in C or
3113
\Cpp, we would like to open the related file \.{test.H} and process it for
3114
format commands. (Processing \.{test.h} would format and cross-reference
3115
many variables that the user wouldn't care to know about.) See ``Push
3116
stack'' code in \.{common.web}.
3118
@d change_params prms[incl_depth].input_params
3125
outer_char temp[100], HUGE *period;
3129
preprocessing = sharp_include_line = NO;
3131
STRNCPY(temp, id_first+1, n=PTR_DIFF(int, id_loc, id_first)-2);
3133
to_outer((ASCII HUGE *)temp);
3135
if(!(period = (outer_char HUGE *)STRRCHR(temp, '.')))
3139
STRCAT(temp, w_style.misc.include_ext);
3141
if(++incl_depth >= (int)max_include_depth)
3144
err_print(C, "Too many nested includes; %d allowed. \
3145
Increase with `-yid'.", max_include_depth);
3146
@.Too many nested includes@>
3150
{ /* No change file name specified; obtain it from the
3152
INPUT_PRMS *p_lower = &prms[incl_depth-1];
3153
INPUT_PRMS0 *p0_lower = &p_lower->change;
3155
STRCPY(change_file_name,p0_lower->File_name);
3156
change_file = p0_lower->File;
3157
change_params = p_lower->input_params;
3160
STRCPY(cur_file_name, temp);
3161
new_depth = incl_depth;
3164
IN_COMMON INCL_PATHS incl;
3166
if(ini_input_prms(CUR_FILE,incl.list,NO))
3168
if(cur_prms.change->File != prms[incl_depth-1].change.File)
3170
else *cur_prms.change = prms[incl_depth-1].change;
3171
// Still using the old change file.
3175
CLR_PRINTF(SHORT_INFO, include_file,
3176
(" (%s", (char *)cur_file_name));
3177
/* Tell the terminal where we're reading from. */
3180
{ /* Failed to open include file. */
3185
if(new_depth != incl_depth || !get_line())
3188
next_control = get_next();
3190
while(new_depth == incl_depth)
3192
switch(next_control)
3199
ERR_PRINT(W, "Invalid command in #include file");
3205
preprocessing = sharp_include_line = YES;
3208
@ At this point, we've sensed an explicit \.{@@(}.
3210
@<Skip over meta-comment@>=
3216
ERR_PRINT(W,"Input ended during meta-comment");
3220
if(loc[0] == @'@@' && loc[1] == @')')
3221
{ /* Sensed end-meta. */
3228
@ Here we're scanning an implicit (literal) |begin_meta|.
3230
@<Skip over literal text@>=
3234
if(loc > limit && !get_line())
3236
next_control = new_module;
3261
@ For the forward-referencing facility, we need to format the variable of a
3262
\&{typedef} during phase~1. We mark the first variable we come to that isn't
3263
reserved and isn't enclosed by braces. (We must format identifiers even if
3264
they're inside braces.)
3265
@<Mark \&{typedef} variable@>=
3267
int brace_level = 0;
3268
boolean typedefd_it = NO;
3270
/* First, we scan over a possible |struct|. */
3271
while((next_control=get_next()) == identifier)
3272
if((p=id_lookup(id_first,id_loc,0))->ilk != struct_like)
3274
new_xref(part0,p); // Structure name: ``|typedef struct s@;|''.
3275
next_control = get_next(); // Don't repeat the structure name.
3279
while(next_control <=module_name)
3281
switch(next_control)
3290
if(brace_level-- == 0)
3292
err_print(W, "Extra '%c' in typedef",
3293
XCHR(next_control));
3299
p = id_lookup(id_first,id_loc,0);
3301
if(brace_level == 0 && !typedefd_it)
3306
defd_switch = BOOLEAN(mark_defined.typedef_name);
3307
defd_type = TYPEDEF_NAME;
3315
if(brace_level == 0 && !typedefd_it)
3316
typedefd_it = YES; /* Don't do any more (e.g., array
3317
dimensions). (But this means one can't yet do |BB| in |typedef int AA, BB@;|.) */
3326
case WEB_definition:
3328
case new_output_file:
3335
if(cur_module) new_mod_xref(cur_module);
3336
next_control = get_next();
3337
if(next_control == @'=')
3339
ERR_PRINT(W,"'=' not allowed after @@<...@@> \
3340
inside typedef; check typedef syntax. Inserted ';'");
3341
next_control = @';';
3346
if(brace_level == 0) goto done; // End of |typedef|.
3350
@<Handle a comment@>@;
3354
next_control = get_next();
3358
defd_switch = typd_switch = NO; // Just in case we screwed up.
3360
if(next_control == new_module)
3362
ERR_PRINT(W,"Module ended during typedef");
3369
@d CANT_DO(part) cant_do(OC(#part))
3373
cant_do FCN((the_part))
3374
outer_char *the_part C1("")@;
3376
err_print(W, "You can't do that inside %s text", the_part);
3379
@ Similarly, \&{class} variables should be formatted during phase~1.
3380
@<Mark \&{class}...@>=
3382
if((next_control=get_next()) == identifier)
3384
p = id_lookup(id_first,id_loc,0);
3386
defd_switch = BOOLEAN(mark_defined.typedef_name);
3387
defd_type = TYPEDEF_NAME;
3396
@ The |language| has already been set inside |get_next()| when we get to here.
3398
@<Handle a possible language switch...@>=
3403
CONFUSION("handle possible language switch",
3404
"A language hasn't been defined yet");
3410
if(mode0 == OUTER && !free_form_input)
3411
@<Set up column mode@>@;
3415
if(mode0 == OUTER) @<Set up col...@>@;
3426
CONFUSION("handle possible language switch",
3427
"Langage %i is invalid", language);
3431
@ The |outr_xref| subroutine is like |C_xref| but it begins with
3432
|next_control!='|'| and ends with |next_control>=formatt|. Thus, it handles
3433
\cee\ text with embedded comments.
3438
outr_xref FCN((part0)) /* extension of |C_xref| */
3441
while (next_control<formatt)
3442
if(next_control != begin_comment)
3443
C_xref(part0, OUTER);
3445
@<Handle a comment@>@;
3448
@ Deal with a comment inside C~text.
3449
@<Handle a comment@>=
3451
int bal; // Brace level in comment.
3453
bal = copy_comment(1); next_control = @'|';
3458
{ /* Inside comment. */
3460
C_xref(part0,INNER);
3462
if (next_control==@'|')
3463
bal = copy_comment(bal);
3465
bal = 0; // An error message will occur in phase 2.
3469
@ In the \TeX\ part of a module, cross-reference entries are made only for
3470
the identifiers in \cee\ texts enclosed in~\Cb, or for control texts
3471
enclosed in \.{@@\^}$\,\ldots\,$\.{@@>} or \.{@@.}$\,\ldots\,$\.{@@>} or
3472
\.{@@9}$\,\ldots\,$\.{@@>}.
3474
@<Store cross-references in the \T...@>=
3478
do_inside = YES; // So don't eliminate the user cross-references.
3482
switch (next_control=skip_TeX())
3484
@<Specific language cases@>:
3485
loc--; // Falls through to general case below.
3489
@<Set the |language|...@>;
3494
nuweb_mode = !NUWEB_MODE;
3502
xref_switch = def_flag;
3506
case trace: tracing=next_control-@'0'; continue;
3507
#endif /* |DEBUG| */
3510
while(next_control <= module_name)
3514
if(next_control == @'|' || next_control == new_module)
3517
next_control = get_next();
3519
if(next_control == @'|')
3525
case xref_roman: case xref_wildcard: case xref_typewriter:
3526
case macro_module_name: case module_name:
3528
loc-=2; next_control=get_next(); // Scan to \.{@@>}.
3530
if( !(next_control==module_name ||
3531
next_control==macro_module_name) )
3532
new_xref(TEX_,id_lookup(id_first,id_loc,
3533
(eight_bits)(next_control-identifier)));
3536
case invisible_cmnt:
3541
if (next_control>=formatt)
3546
@ During the definition and \cee\ parts of a module, cross-references are
3547
made for all identifiers except reserved words; however, the identifiers in
3548
a format definition are referenced even if they are reserved. The \TeX\
3549
code in comments is, of course, ignored, except for \cee\ portions enclosed
3550
in~\Cb; the text of a module name is skipped entirely, even if it contains
3553
The variables |lhs| and |rhs| point to the respective identifiers involved
3554
in a format definition.
3558
EXTERN name_pointer lhs, rhs; /* pointers to |byte_start| for format
3561
@ When we get to the following code we have |next_control>=formatt|.
3563
@d KILL_XREFS(name) no_xref |= !defn_mask.name
3564
@d INDEX_SHORT index_short = index_flag = YES // Implicit \.{@@~}.
3566
@<Store cross-references in the d...@>=
3568
boolean no_xref0 = no_xref;
3570
the_part = DEFINITION;
3572
while (next_control<begin_code)
3573
{ /* |formatt| or |definition| or |WEB_definition| or \.{@@\#...}
3575
switch(next_control)
3577
case WEB_definition:
3578
if(mark_defined.WEB_macro && lower_case_code)
3579
defd_switch = YES; // Implied \.{@@[}.
3581
xref_switch = def_flag; /* Implied \.{@@\_} */
3582
defd_type = M_MACRO;
3594
if(mark_defined.outer_macro && mark_defined.outer_macro)
3595
defd_switch = YES; // Implied \.{@@[}.
3597
xref_switch = def_flag; /* Implied \.{@@\_} */
3598
defd_type = D_MACRO;
3600
KILL_XREFS(outer_macros);
3605
KILL_XREFS(outer_macros);
3615
switch(next_control)
3618
pr_format(YES, YES);
3622
@<Absorb limbo text@>@;
3626
@<Overload an operator@>@;
3630
@<Overload an identifier@>@;
3633
case invisible_cmnt:
3634
loc = limit + 1; // Skip the line.
3637
next_control=get_next();
3641
outr_xref(DEFINITION);
3646
@ The syntax of a format definition is ``\.{@@f\ new\_name\ old\_name}'' or
3647
``\.{@@f\ `\{\ 10}''. Error messages for improper format definitions of
3648
the first kind will be issued in phase two; for the second kind, in phase
3649
one. For the first kind, our job in phase one is to define the |ilk| of a
3650
properly formatted identifier, and to fool the |new_xref| routine into
3651
thinking that the identifier on the right-hand side of the format
3652
definition is not a reserved word. For the second kind, we must actually
3653
change the category code of a \TeX\ character, and that must be done in
3654
phase one so future identifiers can be resolved properly.
3659
pr_format FCN((xref_lhs, xref_rhs))
3660
boolean xref_lhs C0("")@;
3661
boolean xref_rhs C1("")@;
3663
eight_bits last_control,rhs_ilk;
3664
LANGUAGE saved_language = language;
3667
KILL_XREFS(Formats);
3669
KILL_XREFS(formats);
3676
last_control = next_control = get_next(); /* Identifier or module name to be
3677
formatted, or |ASCII| character. */
3679
if (next_control==identifier || next_control==module_name)
3680
@<Process an identifier or module name@>@;
3681
else if(next_control==@'`')
3682
@<Change a category code@>@;
3684
if(saved_language==TEX)
3685
language = saved_language;
3688
@ Here we deal with format commands of the form ``\.{@@f\ new\_name\
3691
@<Process an identifier...@>=
3693
if(next_control==identifier)
3695
lhs=id_lookup(id_first, id_loc, normal);
3699
new_xref(DEFINITION,lhs);
3704
next_control=get_next();
3706
if (next_control==identifier)
3707
{ /* Format the lhs like this one. */
3708
rhs=id_lookup(id_first, id_loc,normal);
3712
if(last_control==identifier)
3713
@<Format the left-hand side@>@;
3715
lhs->mod_ilk = rhs->ilk;
3716
// We're formatting a module name.
3719
/* Take care of the possibility that the rhs may not yet have been
3726
new_xref(DEFINITION,rhs);
3731
next_control=get_next();
3735
@ Set the appropriate format bit.
3736
@<Format the left-hand side@>=
3738
lhs->ilk = rhs->ilk;
3740
/* First turn off the old lhs bit (retaining all others), then add in the
3741
new bit for the current language. */
3742
#define RST_BIT(field) lhs->field = BOOLEAN(lhs->field & ~(boolean)language)\
3743
| (rhs->field & (boolean)language)
3745
RST_BIT(reserved_word);
3747
RST_BIT(intrinsic_word);
3753
@ Here we consider format commands of the form ``\.{@@f\ `\{\ 10}''.
3754
|get_TeX|~leaves the (|outer_char|) constant string between
3755
[|id_first|,|id_loc|).
3756
@<Change a category code@>=
3758
if((next_control = get_TeX()) != constant)
3759
ERR_PRINT(W,"Invalid @@f command: \
3760
One of the representations `a, `\\a, or `^^M is required");
3763
int c = TeX_char(); // Convert the |ASCII| code in |id_first|.
3765
next_control = get_next(); // Now expecting integer category code.
3767
if(next_control != constant) ERR_PRINT(W,"Invalid category code");
3772
TERMINATE(id_loc,0);
3773
cat = (TeX_CATEGORY)ATOI(id_first);
3774
// Numerical value of new cat code.
3776
if((int)cat < 0 || (int)cat > 15)
3777
ERR_PRINT(W,"Category code must be between 0 and 15");
3778
else TeX[c] = cat; // Change the category code.
3780
next_control = get_next();
3785
@ We require a special routine to obtain an |ASCII| character in \TeX's
3786
representation after a~'\.`'. On entry, |loc|~is positioned after
3787
the~'\.`'. The possible representations are~`\.{a}', `\.{\\a}',
3797
ERR_PRINT(W,"@@f line ends prematurely");
3801
id_first = id_loc = mod_text + 1;
3803
if(*loc == @'\\') *id_loc++ = *loc++;
3804
else if(*loc == @'^' && *(loc+1) == @'^')
3805
{ // \TeX's way of representing control characters.
3806
*id_loc++ = *loc++; @~ *id_loc++ = *loc++;
3810
if(*(loc+1) == @'@@') loc++;
3811
else ERR_PRINT(W,"You should say `@@@@");
3813
*id_loc++ = *loc++; // Position to next non-processed character.
3816
id_first = esc_buf(id_loc+1,mod_end,id_first,YES);
3822
@ Here we convert the constant obtained in the previous routine into an
3831
while(*id_first == @'\\') id_first++;
3833
if(*id_first == @'^' && *(id_first+1) == @'^')
3836
if(c >= 64) c -= 64;
3844
@ Limbo text commands have the form ``\.{@@l\ "abc\\ndef"}'', and must be
3845
absorbed during phase one so they can be dumped out at the beginning of
3848
@<Absorb limbo text@>=
3850
LANGUAGE language0 = language;
3855
language = C; // In order to absorb strings properly.
3857
insert_breaks = NO; // We want the string to be absorbed completely literally.
3859
if((next_control = get_next()) != stringg)
3860
ERR_PRINT(W,"String must follow @@l");
3862
{ // Begin by stripping off delimiting quotes.
3863
for(id_first++,id_loc--; id_first<id_loc; )
3865
if(*id_first==@'@@')
3867
if(*(id_first+1)==@'@@')
3870
ERR_PRINT(W,"Double @@ should be used in strings");
3873
/* Deal with escape sequences. */
3874
if(*id_first == @'\\')
3877
/* Splitting the following line before |HUGE| led to compiler problem with
3880
(CONST ASCII HUGE*HUGE*)&id_first))@;
3883
app_tok(*id_first++);
3886
freeze_text; /* We'll know we've collected stuff because |text_ptr|
3887
will be advanced. */
3890
insert_breaks = YES;
3892
language = language0;
3895
@ The syntax of an operator-overloading command is
3896
``\.{@@v\ .IN.\ "\\in"\ +}''.
3898
@<Overload an op...@>=
3900
OPERATOR HUGE *p,HUGE *p1;
3904
/* Look at the first field, which should be an operator or a dot-op. */
3905
next_control = get_next();
3907
if(next_control == identifier)
3908
ERR_PRINT(W,"For future compatibility, please use syntax `.NAME.' for \
3909
overloading dot operators");
3911
if(!(p=valid_op(next_control)))
3912
ERR_PRINT(W,"Operator after @@v is invalid");
3915
if(get_next() != stringg)
3916
ERR_PRINT(W,"Second argument (replacement text) \
3917
of @@v must be a quoted string");
3920
int k = language_num;
3921
OP_INFO HUGE *q = p->info + k;
3922
int n = PTR_DIFF(int, id_loc, id_first) - 2; /* Don't count the
3923
string delimiters. */
3926
if(q->defn) FREE_MEM(q->defn,"q->defn",STRLEN(q->defn)+1,
3928
q->defn = GET_MEM("q->defn",n+1,outer_char);
3930
*(id_loc-1) = '\0'; // Kill off terminating quote.
3932
for(s=q->defn,id_first++; *id_first; s++)
3933
if(*id_first == @'\\')
3936
*s = XCHR(esc_achar((CONST ASCII HUGE
3939
else *s = XCHR(*id_first++);
3941
overloaded[k] = q->overloaded = YES;
3943
/* There may be several representations with the same name. */
3944
for(p1=op; p1<op_ptr; p1++)
3946
if(p1==p || !p1->op_name) continue;
3948
if(STRCMP(p1->op_name,p->op_name) == 0)
3950
OP_INFO HUGE *q1 = p1->info + k;
3952
if(q1->defn) FREE_MEM(q1->defn,"q1->defn",
3953
STRLEN(q1->defn)+1,outer_char);
3954
q1->defn = GET_MEM("q1->defn",n+1,outer_char);
3955
STRCPY(q1->defn,q->defn);
3956
q1->overloaded = YES;
3960
/* Get the new category and set it. If the last construction isn't
3961
recognized as a valid operator, the category is set to |expr|. */
3962
p = valid_op(next_control=get_next());
3964
q->cat = (p ? p->info[k].cat : (eight_bits)expr);
3969
@ The syntax for overloading an identifier is ``\.{@@w\ \It{id}\
3970
"\dots"}'', or the string replacement text can be replaced by~'\..', which
3971
means just prepend a backslash to make it into a macro name.
3973
@d QUICK_FORMAT @'.' // The shorthand for overloading like itself.
3975
@<Overload an id...@>=
3977
if((next_control=get_next()) != identifier)
3978
ERR_PRINT(W,"Identifier must follow @@w");
3981
name_pointer p = id_lookup(id_first,id_loc,normal);
3985
ASCII HUGE *id_first0, HUGE *id_loc0;
3987
/* Index the identifier (but not defined). Force short identifiers to be
3991
new_xref(DEFINITION, p);
3993
/* Remember the first identifier. */
3994
id_first0 = id_first;
3997
switch(next_control=get_next())
4000
if((next_control = get_next()) != identifier)
4002
ERR_PRINT(W,"Identifier must follow '\\'");
4006
next_control = ignore; /* We don't want to put the
4007
identifier into the index. */
4012
id_first = id_first0;
4017
n = PTR_DIFF(int, id_loc, id_first) + 1;
4019
goto fmt_like_string;
4024
n = PTR_DIFF(int, id_loc, id_first) - 2; // Don't count quotes.
4026
id_first++; // Skip over opening quote.
4029
p->wv_macro = w = GET_MEM("wv_macro",1,WV_MACRO);
4030
w->text = GET_MEM("w->text",n+1,outer_char);
4032
if(offset) *w->text = @'\\';
4034
for(s=w->text + offset; *id_first; s++)
4035
if(*id_first == @'\\')
4038
*s = esc_achar((CONST ASCII HUGE
4041
else *s = *id_first++;
4043
w->len = PTR_DIFF(unsigned, s, w->text);
4045
w->cat = (eight_bits)(upper_case_code ? 0 : expr); // Temporary
4050
ERR_PRINT(W,"Second argument (replacement text) \
4051
of @@w must be either a quoted string or '.' or have the form \\name");
4057
@ Finally, when the \TeX\ and definition parts have been treated, we have
4058
|next_control>=begin_code|.
4062
EXTERN boolean unnamed_section SET(NO);
4065
@<Store cross-references in the \cee...@>=
4069
if (next_control<=module_name)
4070
{ /* |begin_code| or |module_name| */
4071
boolean beginning_module = YES;
4073
if(next_control==begin_code)
4075
boolean nuweb_mode0 = nuweb_mode;
4077
unnamed_section = YES;
4079
params = global_params;
4080
nuweb_mode = nuweb_mode0;
4083
mod_xref_switch = NO;
4085
if(mark_defined.fcn_name && lower_case_code)
4087
defd_switch = YES; // Implicit \.{@@[}.
4088
defd_type = FUNCTION_NAME;
4093
unnamed_section = NO;
4094
mod_xref_switch = def_flag;
4100
if (next_control==module_name && cur_module)
4101
new_mod_xref(cur_module);
4103
if(beginning_module)
4106
next_control = get_next();
4108
next_control = @'='; // For |begin_code|.
4110
if(next_control==@'=')
4111
if( !nuweb_mode && ((FORTRAN_LIKE(language) && !free_form_input)
4112
|| (language==TEX)) )
4113
@<Set up column mode@>@;
4115
beginning_module = NO;
4117
else next_control = get_next();
4121
while (next_control<=module_name)
4122
; // Hunt for new module.
4124
column_mode = NO; // Turn off the FORTRAN verbatim input mode.
4125
unnamed_section = NO; // Don't deflect cross-references.
4129
@ After phase one has looked at everything, we want to check that each
4130
module name was both defined and used. The variable |cur_xref| will point
4131
to cross-references for the current module name of interest.
4133
@d IS_ON(flag, bits) ((flag) & (bits))
4140
EXTERN xref_pointer cur_xref; /* temporary cross-reference pointer */
4141
IN_COMMON boolean mod_warning_flag;
4143
@ The following recursive procedure
4144
walks through the tree of module names and prints out anomalies.
4151
name_pointer p C1("Print anomalies in subtree |p|.")@;
4157
int never_defined:1, never_used:1, multiple_uses:1;
4160
anomalies.never_defined = anomalies.never_used = anomalies.multiple_uses = NO;
4166
status |= mod_check(p->llink);
4168
cur_xref = (xref_pointer)p->xref;
4170
if(cur_xref->num <def_flag)
4171
anomalies.never_defined = YES;
4173
while (cur_xref->num >= def_flag)
4174
cur_xref = cur_xref->xlink;
4177
anomalies.never_used = YES;
4179
n_uses = p->mod_info->params.uses;
4182
anomalies.multiple_uses = YES;
4184
if(anomalies.never_defined || anomalies.never_used
4185
|| anomalies.multiple_uses)
4187
boolean warning_printed = NO;
4191
if(anomalies.never_defined)
4194
warning_printed = mod_warn(p, OC("never defined"));
4195
@.Never defined: <section name>@>
4199
if(anomalies.never_used && IS_ON(mod_warning_flag, NEVER_USED))
4204
warning_printed = mod_warn(p, OC("never used"));
4206
@.Never used: <section name>@>
4208
if(anomalies.multiple_uses
4209
&& IS_ON(mod_warning_flag, MULTIPLE_USES))
4216
= mod_warn(p, OC("multiple uses"));
4218
printf(" (%i)", n_uses);
4221
@.Multiple uses: <section name>@>
4225
printf("."), fflush(stdout);
4226
status = warning_printed;
4230
status |= mod_check(p->rlink);
4239
mod_warn FCN((p, msg))
4240
name_pointer p C0("")@;
4241
outer_char *msg C1("")@;
4243
printf("\n%c! ", beep(1));
4248
set_color(color0.last);
4250
printf((char *)msg);
4255
@ Start off at the top of the tree.
4257
@<Print error messages about un...@>=
4259
if(mod_check(root) && msg_level < SHORT_INFO)
4265
@* LOW-LEVEL OUTPUT ROUTINES.
4266
The \TeX\ output is supposed to appear in lines at most |line_length|
4267
characters long, so we place it into an output buffer. During the output
4268
process, |out_line| will hold the current line number of the line about to
4271
@d CHECK_OPEN // This is defined differently in \FTANGLE.
4275
EXTERN BUF_SIZE line_length;
4276
EXTERN ASCII HUGE *out_buf; // Assembled characters.
4277
EXTERN ASCII HUGE *out_end; // End of |out_buf|.
4279
EXTERN ASCII HUGE *out_ptr; // Points to last character in |out_buf|.
4280
EXTERN LINE_NUMBER out_line; // number of next line to be output.
4285
ALLOC(ASCII,out_buf,ABBREV(line_length),line_length,1); /* assembled
4287
out_end = out_buf+line_length; /* end of |out_buf| */
4289
@ The |flush_buffer| routine empties the buffer up to a given breakpoint,
4290
and moves any remaining characters to the beginning of the next line. If
4291
the |per_cent| parameter is |YES|, a |'%'|~is appended to the line that is
4292
being output; in this case the breakpoint~|b| should be strictly less than
4293
|out_end|. If the |per_cent| parameter is |NO|, trailing blanks are
4294
suppressed. The characters emptied from the buffer form a new line of
4297
The same caveat that applies to |ASCII_write| applies to |c_line_write|. (??)
4299
@d OUT_FILE tex_file
4301
fflush(tex_file),FWRITE(out_buf+1,n,tex_file)
4302
@d ASCII_LINE_WRITE(n)
4303
fflush(tex_file),ASCII_file_write(tex_file,out_buf+1,(size_t)(n))@;
4304
@d TEX_PUTXCHAR(c) PUTC(c) // Send an |outer_char| to the \.{TEX} file.
4305
@d TEX_NEW_LINE PUTC('\n') // A newline to the \.{TEX} file.
4306
@d TEX_PRINTF(s) fprintf(tex_file,s) // A string to the \.{TEX} file.
4311
flush_buffer FCN((b, per_cent))
4312
ASCII HUGE *b C0("")@;
4313
boolean per_cent C1("Outputs from |out_buf+1| to |b|, \
4314
where |b<=out_ptr|.")@;
4317
ASCII HUGE *out_start;
4321
out_start = out_buf + 1;
4322
j = b; // Pointer into |out_buffer|.
4324
/* Remove trailing blanks. */
4326
while (j>out_buf && *j==@' ')
4329
ASCII_LINE_WRITE(j-out_buf);
4335
TEX_NEW_LINE; // Nuweb mode has explicit newlines.
4341
if(*out_start == @'%')
4344
STRNCPY(out_start, b+1, PTR_DIFF(size_t,out_ptr,b));
4347
out_ptr -= b - out_start + 1;
4353
@ When we are copying \TeX\ source material, we retain line breaks that
4354
occur in the input, except that an empty line is not output when the \TeX\
4355
source line was nonempty. For example, a line of the \TeX\ file that
4356
contains only an index cross-reference entry will not be copied. The
4357
|fin_line| routine is called just before |get_line| inputs a new line,
4358
and just after a line break token has been emitted during the output of
4359
translated \cee\ text.
4364
fin_line(VOID) /* do this at the end of a line */
4366
ASCII HUGE *k; // Pointer into |cur_buffer|.
4368
if (out_ptr>out_buf)
4369
flush_buffer(out_ptr, NO); // Something nontrivial in line.
4372
/* Don't output an empty line when \TeX\ source line is nonempty. */
4373
for (k=cur_buffer; k<=limit; k++)
4374
if (*k!=@' ' && *k!=tab_mark)
4377
flush_buffer(out_buf, NO); // Empty line.
4381
@ In particular, the |fin_line| procedure is called near the very
4382
beginning of phase two. We initialize the output variables in a slightly
4383
tricky way so that the first line of the output file will be `\.{\\input
4384
fwebmac}'. This is the default. However, occasionally, one may need to
4385
load other macro packages before \.{fwebmac}. To prevent this first line to
4386
be generated, use the command line option~``\.{-w}''. To change the name
4387
of the default, way ``\.{-wnew\_name}''---for example, ``\.{-wfmac.sty}''.
4391
out_ptr = out_buf; out_line = 1;
4396
TEX_PRINTF("%% --- FWEB's macro package ---\n\\input ");
4397
OUT_STR(*fwebmac ? fwebmac : w_style.misc.macros); /* The command
4398
line overrides the style file. */
4402
@ When the `\.{@@I}'~command is used in conjunction with the command-line
4403
option `\.{-i}', we process the incoming text, but don't write it out. We
4404
need an output flag to tell us when output is allowed.
4408
EXTERN boolean output_on SET(YES);
4410
@ When we wish to append one character~|c| to the output buffer, we write
4411
`|out(c)|'; this will cause the buffer to be emptied if it was already
4412
full. |c|~is assumed to be of type |ASCII|. If we want to append more
4413
than one character at once, we say |OUT_STR(s)|, where |s|~is a string
4414
containing the characters, or |out_del_str(s,t)| (``output a delimited
4415
string''), where~|s| and~|t| point to the same array of characters (stored
4416
as 16-bit tokens); characters from~|s| to~|t-1|, inclusive, are output. The
4417
|out_str| routine takes an |outer_char| string as an argument, since this
4418
is typically used as a print statement from inside the code.
4420
A line break will occur at a space or after a single-nonletter \TeX\
4425
if(out_ptr >= out_end)
4427
*(++out_ptr) = (ASCII)(c);
4430
@d OUT_STR(s) out_str(OC(s))
4435
out_del_tokens FCN((s, t)) /* output |ASCII| tokens from |s| to |t-1|. */
4436
token_pointer s C0("")@;
4437
token_pointer t C1("")@;
4440
return; // Skip output.
4447
out_del_str FCN((s, t)) /* output |ASCII| characters from |s| to |t-1|. */
4448
ASCII HUGE *s C0("")@;
4449
ASCII HUGE *t C1("")@;
4452
return; // Skip output.
4459
out_str FCN((s)) /* output |outer_char| characters from |s| to end of string */
4460
CONST outer_char HUGE *s C1("")@;
4463
return; // Skip output.
4469
@ Here we write an |outer_char| file name. We have to watch out for special
4475
CONST outer_char HUGE *s C1("File name to be written.")@;
4485
@<Special string cases@>:
4493
@ Escape and output an |ASCII| string.
4498
CONST ASCII HUGE *s C1("ASCII text to be written.")@;
4504
@<Special string cases@>:
4512
@ The |break_out| routine is called just before the output buffer is about
4513
to overflow. To make this routine a little faster, we initialize position~0
4514
of the output buffer to~'\.\\'; this character isn't really output.
4520
@ A long line is broken at a blank space or a newline (which may enter from
4521
a limbo string), or just before a backslash that isn't preceded by another
4522
backslash or a newline. In the latter case, a~|'%'| is output at the break.
4527
break_out(VOID) /* finds a way to break the output line */
4529
ASCII HUGE *k = out_ptr; /* pointer into |out_buf| */
4530
boolean is_tex_comment = BOOLEAN(*(out_buf+1) == @'%');
4536
@<Print warning message, break the line, and |return|@>;
4538
if(STRNCMP(k, "\\WEM ", 4) == 0)
4539
{ /* |ASCII|/|outer_char| conflict! */
4540
flush_buffer(k+=4, NO);
4546
flush_buffer(++k, NO);
4554
@<Print warning message, break the line, and |return|@>;
4558
flush_buffer(k, NO);
4562
if (*k==@'\n' && k[-1] != @'\n')
4563
{/* Get the per-cent sign before the newline. */
4565
flush_buffer(k, NO); // Kill off the newline.
4569
if (*(k--)==@'\\' && *k!=@'\\' && *k != @'\n')
4570
{ /* we've decreased |k| */
4571
flush_buffer(k, YES);
4577
*(++out_ptr) = @'%';
4580
@ We get to this module only in unusual cases that the entire output line
4581
consists of a string of backslashes followed by a string of nonblank
4582
non-backslashes. In such cases it is almost always safe to break the line
4583
by putting a~|'%'| just before the last character.
4585
@<Print warning message...@>=
4588
printf("\n! Line had to be broken (output l. %u):\n",out_line);
4589
@.Line had to be broken@>
4590
ASCII_write(out_buf+1, out_ptr-out_buf-1);
4593
flush_buffer(out_ptr-1, YES);
4597
@ Here is a macro that outputs a module number in decimal notation. The
4598
number to be converted by |out_mod| is known to be less than |def_flag|, so
4599
it cannot have more than five decimal digits. If the module is changed, we
4600
output~`\.{\\*}' just after the number.
4605
out_mod FCN((n,encap))
4606
sixteen_bits n C0("Module number.")@;
4607
boolean encap C1("Encapsulate?")@;
4612
sprintf(s,"%s%s%u%s",
4613
(char *)w_style.indx.encap_prefix,
4614
(char *)w_style.indx.encap_infix
4616
, (char *)w_style.indx.encap_suffix);
4618
sprintf(s, "%u", n);
4625
if(makeindex && phase==3)
4628
fprintf(mx_file, "%c%u%c",
4629
(char)w_style.indx.m_arg_open
4631
, (char)w_style.indx.m_arg_close);
4633
fprintf(mx_file, "%u", n); // Shouldn't occur.
4637
@ The |out_name| procedure is used to output an identifier or index entry,
4638
enclosing it in braces. When we're outputting an identifier, we must escape
4639
the various special characters that may sneak in. Index entries are treated
4648
out_name FCN((m_temp, surround,nis_id, p))
4649
outer_char *m_temp C0("Buffer")@;
4650
boolean surround C0("Surround with braces?")@;
4651
boolean is_id C0("Flag to distinguish identifier/index entry.")@;
4652
name_pointer p C1("The name to be output.")@;
4654
ASCII HUGE *k, HUGE *k_end=(p+1)->byte_start; // Pointers into |byte_mem|.
4655
boolean multi_char,non_TeX_macro;
4656
sixteen_bits mod_defined;
4659
return; // Skip output.
4661
multi_char = BOOLEAN(k_end - p->byte_start > 1);
4663
if(multi_char && surround)
4664
out(@'{');// Multiple-letter identifiers are enclosed in braces.
4666
non_TeX_macro = BOOLEAN(is_id && *p->byte_start == @'\\' && language != TEX);
4669
out(@'$'); /* \Cpp\ macros (such as those like \.{\\Wcp} that would
4670
arise from |@c++ operator +=()|) must be in math mode. */
4672
for (k=p->byte_start; k<k_end; k++)
4676
{ /* Escape the special characters in identifiers. */
4678
case @'{': case @'}':
4679
/* A non-\TeX\ identifier can result from the translation of an operator
4680
name in \Cpp. For that, we shouldn't escape the opening backslash. We
4681
also assume that any braces following that macro should be interpreted
4686
@<Other string cases@>:
4696
if(multi_char && surround)
4699
if(m_temp && makeindex)
4701
int n = out_ptr + 1 - m_start;
4703
STRNCPY(m_temp, m_start, n);
4708
@<Output the overloaded translation@>@;
4710
/* Should do all languages here. (Sorted!). */
4711
if(subscript_fcns && (mod_defined = p->defined_in(language)))
4716
OUT_STR("\\protect");
4718
sprintf(temp,"\\WIN%d{%d}",DEFINED_TYPE(p),
4719
mod_defined==module_count ? 0 : mod_defined);
4725
@<Output the overlo...@>=
4727
WV_MACRO HUGE *w = p->wv_macro;
4728
ASCII HUGE *s = w->text;
4738
@ The following can occur in identifiers recognized by \FWEB.
4739
@<Special identifier cases@>=
4748
@* ROUTINES THAT COPY \TeX\ MATERIAL. During phase two, we use the
4749
subroutines |copy_limbo| and |copy_TeX| in place of the analogous
4750
|skip_limbo| and |skip_TeX| that were used in phase one. The routine
4751
|copy_comment| serves for both phases.
4753
The |copy_limbo| routine, for example, begins by outputting two kinds of
4754
\TeX\ code that it has constructed or collected. First, it writes out
4755
\TeX\ definitions for user-defined dot constants; second, it writes out any
4756
limbo text that it collected during phase one. Then it takes \TeX\
4757
material that is not part of any module and transcribes it almost verbatim
4758
to the output file. No `\.{@@}'~signs should occur in such material except
4759
in `\.{@@@@}'~pairs; such pairs are replaced by singletons.
4768
@<Output default definitions for user-defined dot constants@>@;
4769
@<Output any limbo text definitions@>@;
4771
OUT_STR("\n% --- Beginning of user's limbo section ---");
4772
flush_buffer(out_ptr, NO);
4776
if (loc>limit && (fin_line(), !get_line()))
4782
out(*(loc++)); // Copy verbatim to output.
4786
c=*loc++; // Character after `\.{@@}'.
4788
if (ccode[c]==new_module)
4789
break; // Recognized beginning of first section.
4791
if (c!=@'z' && c!=@'Z')
4794
@<Cases to set |language| and |break|@>@:@;
4800
case invisible_cmnt:
4801
loc = limit + 1; // Skip entire rest of line.
4805
out(@'@@'); // $\.{@@@@} \to \.{@@}$.
4809
loc-=2; get_next(); /* skip to \.{@@>} */
4810
@<Output an RCS-like keyword@>@;
4814
ERR_PRINT(W,"Double @@ required \
4815
outside of sections");
4816
@.Double \AT! required...@>
4821
@<Output the end of limbo section@>@;
4824
@ By the beginning of phase~2, we know about any user-defined operators in
4825
\Fortran-90 via the \.{@@v}~command. Here we output default (empty)
4826
definitions of the associated
4827
macros. The user can override these in his limbo section.
4829
@<Output default def...@>=
4834
/* An extra blank line after \.{\\input fwebmac.sty}. */
4835
for(k=0; k<NUM_LANGUAGES; k++)
4838
flush_buffer(out_ptr, NO);
4842
for(k=0; k<NUM_LANGUAGES; k++)
4845
flush_buffer(out_ptr, NO);
4847
OUT_STR("% --- Overloaded operator definitions from @@v for '");
4848
OUT_STR(lang_codes[k]);
4850
flush_buffer(out_ptr, NO);
4852
for(p=op; p<op_ptr; p++)
4854
OP_INFO HUGE *q = p->info + k;
4857
@<Define to \TeX\ an overloaded operator@>@;
4860
flush_buffer(out_ptr, NO);
4864
@ This fragment produces output of the form
4865
``\.{\\newbinop\{abc\}\{C\{def\}}''. See \.{fwebmac.web} to learn how such
4868
@<Define to \TeX\ ...@>=
4870
#define TEMP_LEN 1000
4872
outer_char temp[TEMP_LEN], outer_op_name[100];
4880
OUT_STR("binop"); @~ break;
4883
OUT_STR("unop"); @~ break;
4886
OUT_STR("op"); @~ break;
4889
STRCPY(outer_op_name,p->op_name); @~ to_outer((ASCII *)outer_op_name);
4890
SPRINTF(TEMP_LEN,temp,`"{%s}{%s}{%s} ",outer_op_name,lang_codes[k],q->defn`);
4896
@ Limbo text material is collected from all \.{@@l}~commands, then output
4897
verbatim here, at the beginning of phase two. We begin by writing out any
4898
default material from the style file entry \.{limbo}.
4899
@<Output any limbo text...@>=
4901
text_pointer t = tok_start + 1;
4903
/* Default material. */
4904
if(*w_style.misc.limbo_begin)
4906
flush_buffer(out_ptr, NO);
4907
OUT_STR("% --- Limbo text from style-file parameter `limbo.begin' ---");
4909
OUT_STR(w_style.misc.limbo_begin);
4910
flush_buffer(out_ptr, NO);
4913
/* If there were any \.{@@l}~commands, they were stored in phase~1; output
4917
flush_buffer(out_ptr, NO);
4918
OUT_STR("% --- Limbo text from @@l ---"); // Header line.
4923
for(; t<text_ptr; t++)
4925
out_del_tokens(*t, *(t+1));
4926
flush_buffer(out_ptr, NO);
4929
@<Initialize |tok_ptr|...@>@;
4933
@<Output the end of limbo...@>=
4935
if(*w_style.misc.limbo_end)
4937
flush_buffer(out_ptr, NO);
4938
OUT_STR("% --- Limbo text from style-file parameter `limbo.end' ---");
4940
OUT_STR(w_style.misc.limbo_end);
4941
flush_buffer(out_ptr, NO);
4952
flush_buffer(out_ptr, NO);
4954
for(d=dots + PREDEFINED_DOTS; d->code; d++)
4955
if(d->code == dot_const)
4956
fprintf(tex_file,"\\newdot{%s}{} ",d->symbol);
4958
if(d-dots > PREDEFINED_DOTS + 1) flush_buffer(out_ptr, NO);
4961
@ A fragment that toggles the output switch. This is used in conjunction
4962
with the \.{@@i}~command, which is translated into a |toggle_output|.
4966
EXTERN boolean strt_off SET(NO), ending_off SET(NO);
4971
static int outer_include_depth;
4977
flush_buffer(out_ptr, NO);
4979
outer_include_depth = incl_depth;
4982
else if(incl_depth <= outer_include_depth)
4988
@ While appending code text, store the state of the output.
4990
@<Store the output switch@>=
4992
if(output_on) app(Turn_output_on);
4995
app(force); /* If we don't do this, output is turned off before the
4996
contents of the last line are printed. */
4997
app(turn_output_off);
5000
app_scrap(ignore_scrap,no_math);
5003
@ While appending code text, store the state of the output.
5005
@<Store output switch and \.{\\Wskipped}@>=
5007
if(output_on) app(Turn_output_on);
5011
app(Turn_output_off);
5014
app_scrap(ignore_scrap,no_math);
5017
@ The |copy_TeX| routine processes the \TeX\ code at the beginning of a
5018
module; for example, the words you are now reading were copied in this way.
5019
It returns the next control code or~`\v' found in the input. Lines that
5020
consist of all spaces are made empty; spaces between the beginning of a
5021
line and an \.{@@}~command are stripped away. (Unlike the original design,
5022
we leave tab marks in, since some users use those as active characters.)
5023
This makes the test for empty lines in |fin_line| work.
5029
ASCII c; // Current character being copied.
5035
@<Delete run of spaces between beginning of line and
5036
present position@>@;
5040
return new_module; // End of file.
5046
while ((c=*(loc++))!=@'|' && c!=@'@@')
5048
if(c==interior_semi)
5050
out(c); // Copy \TeX\ verbatim to output.
5053
if (out_ptr==out_buf+1 && (c==@' '
5060
return @'|'; // Beginning of code mode.
5063
{ /* Found an \.{@@}. */
5073
@<Delete run of spaces...@>@;
5077
if( (cc = ccode[*(loc++)]) != big_line_break)
5083
@<Process possible pre...@>; // An `\.{@@\#\dots}' command.
5084
return cc; // A |big_line_break| command.
5088
DUMMY_RETURN(ignore);
5091
@ If there are only spaces between the beginning of the output buffer and
5092
the present position |out_ptr|, delete those spaces.
5093
@<Delete run of spaces...@>=
5097
for(b=out_buf+1; b<=out_ptr; b++)
5105
@ A flag lets us know when we're processing a comment.
5108
EXTERN boolean in_comment;
5110
@ The |copy_comment| function issues a warning if more braces are opened
5111
than closed, and in the case of a more serious error it supplies enough
5112
braces to keep \TeX\ from complaining about unbalanced braces. (Because of
5113
a bug inherited from \CWEB, this doesn't work right if there is a
5114
construction such as~`\.{\\\{}' in the comment.) Instead of copying the
5115
\TeX\ material into the output buffer, this function copies it into the
5116
token memory. The abbreviation |app_tok(t)| is used to append token~|t| to
5117
the current token list, and it also makes sure that it is possible to
5118
append at least one further token without overflow.
5120
@d app_tok(c) {if (tok_ptr+2>tok_m_end)
5121
OVERFLW("tokens",ABBREV(max_toks_w));
5127
copy_comment FCN((bal)) /* copies \TeX\ code in comments */
5128
int bal C1("Brace balance.")@;
5130
ASCII c; //* Current character being copied.
5132
token_pointer tok_ptr0 = tok_ptr;
5136
terminator[0] = *limit; @~ terminator[1] = *(limit+1);
5138
*limit = @' '; /* Space to implement continued line. Short commands will
5139
be ended by this space. */
5141
/* Especially when it comes to stars and asterisks, we need to know when
5142
we're copying \TeX. Since this is actually going into token memory instead
5143
of being transcribed directly to the output, we append the |copy_mode| flag
5144
to help us know where we are. For this to work properly, one must return
5145
only from the bottom of this function, because we append another
5146
|copy_mode| at the bottom. */
5153
@<Continue comment if necessary@>@;
5155
// Get the next character. Convert a run of tabs into one tab.
5160
while(c == tab_mark);
5162
if (c==@'|') break; // Found beginning of code mode.
5164
if (c==@'*' && *loc==@'/' && long_comment)
5166
loc++; // Position after `\.{\starslash}'.
5168
@<Finish comment and |break|@>;
5171
/* It looks better in the \.{tex} file if tabs are replaced by spaces.
5172
Presumably this won't harm anything else. */
5174
@<Append comment text@>@;
5176
@<Copy special things when |c=='@@', '\\', '{', '}'|@>;
5180
app_tok(copy_mode); // Negate the copying mode.
5182
*limit = terminator[0]; @~ *(limit+1) = terminator[1];
5184
if(!long_comment && *limit == @'@@' && loc > limit)
5192
@<Continue comment if nec...@>=
5194
if(!(long_comment || language==TEX))
5195
{ // End of short comment.
5196
if((auto_semi && !free_Fortran) && *(tok_ptr-2) == @';'
5197
&& *(tok_ptr-1) == @' ')
5200
/* Strip trailing spaces. */
5201
while(*(tok_ptr-1) == @' ')
5204
/* If the last space happened to be escaped, kill the escape. */
5205
if(*(tok_ptr-1) == @'\\' && *(tok_ptr-2) != @'\\')
5208
/* Kill the trailing end-of-comment. */
5209
if(*(tok_ptr-2)==@'*' && *(tok_ptr-1)==@'/')
5212
@<Finish comment and |break|@>@;
5218
ERR_PRINT(W,"Input ended in mid-comment");
5219
@.Input ended in mid-comment@>
5220
loc=cur_buffer+1; @<Clear |bal| and |break|@>;
5223
/* For \TeX, we concatenate adjacent lines that all begin with comment
5227
if(loc==limit) @<Finish comment...@>@;
5229
for(;loc <= limit; loc++)
5230
if(*loc!=@' ' && *loc!=tab_mark) break;
5232
if(loc > limit) continue;
5234
if(TeX[*loc] == TeX_comment) loc++;
5236
{ // Unskip the white space.
5238
@<Finish comment...@>@;
5243
@ During phase~2, we must actually append the text character by character.
5244
That's essentially straightforward, but a few replacements are made.
5246
@<Append comment text@>=
5269
/* Basically, we just append the present character here. However, compiler
5270
directives need to be escaped. */
5274
@<Special string cases@>:
5282
@ This fragment finishes off a comment, ensuring that braces are properly
5284
@<Finish comment...@>=
5290
if(language==TEX) @<Check for a null \TeX\ comment@>@;
5298
ERR_PRINT(W,"Braces don't balance in comment");
5299
@.Braces don't balance in comment@>
5300
@<Clear |bal| and |break|@>;
5304
@<Check for a null ...@>=
5308
for(t=tok_ptr-1; t>tok_ptr0; t--)
5309
if(*t != @' ') break;
5311
if(t == tok_ptr0 && *(t-4)==@'\\' && *(t-3)==@'W' && *(t-2)==@'C' &&
5313
*(tok_ptr0-2) = @'x'; // Change \.{\\WC} to \.{\\Wx}.
5318
@<Copy special things when |c=='@@'...@>=
5322
if (*(loc++)!=@'@@')
5324
ERR_PRINT(W,"Illegal use of @@ in comment");
5325
@.Illegal use of \AT!...@>
5334
else if (c==@'\\' && *loc!=@'@@' && phase==2)
5341
@ When the comment has terminated abruptly due to an error, we output
5342
enough right braces to keep \TeX\ happy.
5346
app_tok(@' '); /* this is done in case the previous character was~`\.\\' */
5348
while (bal-- >0) app_tok(@'}');
5353
@i scraps.hweb /* Declarations related to the scraps and productions. */
5358
ALLOC(scrap,scrp_info,ABBREV(max_scraps),max_scraps,0);
5359
scrp_end=scrp_info+max_scraps -1; /* end of |scrp_info| */
5364
scrp_base=scrp_info+1;
5366
mx_scr_ptr=scrp_ptr=scrp_info;
5368
@* INITIALIZING the SCRAPS. If we are going to use the powerful production
5369
mechanism just developed, we must get the scraps set up in the first place,
5370
given a \cee\ text. A table of the initial scraps corresponding to \cee\
5371
tokens appeared above in the section on parsing; our goal now is to
5372
implement that table. We shall do this by implementing a subroutine called
5373
|C_parse| that is analogous to the |C_xref| routine used during phase one.
5375
Like |C_xref|, the |C_parse| procedure starts with the current value of
5376
|next_control| and it uses the operation |next_control=get_next()| repeatedly
5377
to read \cee\ text until encountering the next~`\v' or comment, or until
5378
|next_control>=formatt|. The scraps corresponding to what it reads are
5379
appended into the |cat| and |trans| arrays, and |scrp_ptr| is advanced.
5383
EXTERN boolean scanning_meta SET(NO);
5389
C_parse FCN((mode0)) /* Creates scraps from \cee\ tokens */
5390
PARSING_MODE mode0 C1("")@;
5392
name_pointer p; // Identifier designator.
5393
LANGUAGE language0 = language; // Save the incoming language.
5394
PARSE_PARAMS parse_params0;
5396
parse_params0 = parse_params; // Save parsing state.
5398
parsing_mode = mode0;
5401
if(parsing_mode == INNER)
5402
{ // Start fresh for parsing interior code.
5407
while (next_control<formatt)
5409
if(nuweb_mode && parsing_mode == INNER)
5410
@<Append a verbatim scrap@>@;
5413
@<Append the scrap appropriate to |next_control|@>;
5414
next_control = get_next();
5417
if (next_control==@'|' || next_control==begin_comment)
5421
if(next_control == begin_language && !ok_to_define
5422
&& parsing_mode == OUTER)
5426
/* If the language has changed, append stuff to restore it. */
5427
if(language != language0)
5429
app_tok(begin_language);
5430
app(lan_num(language0));
5431
app_scrap(ignore_scrap,no_math);
5434
if(parsing_mode == INNER)
5435
parse_params = parse_params0; // Restore incoming values.
5438
@ This fragment is a simple kludge; it doesn't handle various cases
5439
gracefully, such as `\.{||}'.
5441
@<Append a verbatim s...@>=
5445
if(tok_ptr == tok_m_end)
5446
OVERFLW("tokens", ABBREV(max_toks_w));
5452
next_control = *loc++;
5458
else if(!get_line())
5460
ERR_PRINT(W, "Missing '|'. File ended while appending a \
5462
next_control = @'|';
5466
app(@' '); // Instead of newline.
5469
if(scrp_ptr == scrp_end)
5470
OVERFLW("scraps", ABBREV(max_scraps));
5472
app_scrap(ignore_scrap, no_math);
5475
@ The following macro is used to append a scrap whose tokens have just
5476
been appended. Note that mathness is stored in the form $4(\hbox{\it right
5477
boundary}) + \hbox{\it left boundary}$. Thus, noting that $5b = 4b + b$,
5478
we see that the construction~$5b$ makes the left- and right-hand boundaries
5482
(++scrp_ptr)->cat = (eight_bits)(c);
5483
scrp_ptr->trans = text_ptr;
5484
scrp_ptr->mathness = (eight_bits)(5*(b)); /* Make left and right
5485
boundaries equal. */
5491
set_language FCN((language0))
5492
LANGUAGE language0 C1("")@;
5494
char language_line[50];
5496
language = language0;
5498
app_tok(begin_language);
5499
app(lan_num(language));
5501
if(parsing_mode == OUTER)
5503
sprintf(language_line,"\\LANGUAGE{%s}",
5504
(char *)LANGUAGE_CODE(language));
5505
APP_STR(language_line);
5509
app_scrap(language_scrap,no_math);
5512
@ Operator overloading.
5515
EXTERN boolean overloaded[NUM_LANGUAGES];
5517
EXTERN BUF_SIZE op_entries; /* Length for dynamic array. */
5518
EXTERN OPERATOR HUGE *op, HUGE *op_end; /* Dynamic array of entries for
5519
operator overloading. */
5520
EXTERN OPERATOR HUGE *op_ptr; /* Next open position in |OP|. */
5522
@ Initializing operators is conveniently handled by macros.
5524
/* Initialize an ordinary operator such as~`\.+'. */
5525
@d INIT_OP(op_code,op_name,lang,op_macro,cat)
5526
init_op((eight_bits)(op_code),OC(op_name),(int)(lang),OC(op_macro),
5527
NO,cat,(CONST outer_char *)NULL)
5529
/* Initialize a compound assignment operator such as~`\.{+=}'. */
5530
@d INIT_CA(ca_index,op_name,lang,op_macro,cat)
5531
assignment_token = ca_index;
5532
INIT_OP(compound_assignment,OC(op_name),(int)(lang),OC(op_macro),cat)@;
5534
/* Initialize a dot operator such as~`\.{.NE.}'. */
5535
@d INIT_DOT(op_name,lang,op_macro,cat)
5536
init_op((eight_bits)identifier,OC(op_name),(int)(lang),OC(op_macro),
5537
NO,cat,(CONST outer_char *)NULL)
5539
@d ONLY_C_like ((int)C | (int)C_PLUS_PLUS)
5540
@d ALL_BUT_C_like (~ONLY_C_like)
5541
@d ALL_BUT_Cpp ((int)C | ONLY_N_like | (int)LITERAL)
5543
@d ONLY_N_like ((int)FORTRAN | (int)FORTRAN_90 | (int)RATFOR | (int)(RATFOR_90))
5544
@d ALL_BUT_N_like (~ONLY_N_like)
5546
@d ALL_LANGUAGES (ONLY_C_like | ONLY_N_like | (int)LITERAL)
5553
for(l=0; l<NUM_LANGUAGES; l++)
5556
ALLOC(OPERATOR,op,ABBREV(op_entries),op_entries,0);
5557
op_end = op + op_entries;
5558
op_ptr = op + 128; /* The first 128 are for direct indexing. */
5560
@<Initialize ordinary operators@>;
5561
@<Initialize compound assignment operators@>;
5565
@<Initialize ordinary op...@>=
5567
INIT_OP(@'!',"NOT",ALL_LANGUAGES,"\\WR",unop); // `|!|'
5568
INIT_DOT("NOT",ALL_BUT_C_like,"\\WR",unop);
5571
INIT_OP(@'%',"MOD",ALL_LANGUAGES,"\\WMOD",binop); // `|%|'
5574
INIT_OP(@'&',"LAND",C,"\\amp",unorbinop); /* `|&|'. */
5575
INIT_OP(@'&',"LAND",C_PLUS_PLUS,"\\amp",reference);
5577
INIT_OP(@'&',"LAND",ALL_BUT_C_like,"\\WAND",binop); // `|@r &|'
5580
INIT_OP(@'+',"PLUS",ALL_LANGUAGES,"+",unorbinop); // `|+|'
5581
INIT_OP(@'-',"MINUS",ALL_LANGUAGES,"-",unorbinop); // `|-|'
5583
INIT_OP(@'*',"STAR",ALL_LANGUAGES,"\\ast",unorbinop); // `|*|'
5586
/* \TeX's slash is an ordinary operator, not a binary operator. Hence the
5587
need for \.{\\WSl}. But in \Fortran\ it's used in funny ways, like for |@n
5588
common| blocks, so it must be converted to a binary operator later. */
5589
INIT_OP(@'/',"SLASH",ALL_BUT_N_like,"\\WSl", binop); // `|/|'
5590
INIT_OP(@'/',"SLASH",ONLY_N_like,"/", binop); // `|/|'
5592
INIT_OP(@'<',"LT",ALL_BUT_Cpp,"<",binop); // `|<|'
5593
INIT_OP(@'<',"LT",C_PLUS_PLUS,"<",langle); // `|<|'
5594
INIT_DOT("LT",ALL_BUT_C_like,"<",binop);
5597
INIT_OP(@'=',"EQUALS",ALL_LANGUAGES,"=",binop); // `|=|'
5599
INIT_OP(@'>',"GT",ALL_BUT_Cpp,">",binop); // `|>|'
5600
INIT_OP(@'>',"GT",C_PLUS_PLUS,">",rangle); // `|>|'
5601
INIT_DOT("GT",ALL_BUT_C_like,">",binop);
5604
INIT_OP(@'?',"QUESTION",ONLY_C_like,"\\?",question); // `|?|'
5606
INIT_OP(@'^',"CARET",ALL_LANGUAGES,"\\Caret",binop); // `|x^y|'
5609
INIT_OP(@'|',"OR",ALL_LANGUAGES,"\\WOR",binop); // `$\WOR$'
5611
INIT_OP(@'~',"TILDE",ONLY_C_like,"\\TLD",unop);
5614
INIT_OP(not_eq,"NE",ALL_LANGUAGES,"\\WI",binop); /* `|!=|' */
5615
INIT_DOT("NE",ALL_BUT_C_like,"\\WI",binop);
5618
INIT_OP(lt_eq,"LE",ALL_LANGUAGES,"\\WL",binop); /* `|<=|' */
5619
INIT_DOT("LE",ALL_BUT_C_like,"\\WL",binop);
5622
INIT_OP(gt_eq,"GE",ALL_LANGUAGES,"\\WG",binop); /* `|>=|' */
5623
INIT_DOT("GE",ALL_BUT_C_like,"\\WG",binop);
5626
INIT_OP(eq_eq,"EQ",ALL_LANGUAGES,"\\WS",binop); /* `|==|' */
5627
INIT_DOT("EQ",ALL_BUT_C_like,"\\WS",binop);
5630
INIT_OP(and_and,"AND",ALL_LANGUAGES,"\\WW",binop); /* `|&&|' */
5631
INIT_DOT("AND",ALL_BUT_C_like,"\\WW",binop);
5634
INIT_OP(or_or,"OR",ALL_LANGUAGES,"\\WV",binop); /* `||| |' */
5635
INIT_DOT("OR",ALL_BUT_C_like,"\\WOR",binop);
5638
INIT_OP(plus_plus,"PP",ALL_LANGUAGES,"\\WPP",unop); // `|++|'
5640
INIT_OP(minus_minus,"MM",ALL_LANGUAGES,"\\WMM",unop); // `|--|'
5643
INIT_OP(minus_gt,"EQV",ONLY_C_like,"\\WMG",binop); /* `|->|' */
5645
INIT_OP(minus_gt,"EQV",ALL_BUT_C_like,"\\WEQV",binop); /* `|@r .eqv.|' */
5646
INIT_DOT("EQV",ALL_BUT_C_like,"\\WEQV",binop);
5649
INIT_OP(gt_gt, "RSHIFT",ONLY_C_like,"\\WGG",binop); // `|>>|'
5651
INIT_OP(lt_lt,"LSHIFT",ONLY_C_like,"\\WLL",binop); // `|<<|'
5653
INIT_OP(star_star,"EE",ALL_LANGUAGES,"\\WEE",exp_op); /* `\.{**}' */
5655
INIT_OP(slash_slash,"SlSl",ALL_BUT_C_like,"\\WSlSl",binop); /* `|@r \/|' */
5658
INIT_OP(ellipsis,"NEQV",ALL_BUT_C_like,"\\WNEQV",binop); // `|@r .NEQV.|'
5659
INIT_DOT("NEQV",ALL_BUT_C_like,"\\WNEQV",binop);
5660
INIT_DOT("XOR",ALL_BUT_C_like,"\\WNEQV",binop);
5661
@..NEQV.@> @..XOR.@>
5663
INIT_DOT("FALSE",ALL_BUT_C_like,"\\WFALSE",expr); // `|@r .false.|'
5665
INIT_DOT("TRUE",ALL_BUT_C_like,"\\WTRUE",expr)@; // `|@r .true.|'
5669
@<Initialize compound...@>=
5671
INIT_CA(plus_eq,"Wcp",ALL_LANGUAGES,"\\Wcp",binop); // `|+=|'
5673
INIT_CA(minus_eq,"Wcm",ALL_LANGUAGES,"\\Wcm",binop); // `|-=|'
5675
INIT_CA(star_eq,"Wcs",ALL_LANGUAGES,"\\Wcs",binop); // `|*=|'
5677
INIT_CA(slash_eq,"Wcv",ALL_LANGUAGES,"\\Wcv",binop); // `|/=|'
5679
INIT_CA(mod_eq,"Wcd",ONLY_C_like,"\\Wcd",binop); // `|%=|'
5681
INIT_CA(xor_eq,"Wcx",ONLY_C_like,"\\Wcx",binop); // `|^=|'
5683
INIT_CA(and_eq,"Wca",ONLY_C_like,"\\Wca",binop); // `|&=|'
5685
INIT_CA(or_eq,"Wco",ONLY_C_like,"\\Wco",binop); // `||=|'
5687
INIT_CA(gt_gt_eq,"Wcg",ONLY_C_like,"\\Wcg",binop); // `|>>=|'
5689
INIT_CA(lt_lt_eq,"Wcl",ONLY_C_like,"\\Wcl",binop)@; // `|<<=|'
5692
@ Initializing an operator involves several possibilities. If the
5693
operator's code is less than~128, the info is put directly into the
5694
corresponding table position. Otherwise, as for a new dot constant, we
5695
search through the positions $>= 128$ and insert it at the first available
5700
init_op FCN((op_code,op_name,lang,op_macro,overload,cat,defn))
5701
eight_bits op_code C0("The operator")@;
5702
CONST outer_char op_name[] C0("Fortran-like name of the operator")@;
5703
int lang C0("Union of all allowable languages for this def")@;
5704
CONST outer_char op_macro[] C0("Default macro expansion")@;
5705
boolean overload C0("Do we overload?")@;
5706
eight_bits cat C0("Category code")@;
5707
CONST outer_char defn[] C1("Replacement text for overloaded macro")@;
5712
/* The dot constants won't be in the table yet. Just put them there. */
5713
if(op_code == identifier) p = op_ptr++; // Next free position for a dot op.
5714
else if(!(p=valid_op(op_code)))
5716
err_print(W,"Invalid op code %d",op_code);
5720
p->op_name = GET_MEM("op name",STRLEN(op_name)+1,ASCII);
5721
STRCPY(p->op_name,op_name);
5722
to_ASCII((outer_char *)p->op_name);
5724
/* Access the languages by bit-shifting with~|l|. */
5725
for(k=0,l=1; k<NUM_LANGUAGES; k++,l<<=1)
5728
OP_INFO HUGE *q = p->info + k;
5730
q->op_macro = op_macro;
5731
overloaded[k] |= (q->overloaded = overload);
5733
if(defn) q->defn = (outer_char HUGE *)defn;
5737
@ A storage variable.
5740
EXTERN eight_bits last_control;
5742
@ Here we translate |next_control| into text characters, which are stored
5745
@<Append the scrap appropriate to |next_control|@>=
5747
room_for(6,4,4); // Is there enough room? (Check and justify these numbers!!!)
5752
switch (next_control)
5755
case macro_module_name: @<Append a module name@>@; break;
5758
case stringg: case constant: case verbatim: @<Append a string or constant@>;
5761
case begin_format_stmt: in_format = YES;
5762
case identifier: @<Append an identifier scrap@>; break;
5763
case TeX_string: @<Append a \TeX\ string scrap@>; break;
5764
case begin_language: @<Append scraps for |begin_language|@>; break;
5766
case new_output_file: @<Append the output file name@>@; break;
5770
@<Store output switch and \.{\\Wskipped}@>@;
5774
case macro_space: app(@' '); app_scrap(space,maybe_math); break;
5776
case macro_space: app_scrap(ignore_scrap, maybe_math); break;
5778
@<Cases involving single ASCII characters@>@:@;
5779
@<Cases involving nonstandard ASCII characters@>@:@;
5780
@<Cases involving special \WEB\ commands@>@:@;
5782
default: app(next_control); app_scrap(ignore_scrap, maybe_math); break;
5786
@ Check against possible overflow.
5791
room_for FCN((ntokens,ntexts,nscraps))
5792
int ntokens C0("")@;
5794
int nscraps C1("")@;
5796
if(tok_ptr+ntokens>tok_m_end)
5798
if (tok_ptr>mx_tok_ptr) mx_tok_ptr=tok_ptr;
5799
OVERFLW("tokens",ABBREV(max_toks_w));
5802
if(text_ptr+ntexts>tok_end)
5804
if (text_ptr>mx_text_ptr) mx_text_ptr=text_ptr;
5805
OVERFLW("texts",ABBREV(max_texts));
5808
if (scrp_ptr+nscraps>scrp_end)
5810
if (scrp_ptr>mx_scr_ptr) mx_scr_ptr=scrp_ptr;
5811
OVERFLW("scraps",ABBREV(max_scraps));
5815
@ Some nonstandard ASCII characters may have entered \.{WEAVE} by means of
5816
standard ones. They are converted to \TeX\ control sequences so that it is
5817
possible to keep \.{WEAVE} from stepping beyond standard ASCII.
5819
@<Cases involving nonstandard...@>=
5821
/* Overloaded operators can be defined dynamically in \FORTRAN-88. These
5822
are generically labelled by |dot_const|. The |dot_code| routine fills the
5823
structure |dot_op| with the macro name and category corresponding to the
5826
next_control = identifier;
5827
id_first = dot_op.name + 1;
5828
id_loc = id_first + STRLEN(id_first);
5832
case eq_gt: APP_STR("\\WPtr"); /* `$\WPtr$' */ app_scrap(binop,yes_math);
5837
if(C_LIKE(language))
5839
APP_STR("\\dots"); /* `|...|' */
5841
app_scrap(int_like,maybe_math);
5843
else app_overload();
5860
case compound_assignment:
5861
app_overload(); @~ break;
5863
case paste: APP_STR("\\WNN"); /* `|##|' */ app_scrap(ignore_scrap,maybe_math);
5867
case dont_expand: APP_STR("\\WNP"); /* `|#!|' */
5868
app_scrap(ignore_scrap,maybe_math);
5872
case auto_label: APP_STR("\\WNC"); /* `|#:|' */
5873
app_scrap(ignore_scrap,maybe_math);
5877
case all_variable_args:
5878
APP_STR("\\WND"); // `|#.|
5879
app_scrap(expr,maybe_math);
5884
if(C_LIKE(language))
5887
APP_STR("\\WCC"); // `|a::b|'
5888
app_scrap(unop,yes_math);
5892
APP_STR("\\WCF"); // `|@r a::b|'
5894
app_scrap(binop,yes_math);
5899
APP_STR("\\WLS"); // `|@r (/|'
5901
app_scrap(lpar,yes_math);
5905
APP_STR("\\WSR"); // `|@r /)|'
5907
app_scrap(rpar,yes_math);
5913
EXTERN boolean did_arg;
5916
@<Cases involving special...@>=
5918
case force_line: APP_STR("\\]"); app_scrap(ignore_scrap,yes_math); break;
5919
case thin_space: APP_STR("\\,"); app_scrap(ignore_scrap,yes_math); break;
5922
app(opt); @~ APP_STR("0");
5923
app_scrap(ignore_scrap,yes_math);
5927
APP_STR("\\WBK"); // Used to be |app(force)|.
5928
app_scrap(ignore_scrap,no_math);
5931
case ln_break_outdent:
5934
app(out_force); /* Makes the |indent| command come after the
5935
beginning of the line; useful for beginnings of functions. */
5938
app_scrap(ignore_scrap, no_math);
5943
if(parsing_mode==OUTER)
5944
APP_STR("\\4"); // Backspace for beauty.
5945
app_scrap(lproc, no_math);
5951
app_scrap(rproc, no_math);
5956
APP_STR("\\WTLD"); app_scrap(expr, maybe_math); break;
5959
@<Process |begin_meta|@>@;
5963
if( !nuweb_mode && ((FORTRAN_LIKE(language) && !free_form_input)
5964
|| (language==TEX)) )
5965
@<Set up column mode@>@;
5968
APP_STR(w_style.misc.meta.code.end);
5970
app_scrap(ignore_scrap,no_math);
5977
case big_line_break: app(big_force); app_scrap(ignore_scrap,no_math); break;
5978
case no_line_break: app(big_cancel); @~ APP_STR("\\ ");@~ app(big_cancel);
5979
app_scrap(ignore_scrap,no_math); break;
5981
case pseudo_expr: app_scrap(expr,maybe_math); @~ break;
5982
case pseudo_semi: app_scrap(semi,maybe_math); @~ break;
5983
case pseudo_colon: app_scrap(colon,maybe_math); @~ break;
5985
case join: APP_STR("\\WJ"); app_scrap(ignore_scrap,no_math); break;
5990
@.You can't do that...@>
5995
app_scrap(kill_newlines, yes_math);
6000
app(@'0' + upper_case_code);
6003
@<Strip white space from around RCS-like keyword@>@;
6005
app_ASCII_str(id_first);
6009
app_scrap(expr, yes_math);
6013
the_type = ORDINARY_ID;
6017
the_type = RESERVED_WD;
6021
@<Process |begin_meta|@>=
6027
APP_STR(w_style.misc.meta.code.begin);
6030
scanning_meta = YES;
6034
if(loc >= limit) // !!!!!
6044
@<Check for end of meta-comment and |goto
6045
done_meta@;| if necessary@>@;
6051
APP_STR(w_style.misc.meta.code.end);
6057
app_scrap(ignore_scrap,no_math);
6062
@<Check for end of meta-comment...@>=
6064
switch(ccode[*(loc+1)])
6071
if( !nuweb_mode && ((FORTRAN_LIKE(language) && !free_form_input)
6072
|| (language==TEX)) )
6073
@<Set up column mode@>@;
6078
case invisible_cmnt:
6079
if(*(loc+2) == @'%')
6080
eat_blank_lines = YES;
6087
eat_blank_lines = NO;
6097
goto done_meta; // !!!!!
6100
if(loc[2] == @'*' || loc[2] == @'/')
6101
{ /* Verbatim comment. */
6106
/* Falls through! */
6109
case no_line_break: case join:
6110
case pseudo_semi: case pseudo_expr: case pseudo_colon:
6111
case Compiler_Directive:
6112
case no_index: case yes_index:
6113
case begin_bp: case insert_bp:
6117
case big_line_break:
6118
break; // To handle preprocessor statements easily.
6122
goto done_meta; // !!!!!
6129
@<Cases involving single...@>=
6133
app_scrap(ignore_scrap,no_math);
6139
app_scrap(ignore_scrap, no_math);
6144
app_scrap(newline,maybe_math);
6151
app_scrap(expr,no_math); /* ``|@r format(//e10.5/f5.2)|'' */
6155
app(@'{'); @~ app(next_control); @~ app(@'}');
6156
app_scrap(slash_like,maybe_math);
6160
app_overload(); /* ``|a/b|'' */
6165
app(next_control); app_scrap(binop,yes_math); break;
6167
case @'+':/* Handle \FORTRAN's |@r +1.0|; now also ANSI~C: ``|x = +2.5;|'' */
6179
app_overload(); @~ break;
6182
lst_ampersand = YES;
6183
app_overload(); @~ break;
6203
app_scrap(expr,maybe_math);
6206
case ignore: case xref_roman: case xref_wildcard:
6207
case xref_typewriter: break;
6209
case @'(': app(next_control); app_scrap(lpar, yes_math); break; // !!!
6210
case @')': app(next_control);
6211
app_scrap(rpar, yes_math);
6212
if(preprocessing && !did_arg)
6215
app_scrap(ignore_scrap, no_math);
6220
case @'[': app(next_control); app_scrap(lbracket,yes_math); break;
6221
case @']': app(next_control); app_scrap(rbracket,yes_math); break;
6223
case @'{': APP_STR("\\{"); app_scrap(lbrace,yes_math); break;
6224
case @'}': APP_STR("\\}"); app_scrap(rbrace,yes_math); break;
6226
case @',': app(@','); app_scrap(comma,yes_math); break; // !!!
6231
app_scrap(semi,maybe_math);
6234
case end_format_stmt:
6235
in_format = NO; /* Falls through to the next case,
6236
which appends the semi. */
6241
if(!is_FORTRAN_(language) || prn_semis)
6244
app_scrap(semi,maybe_math);
6249
app_scrap(colon,maybe_math);
6256
APP_STR("\\WLQx"); app_scrap(expr,maybe_math);
6260
q_protected = BOOLEAN(!q_protected);
6261
app(q_protected ? @'{' : @'}');
6262
app_scrap(expr,yes_math);
6265
APP_STR("\\WLQx"); app_scrap(expr,maybe_math);
6269
@<Append scraps for |begin_language|@>=
6274
CONFUSION("append scraps for begin_language",
6275
"A language hasn't been defined yet");
6280
column_mode = NO; @~ break;
6286
if(mode0==OUTER && !free_form_input) @<Set up column mode@>@;
6290
if(mode0==OUTER) @<Set up col...@>@;
6295
CONFUSION("append scraps for begin_language",
6296
"Language %i is invalid", language);
6299
set_language(language);
6302
@ The following function returns a pointer to an |OPERATOR| structure, or
6303
|NULL| if there's something invalid about the operator. Identifiers must
6304
be searched for explicitly. If an identifier isn't there, it's put into
6309
valid_op FCN((op_code))
6310
eight_bits op_code C1("")@;
6346
if(p >= op + 128) CONFUSION("valid_op",
6347
"Operator 0x%x is out of range", op_code);
6350
case compound_assignment:
6351
if(assignment_token==or_or_or)
6354
p = op + CA_START + assignment_token;
6355
if(p >= op + 128) CONFUSION("valid_op",
6356
"Compound assignment operator 0x%x is out of range",
6357
op + assignment_token);
6361
if(!FORTRAN_LIKE(language)) return NULL;
6362
id_first = dot_op.name + 1;
6363
id_loc = id_first + STRLEN(id_first);
6366
if(!FORTRAN_LIKE(language)) return NULL; /* Can do names only in
6368
@<Add an operator to the table, if necessary, and |return p@;|@>@;
6375
@<Add an operator...@>=
6379
STRNCPY(id,id_first,n=PTR_DIFF(int,id_loc,id_first));
6380
id[n] = '\0'; // Make into proper string.
6382
for(p=op+128; p<op_ptr; p++)
6383
if(STRCMP(p->op_name,id) == 0) return p;
6385
if(op_ptr >= op_end) OVERFLW("op table","op");
6387
p->op_name = GET_MEM("op name",n+1,ASCII);
6388
STRCPY(p->op_name,id);
6393
@ The form in which operators are appended depends on whether they have
6394
been overloaded with an \.{@@v}~command or not. If they have not, they are
6395
are appended as a straight macro name, such as the translation of
6396
`\.{.FALSE.}' into `\.{\\WFALSE}'. If they have been overloaded, they are
6397
appended instead as a construction such as `\.{\\Wop\{FALSE\}\{N\}}';
6398
the output limbo section will then contain an automatically generated
6399
definition such as `\.{\\newop\{FALSE\}\{N\}\{\\\{.FALSE.\}\}}'. This
6400
defines the macro \.{\\\_FALSE\_N} to have the definition specified in the
6408
int ln = language_num;
6409
OPERATOR HUGE *p = valid_op(next_control);
6410
OP_INFO HUGE *q = p->info + ln;
6413
if(overload_ops && q->overloaded)
6419
APP_STR("\\Wb{"); @~ break;
6422
APP_STR("\\Wu{"); @~ break;
6425
APP_STR(" \\Wop{"); @~ break;
6428
app_ASCII_str(p->op_name);
6429
sprintf(temp,"}{%s}",lang_codes[ln]);
6432
else if(q->op_macro)
6433
APP_STR(q->op_macro);
6436
err_print(W, "Unidentifiable operator or dot constant in language \
6439
APP_STR("\\Wunknown{");
6440
app(wt_style.dot_delimiter.begin);
6441
app_ASCII_str(p->op_name);
6442
app(wt_style.dot_delimiter.end);
6444
app_scrap(binop,yes_math);
6448
app_scrap(q->cat,yes_math);
6451
@ The following code must use |app_tok| instead of |app| in order to
6452
protect against overflow. Note that |tok_ptr+1<=max_toks| after |app_tok|
6453
has been used, so another |app| is legitimate before testing again.
6455
Many of the special characters in a string must be prefixed by '\.\\' so that
6456
\TeX\ will print them properly.
6457
@^special string characters@>
6459
@<Append a string or...@>=
6461
if(next_control == stmt_label && !isDigit(*id_first))
6462
{/* Identifier as statement label. */
6463
p = id_lookup(id_first,id_loc,normal);
6464
APP_FLAG(id, p, name_dir);
6465
app_scrap(label,no_math);
6469
if (next_control==constant || next_control==stmt_label)
6472
else if (next_control==stringg)
6473
@<Append commands for beginning of string@>@;
6475
else APP_STR("\\={");
6478
@<Append the basic string@>@;
6480
if(next_control==stmt_label)
6481
{app_scrap(label,no_math);}
6483
{app_scrap(expr,yes_math);}
6487
@<Append commands for beginning of string@>=
6489
APP_STR(pfrmt->typewritr);
6493
@ Here we append the string material within [|id_first|,|id_loc|). This is
6494
basically straightforward; however, commas are replaced by~`\.{\\1}' (which
6495
will be treated as a comma followed by a discretionary break), the
6496
|discretionary_break| code is replaced by~`\.{\\2}' (which will be treated
6497
as a discretionary break), the |ordinary_space| code is replaced
6498
by~`\.{\\2}' (which is treated as an ordinary space, not~`\.{\ }'), and the
6499
|tab_mark| code (which will be present only in \TeX\ mode) is replaced
6500
by~`\.{\\3}', which is defined in \.{fwebmac.web} to be several spaces.
6502
@<Append the basic str...@>=
6505
// For toggling string state so can handle higher-order chars.
6507
while (id_first<id_loc)
6511
case @',': *id_first = @'1'; app(@'\\'); break;
6513
case ordinary_space:
6514
*id_first = @'2'; app(@'\\'); break;
6517
*id_first = @'3'; app(@'\\'); break;
6519
case discretionary_break: *id_first = @'0'; // Falls through!
6521
@<Special string cases@>:
6524
case @'@@': if (*(id_first+1)==@'@@') id_first++;
6525
else err_print(W,"Double %s@@%s should be used in strings",
6526
SSET_COLOR(character), SSET_COLOR(error));
6527
@.Double \AT! should be used...@>
6530
app_tok(*id_first++);
6533
/* End the macro. */
6535
// For toggling string state so can handle higher-order chars.
6539
@ Here are the characters that are special to \TeX\ and therefore need to
6540
be escaped within a string.
6542
@f @<Special string cases@> default
6543
@f @<Special \TeX\ cases@> default
6544
@f @<Other string cases@> default
6546
@<Special string cases@>=
6548
@<Special \TeX\ cases@>:
6549
@<Other string cases@>@: @;
6552
@<Special \TeX\ cases@>=
6554
case @'\\':case @'{': case @'}'@: @;
6557
@<Other string cases@>=
6558
case @' ':case @'#':case @'%':case @'$':case @'^':case @'`':
6559
case @'~': case @'&': case @'_'@: @;
6561
@ This fragment appends the text collected inside `\.{@@t\dots@@>}'. That
6562
text is placed inside an \.{\\hbox} and treated as an ordinary expression.
6564
@<Append a \TeX\ string scrap@>=
6566
APP_STR("\\hbox{"); while (id_first<id_loc) app_tok(*id_first++);
6567
app(@'}'); app_scrap(expr,maybe_math);
6569
@ Ordinary identifiers are just treated as expressions, unless \.{@@R} was
6570
invoked just before. The commands \.{@@R} and \.{@@E} set |the_type|.
6574
EXTERN boolean the_type SET(NO_TYPE);
6577
@<Append an identifier scrap@>=
6579
p = id_lookup(id_first, id_loc, normal);
6582
if (p->ilk==normal || !(p->reserved_word & (boolean)language) )
6584
APP_FLAG(id, p, name_dir);
6585
app_scrap(expr,maybe_math); /* not a reserved word */
6589
APP_FLAG(res, p, name_dir);
6590
app_scrap(p->ilk,maybe_math);
6596
WV_MACRO HUGE *w = p->wv_macro;
6597
ASCII HUGE *s = w->text;
6611
app_scrap(p->ilk ? p->ilk : expr, w->cat ? maybe_math : yes_math);
6613
else if ( (p->reserved_word & (boolean)language) && the_type != ORDINARY_ID
6614
|| the_type == RESERVED_WD)
6618
APP_FLAG(res, p, name_dir);
6620
the_ilk = (the_type == RESERVED_WD) ? int_like : p->ilk;
6622
app_scrap(the_ilk == normal ? expr : the_ilk,
6623
the_ilk < max_math ? yes_math : maybe_math);
6624
/* See the inverse construction in \.{reserved}:|save_words|. The last
6625
|yes_math| should only be relevant for |@c++ new, delete|. */
6631
APP_STR("\\WKINDCHAR");
6634
APP_FLAG(id, p, name_dir);
6635
app_scrap(expr, upcoming_kind ? yes_math : maybe_math);
6636
// Not a reserved word.
6645
@<Output an RCS-like keyword@>=
6647
ASCII *id_start, *id_end;
6649
@<Strip white space from around RCS-like keyword@>@;
6651
id_start = id_end = mod_text + 1;
6653
x_keyword(&id_end, mod_end, id_first, id_loc, NO, NO,
6654
upper_case_code ? WEB_FILE : CUR_FILE);
6656
out_del_str(id_start, id_end);
6662
while(IS_WHITE(*id_first))
6665
while(IS_WHITE(id_loc[-1]))
6670
@<Append the output file...@>=
6672
APP_STR(upper_case_code ? "\\WOut{" : "\\Wout{");
6674
*id_loc = '\0'; // Terminate file name.
6676
/* Store current (and possibly global) file names. (These names shouldn't
6678
was_opened(id_first, upper_case_code, ¶ms.OUTPUT_FILE_NAME, NULL);
6681
was_opened(id_first, upper_case_code,
6682
&global_params.OUTPUT_FILE_NAME, NULL);
6684
/* Now escape the buffer and append it. */
6685
id_first = esc_buf(mod_text+1, mod_end, id_first, YES);
6688
app_tok(*id_first++);
6695
app_scrap(ignore_scrap,no_math);
6699
next_control = begin_meta;
6704
@ When the~`\ttv' that introduces \cee\ text is sensed, a call on
6705
|C_translate| will return a pointer to the \TeX\ translation of that text.
6706
If scraps exist in |scrp_info|, they are unaffected by this translation
6714
text_pointer p; // Points to the translation.
6715
scrap_pointer save_base; // Holds original value of |scrp_base|.
6716
PARAMS outer_params;
6717
PARSE_PARAMS parse_params0;
6719
outer_params = params;
6720
parse_params0 = parse_params;
6722
save_base = scrp_base;
6723
scrp_base = scrp_ptr+1; // Empty work space after last existing scrap.
6725
/* We enclose code fragments with the \TeX\ macro~\.{\\WCD\{\dots\}}. */
6727
APP_STR("\\protect");
6729
APP_STR("\\WCD{"); app_scrap(ignore_scrap,no_math);
6734
app_scrap(ignore_scrap, no_math);
6737
while(next_control <= module_name)
6739
C_parse(INNER); // Get the scraps together.
6741
if(next_control == @'|')
6744
@<Emit the scrap for a module name if present@>;
6746
if(next_control == @'|')
6750
app_tok(cancel); app_scrap(ignore_scrap,maybe_math);
6751
// Place a |cancel| token as a final ``comment''.
6757
app_scrap(semi, maybe_math); /* Append a pseudo-semicolon to try to
6758
force the code fragments to reduce to full statements. */
6764
app_scrap(ignore_scrap, no_math);
6767
app(@'}'); app_scrap(ignore_scrap,no_math);
6769
if (next_control != @'|')
6770
ERR_PRINT(W, "Missing '|' after code text. \
6771
(@@ commands that begin definition part, code part, or new module are not \
6772
allowed within |...|.)");
6775
p = translate(INNER); // Make the translation.
6777
if (scrp_ptr>mx_scr_ptr)
6778
mx_scr_ptr=scrp_ptr;
6780
scrp_ptr = scrp_base-1; // Restore old |scrp_ptr|.
6781
scrp_base = save_base; // Scrap the scraps.
6783
params = outer_params;
6786
parse_params = parse_params0;
6791
@ The |outr_parse| routine is to |C_parse| as |outr_xref| is to |C_xref|:
6792
it constructs a sequence of scraps for \cee\ text until
6793
|next_control>=formatt|. Thus, it takes care of embedded comments.
6798
outr_parse(VOID) /* makes scraps from \cee\ tokens and comments */
6800
int bal; // Brace level in comment.
6801
text_pointer p, q; // Partial comments. |p|: Stuff before `\Cb'; |q|: `\Cb'.
6803
while (next_control<formatt)
6805
if (next_control != begin_comment)
6808
@<Append a comment or compiler directive@>@;
6813
@<Append a comment...@>=
6814
{ // Append a comment/compiler directive.
6816
@<Begin a compiler directive@>@;
6818
@<Append a regular comment@>@;
6820
bal = copy_comment(1); // Closing brace is inserted here.
6821
next_control = ignore;
6823
if(doing_cdir && bal > 0)
6824
ERR_PRINT(W,"Can't have vertical bars in @@! compiler directives");
6828
/* Handle code mode inside comments. */
6832
p=text_ptr; freeze_text;
6835
/* at this point we have |tok_ptr+7<=max_toks| */
6836
APP_FLAG(tok,p,tok_start); APP_FLAG(inner_tok,q,tok_start);
6838
if (next_control==@'|')
6840
bal = copy_comment(bal);
6841
next_control = ignore;
6844
bal = 0; // An error has been reported.
6847
app(force); app_scrap(ignore_scrap,no_math); /* the full comment
6851
@ Compiler directives are begun by the style-file text \.{cdir.start}. For
6852
example, `\.{@@!abc}' $\to$ `\.{\#pragma\ abc}'.
6854
@<Begin a compiler dir...@>=
6856
outer_char HUGE *s = t_style.cdir_start[language_num];
6857
int n = 2*STRLEN(s) + 1;
6858
/* The factor of~2 counts possible escapes, and the 1 takes care of |'\0'|. */
6859
ASCII HUGE *temp = GET_MEM("temp_cdir",n,ASCII);
6860
ASCII HUGE *start = GET_MEM("start_cdir",n,ASCII);
6863
to_ASCII((outer_char HUGE *)start);
6865
room_for(9+n,3,1); /* Tokens: */
6868
APP_STR("\\WCDIR{");
6869
esc_buf(temp,temp+n,start,YES); @~ APP_STR(to_outer(temp));
6871
FREE_MEM(temp,"temp_cdir",n,ASCII);
6872
FREE_MEM(start,"start_cdir",n,ASCII);
6876
@<Append a regular comment@>=
6878
room_for(8,3,1); /* Tokens: `\.{;{ }\ { }\\{ }W{ }C\{{ }\}{ }\It{force}}'. */
6882
if(free_Fortran && lst_ampersand)
6884
scrp_ptr--; // Kill off the \.{\&}.
6886
else if(!at_beginning && (auto_semi && !free_Fortran))
6890
last_was_cmnt = YES;
6894
APP_STR(long_comment ? "\\WC{" : "\\Wc{"); // Long/short comment.
6898
@* OUTPUT of TOKENS. So far our programs have only built up multi-layered
6899
token lists in \.{WEAVE}'s internal memory; we have to figure out how to
6900
get them into the desired final form. The job of converting token lists to
6901
characters in the \TeX\ output file is not difficult, although it is an
6902
implicitly recursive process. Three main considerations had to be kept in
6903
mind when this part of \.{WEAVE} was designed: (a)~There are two modes of
6904
output, |outer| mode that translates tokens like |force| into line-breaking
6905
control sequences, and |inner| mode, intended for code between~\Cb, that
6906
ignores them except that blank
6907
spaces take the place of line breaks. (b)~The |cancel| instruction applies
6908
to adjacent token or tokens that are output, and this cuts across levels of
6909
recursion since `|cancel|' occurs at the beginning or end of a token list
6910
on one level. (c)~The \TeX\ output file will be semi-readable if line
6911
breaks are inserted after the result of tokens like |break_space| and
6912
|force|. (d)~The final line break should be suppressed, and there should
6913
be no |force| token output immediately after `\.{\\WY\\WP}'.
6917
@ The output process uses a stack to keep track of what is going on at
6918
different ``levels'' as the token lists are being written out. Entries on
6919
this stack have three parts:
6921
\yskip\hang |end_field| is the |tok_mem| location where the token list of a
6922
particular level will end;
6924
\yskip\hang |tok_field| is the |tok_mem| location from which the next token
6925
on a particular level will be read;
6927
\yskip\hang |mode_field| is the current mode, either |inner| or |outer|.
6929
\yskip\noindent The current values of these quantities are referred to
6930
quite frequently, so they are stored in a separate place instead of in the
6931
|stack| array. We call the current values |cur_end|, |cur_tok|, and
6934
The global variable |stck_ptr| tells how many levels of output are
6935
currently in progress. The end of output occurs when an |end_translation|
6936
token is found, so the stack is never empty except when we first begin the
6939
@d inner 0 /* Value of |mode| for \cee\ texts within \TeX\ texts */
6940
@d outer 1 /* Value of |mode| for \cee\ texts in modules */
6947
token_pointer end_field; /* Ending location of token list */
6948
token_pointer tok_field; /* Present location within token list */
6949
boolean mode_field; /* Interpretation of control tokens */
6952
typedef output_state HUGE *stack_pointer;
6955
@d cur_end cur_state.end_field /* Current ending location in |tok_mem| */
6956
@d cur_tok cur_state.tok_field /* Location of next output token in |tok_mem| */
6957
@d cur_mode cur_state.mode_field /* Current mode of interpretation */
6958
@d ini_stack stck_ptr=stack;cur_mode=outer@; /* Initialize the stack */
6962
EXTERN output_state cur_state; /* |cur_end|, |cur_tok|, |cur_mode| */
6964
EXTERN BUF_SIZE stck_size;
6965
EXTERN output_state HUGE *stack; /* Dynamic array of info for non-current
6967
EXTERN stack_pointer stck_end; /* End of |stack| */
6969
EXTERN stack_pointer stck_ptr; /* First unused location in the output
6971
EXTERN stack_pointer mx_stck_ptr; /* Largest value assumed by |stck_ptr| */
6976
ALLOC(output_state,stack,ABBREV(stck_size_w),stck_size,0);
6977
stck_end=stack+stck_size-1; /* End of |stack| */
6984
@ To insert token-list |p| into the output, the |push_level| subroutine is
6985
called; it saves the old level of output and gets a new one going. The
6986
value of |cur_mode| is not changed.
6991
push_level FCN((p)) /* Suspends the current level */
6992
text_pointer p C1("")@;
6994
if (stck_ptr==stck_end) OVERFLW("stack levels",ABBREV(stck_size_w));
6996
if (stck_ptr>stack) { /* save current state */
6997
stck_ptr->end_field=cur_end;
6998
stck_ptr->tok_field=cur_tok;
6999
stck_ptr->mode_field=cur_mode;
7004
if (stck_ptr>mx_stck_ptr) mx_stck_ptr=stck_ptr;
7006
cur_tok=*p; cur_end=*(p+1);
7009
@ Conversely, the |pop_level| routine restores the conditions that were in
7010
force when the current level was begun. This subroutine will never be
7011
called when |stck_ptr=1|.
7018
cur_end=(--stck_ptr)->end_field;
7019
cur_tok=stck_ptr->tok_field; cur_mode=stck_ptr->mode_field;
7022
@ The |get_output| function returns the next byte of output that is not a
7023
reference to a token list. It returns the values |identifier| or |res_word|
7024
or |mod_name| if the next token is to be an identifier (typeset in
7025
italics), a reserved word (typeset in boldface) or a module name (typeset
7026
by a complex routine that might generate additional levels of output). In
7027
these cases |cur_name| points to the identifier or module name in question.
7031
EXTERN name_pointer cur_name;
7034
@d res_word OCTAL(201) /* Returned by |get_output| for reserved words */
7035
@d mod_name OCTAL(200) /* Returned by |get_output| for module names */
7039
get_output(VOID) /* Returns the next token of output */
7041
sixteen_bits a; /* Current item read from |tok_mem| */
7043
restart: while (cur_tok==cur_end) pop_level(); /* Get back to unfinished
7050
cur_name=a % id_flag + name_dir;
7052
switch (a / id_flag)
7054
case 2: return res_word; /* |a==res_flag+cur_name| */
7055
case 3: return mod_name; /* |a==mod_flag+cur_name| */
7056
case 4: push_level(a % id_flag + tok_start); goto restart;
7057
/* |a==tok_flag+cur_name| */
7058
case 5: push_level(a % id_flag + tok_start); cur_mode=inner;
7060
/* |a==inner_tok_flag+cur_name| */
7061
default: return identifier; /* |a==id_flag+cur_name| */
7065
/* If we get here, it's a single-byte token. */
7066
return (eight_bits)a;
7069
@ The real work associated with token output is done by |make_output|.
7070
This procedure appends an |end_translation| token to the current token
7071
list, and then it repeatedly calls |get_output| and feeds characters to the
7072
output buffer until reaching the |end_translation| sentinel. It is possible
7073
for |make_output| to be called recursively, since a module name may include
7074
embedded \cee\ text; however, the depth of recursion never exceeds one
7075
level, since module names cannot be inside of module names.
7077
A procedure called |output_C| does the scanning, translation, and output of
7078
\cee\ text within `\Cb'~brackets, and this procedure uses |make_output| to
7079
output the current token list. Thus, the recursive call of |make_output|
7080
actually occurs when |make_output| calls |output_C| while outputting the
7087
output_C(VOID) /* Outputs the current token list */
7089
token_pointer save_tok_ptr;
7090
text_pointer save_text_ptr;
7091
eight_bits save_next_control; /* Values to be restored */
7092
text_pointer p; /* Translation of the \cee\ text */
7094
save_tok_ptr=tok_ptr; save_text_ptr=text_ptr;
7095
save_next_control=next_control;
7097
next_control=ignore; p=C_translate();
7098
APP_FLAG(inner_tok,p,tok_start);
7101
make_output(); /* output the list */
7103
if (text_ptr>mx_text_ptr) mx_text_ptr=text_ptr;
7104
if (tok_ptr>mx_tok_ptr) mx_tok_ptr=tok_ptr;
7106
text_ptr=save_text_ptr; tok_ptr=save_tok_ptr; /* Forget the tokens */
7107
next_control=save_next_control; /* Restore |next_control| to original
7111
@ Here is \.{WEAVE}'s major output handler.
7116
make_output(VOID) /* outputs the equivalents of tokens */
7118
eight_bits a; // Current output byte.
7119
eight_bits b; // Next output byte.
7120
int c; // Count of |indent| and |outdent| tokens.
7121
boolean copying = NO; // Are we copying the \TeX\ part of a comment?
7123
app(end_translation); // Append a sentinel.
7124
freeze_text; push_level(text_ptr-1);
7132
case ignore: continue; // In case a null sneaks in.
7135
while((a=get_output()) != verbatim)
7139
case begin_language:
7140
language = lan_enum(get_output()); /* The byte after
7141
|begin_language| contains the language number. */
7144
@<Cases for turning output on or off@>@:@;
7149
case end_translation:
7152
case identifier: case res_word:
7154
@<Output an identifier@>@;
7159
@<Output a module name@>@; @~ break;
7161
case math_bin: case math_rel:
7162
@<Output a \.{\\math} operator@>; @~ break;
7165
scanning_meta = BOOLEAN(!scanning_meta);
7169
c=0; while ((a=get_output())>=indent && a<=big_force)
7171
if (a==indent) c++; if (a==outdent) c--;
7173
@<Output saved |indent| or |outdent| tokens@>;
7178
while (((a=get_output())>=indent || a==@' ') && a<=big_force)
7180
if (a==indent) c++; if (a==outdent) c--;
7182
@<Output saved...@>;
7185
case indent: case outdent: case opt: case backup: case break_space:
7186
case force: case big_force:
7188
look ahead in case of line breaks, possibly |goto reswitch@;|@>; break;
7191
if(output_on) out(';');
7195
if(!(copying || nuweb_mode))
7197
OUT_STR("\\ast "); // Special macro for asterisks in code mode.
7201
/* If |copying|, the asterisk case falls through to the default. */
7206
out(a); // Otherwise |a| is an |ASCII| character.
7208
if(scanning_meta && a=='\n')
7209
flush_buffer(out_ptr, NO);
7216
@<Output contents of a string@>=
7221
@<Cases for turning output on...@>=
7224
output_protect = BOOLEAN(!output_protect); @~ break;
7227
copying = BOOLEAN(!copying); @~ break;
7229
case turn_output_off:
7230
@% OUT_STR("OFF"); // For debugging.
7234
case turn_output_on:
7235
@% OUT_STR("ON"); // For debugging.
7239
case Turn_output_off:
7242
@% OUT_STR("OFF"); // For debugging.
7246
case Turn_output_on:
7248
@% OUT_STR("ON"); // For debugging.
7258
#define TEMP_LEN (MAX_FILE_NAME_LENGTH + 11)
7260
outer_char temp[TEMP_LEN], temp1[TEMP_LEN];
7262
esc_file_name(temp1, TEMP_LEN, prms[1].web.File_name);
7263
SPRINTF(TEMP_LEN, temp, `"\\Wskipped{%s}", temp1`);
7280
OUT_STR("\\WY\\WP");
7288
@<Output an identifier@>=
7294
for(k=cur_name->byte_start; k<(cur_name+1)->byte_start; k++)
7300
@<Format and output an identifier@>@;
7304
@ An identifier of length one does not have to be enclosed in braces, and
7305
it looks slightly better if set in a math-italic font instead of a
7306
(slightly narrower) text-italic font. Thus we output `\.{\\\char'174a}' but
7309
@d ALL_UC (all_uc && length(cur_name) > 1)
7312
@<Format and output an id...@>=
7314
boolean all_uc = cur_name->info.upper_case;
7317
OUT_STR("\\protect");
7321
if(is_intrinsic(cur_name))
7322
OUT_STR(pfrmt->intrinsic);
7323
/* Intrinsic function---e.g., |fopen|. */
7325
else if(is_keyword(cur_name))
7326
OUT_STR(ALL_UC ? pfrmt->KEYWORD : pfrmt->keyword);
7327
/* Fortran keyword---e.g., |@r BLOCKSIZE|. */
7329
else if (length(cur_name)==1)
7330
OUT_STR(pfrmt->short_id);
7331
/* One-character identifier---e.g., |a|. */
7334
@<Output the appropriate identifier prefix@>@;
7337
OUT_STR(ALL_UC ? pfrmt->RESERVED : pfrmt->reserved);
7338
/* Reserved word---e.g., |float|. */
7341
out_name(NULL, YES, IDENTIFIER, cur_name);
7344
@ Some people prefer macros to be formatted differently from ordinary
7346
@<Output the appro...@>=
7347
switch(DEFINED_TYPE(cur_name))
7350
OUT_STR(ALL_UC ? pfrmt->ID_OUTER : pfrmt->id_outer);
7351
// E.g., |NON_TEX_MACRO|.
7355
OUT_STR(ALL_UC ? pfrmt->ID_INNER : pfrmt->id_inner); // E.g., |_FWEAVE_|.
7359
OUT_STR(ALL_UC ? pfrmt->ID: pfrmt->id);
7360
// Longer ordinary identifier---e.g., |out|.
7365
@ Here |a|~will only be |math_bin| or |math_rel|.
7368
OUT_STR(a==math_bin ? "\\mathbin{" : "\\mathrel{");
7372
@ The current mode does not affect the behavior of \.{WEAVE}'s output routine
7373
except when we are outputting control tokens.
7375
@<Output a control...@>=
7378
{ /* $a \in \{|indent|, |outdent|, |opt|, or |backup|\}$. */
7379
if (cur_mode==outer)
7383
out(@'\\'); @~ out(a-cancel+@'0'); /* As an example,
7384
$|backup| = |0345| - |0341| + \.{'0'} = \.{'4'} \to \.{\\4}$. */
7391
} // |opt| is followed by a digit.
7397
b = get_output(); // Ignore digit following |opt|.
7400
@<Look ahead for strongest line break, |goto reswitch@;|@>;
7401
/* Here $a \in \{|break_space|,|force|,|big_force|\}$. */
7403
@ If several of the tokens |break_space|, |force|, |big_force| occur in a
7404
row, possibly mixed with blank spaces (which are ignored), the largest one
7405
is used. A line break also occurs in the output file, except at the very
7406
end of the translation. The very first line break is suppressed (i.e., a
7407
line break that follows `\.{\\WY\\WP}').
7409
@<Look ahead for st...@>=
7411
boolean save_mode; /* value of |cur_mode| before a sequence of breaks */
7413
b=a; save_mode=cur_mode; c=0;
7419
if (a==cancel || a==big_cancel)
7421
@<Output saved |indent| or |outdent| tokens@>;
7422
goto reswitch; // |cancel| overrides everything.
7425
if ((a!=@' ' && a<indent) || a==backup || a > big_force)
7426
@<Output something; |goto reswitch|@>@;
7429
c++; // Count the |indent|'s.
7430
else if (a==outdent)
7431
c--; // Count the |outdent|'s.
7433
{ /* Use only the largest line-break command.. */
7435
b = a; // if |a==' '| we have |a < b|.
7437
get_output(); // Throw away digit after |opt|.
7443
@<Output something...@>=
7445
if (save_mode==outer)
7447
if (out_ptr>out_buf+5 && STRNCMP(out_ptr-5,"\\WY\\WP",6)==0)
7450
@<Output saved |indent| or |outdent| tokens@>;
7455
if(STRNCMP(out_ptr-2,"\\WP",3)==0)
7463
out(@'\\'); @~ out(b-cancel+@'0');
7465
if (a != end_translation)
7466
fin_line(); // Line break in the physical file for beauty.
7468
else if (a != end_translation && cur_mode==inner)
7471
// In inner code mode, line breaks are replaced by spaces.
7476
@ While we're removing unwanted or duplicate tokens, we don't want to lose
7477
track of the indent level. So we count the |indent|s and |outdent|s, and
7478
write out the net here.
7480
@<Output saved...@>=
7482
for (;c>0;c--) OUT_STR("\\1");
7484
for (;c<0;c++) OUT_STR("\\2");
7486
@ The remaining part of |make_output| is somewhat more complicated. When we
7487
output a module name, we may need to enter the parsing and translation
7488
routines, since the name may contain code embedded in \Cb\~constructions.
7489
This code is placed at the end of the active input buffer and the
7490
translation process uses the end of the active |tok_mem| area.
7492
@<Output a module name@>=
7496
@<Code to output a module name@>@;
7507
@<Code to output a module name@>@;
7512
@<Code to output a module name@>=
7514
name_pointer cur_mod_name; /* name of module being output */
7518
cur_xref = (xref_pointer)cur_name->xref;
7520
/* Output the module number, or zero if it was undefined */
7521
if (cur_xref->num>=def_flag)
7523
out_mod(cur_xref->num-def_flag,ENCAP);
7527
cur_xref=cur_xref->xlink;
7529
while (cur_xref->num>=def_flag)
7532
out_mod(cur_xref->num-def_flag,ENCAP);
7533
cur_xref=cur_xref->xlink;
7539
out(@'}'); /* End the module number. */
7540
@<Output the text of the module name@>;
7541
OUT_STR("\\X "); /* End the text. (Can't use a colon here, because
7542
there may be colons in the text.) */
7543
OUT_STR(cur_xref->num >= def_flag ?
7544
LANGUAGE_SYMBOL((LANGUAGE)cur_mod_name->mod_info->language) :
7545
(CONST outer_char *)"");
7546
OUT_STR("\\X"); /* End the language marker. */
7549
@ In most situations, we only want to output a language marker if we're in
7550
a language different from the global language.
7552
@d XLANGUAGE_NAME_PTR(l) Xlanguages[lan_num(l)]
7553
// Points to the full language name, in the form of \TeX\ macros.
7555
@d LANGUAGE_SYMBOL(l)
7556
(l!=global_language ? LANGUAGE_CODE(l) : (CONST outer_char *)"")
7559
@<Output the text...@>=
7561
ASCII HUGE *k, HUGE *k_limit; /* indices into |byte_mem| */
7562
ASCII HUGE *j; /* index into |cur_buffer| */
7563
ASCII HUGE *save_loc, HUGE *save_limit; // |loc| and |limit| to be restored.
7566
k=cur_name->byte_start; k_limit=(cur_name+1)->byte_start;
7567
cur_mod_name=cur_name;
7573
if (b==@'@@') @<Skip next character, give error if not `\.{@@}'@>;
7575
if (b!=@'|') out(b)@;
7578
@<Copy the \cee\ text into the |cur_buffer| array@>;
7579
save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1;
7580
*limit=@'|'; output_C();
7581
loc=save_loc; limit=save_limit;
7587
@<Skip next char...@>=
7592
printf("\n! Illegal control code in section name: <");
7593
@.Illegal control code...@>
7594
prn_id(cur_mod_name); printf("> ");
7598
@ The \cee\ text enclosed in~\Cb\ should not contain `\vertbar'~characters,
7599
except within strings. We put a~`\vertbar' at the front of the buffer, so
7600
that an error message that displays the whole buffer will look a little bit
7601
sensible. The variable |delim| is zero outside of strings, otherwise it
7602
equals the delimiter that began the string being copied.
7604
@<Copy the \cee\ text into...@>=
7606
ASCII delim; /* first and last character of string being copied */
7608
j=limit+1; *j=@'|'; delim=0;
7615
printf("\n! C text in section name didn't end: <");
7616
@.C text...didn't end@>
7617
prn_id(cur_mod_name); printf("> ");
7625
@<Copy a control code into the buffer@>@;
7628
if (b==@'\'' || b==@'"')
7629
if (delim==0) delim=b;
7630
else if ((eight_bits)delim == b) delim=0;
7632
if (b!=@'|' || delim!=0)
7634
if (j>cur_buffer+buf_size-2) OVERFLW("buffer","");
7644
@<Copy a control code into the buffer@>=
7646
if (j>cur_buffer+buf_size-3) OVERFLW("buffer","");
7648
*(++j)=@'@@'; *(++j)=*(k++);
7651
@* PHASE TWO PROCESSING. We have assembled enough pieces of the puzzle in
7652
order to be ready to specify the processing in \.{WEAVE}'s main pass over
7653
the source file. Phase two is analogous to phase one, except that more work
7654
is involved because we must actually output the \TeX\ material instead of
7655
merely looking at the \.{WEB} specifications.
7662
extern outer_char wbflnm0[];
7663
IN_COMMON int num_ifiles;
7665
phase = 2; // Prepare for second phase.
7668
params = global_params;
7672
strt_off = ending_off = NO;
7673
writing(YES,tex_fname); @~ if(tex_file==stdout) putchar('\n');
7675
fin_line(); // Write out the ``\.{\\input\ fwebmac.sty}''.
7677
@<Issue the \.{\\Wbegin} command that sets up the beginning of the document@>@;
7683
flush_buffer(out_buf, NO); /* Insert a blank line---it looks nice. */
7687
while (!input_has_ended)
7688
@<Translate the current module@>@;
7691
@ After the macros have been read in, we are ready to
7692
actually begin the document. The command has the form
7693
``\.{\\Wbegin[\It{options}]\{\It{style}\}\{\It{TeXindent}\}\{\It{codeindent}\}
7695
\{\{\It{reserved}\}\{\It{short identifier}\}\{\It{identifier}\}
7696
\{\It{UPPERCASE identifier}\}
7697
\{\It{outer macro}\}\{\It{inner macro}\}
7698
\{\It{intrinsic}\}\{\It{keyword}\}\{\It{typewriter}\}\{\It{modtrans}\}\}}.''
7699
The \It{options} and \It{style} field are used only by \LaTeX.
7701
@m OUT_PRM(fmt, n, cmt, ...) out_prm(OC(fmt), n, OC(cmt), #.)
7703
@<Issue the \.{\\Wbegin} command...@>=
7705
IN_COMMON outer_char style_file_name[];
7707
OUT_STR("\n% --- Initialization parameters from FWEB's style file `");
7708
OUT_STR(style_file_name);
7712
OUT_PRM("\\Wbegin[%s;%s]", 1, "[LaTeX.class.options;LaTeX.package.options]",
7713
w_style.misc.LaTeX.class.options, w_style.misc.LaTeX.package.options);
7715
OUT_PRM("{%s;%s}", 2, "{LaTeX.class;LaTeX.package}",
7716
w_style.misc.LaTeX.class.file, w_style.misc.LaTeX.package.file);
7718
OUT_PRM("{%s}", 3, "{indent.TeX}",
7719
w_style.misc.TeXindent);
7721
OUT_PRM("{%s}", 4, "{indent.code}",
7722
w_style.misc.codeindent);
7724
OUT_PRM("{%s}", 5, "{contents.TeX}",
7725
w_style.contents.tex);
7727
OUT_PRM("{ %% ##6 ---\n {%s%s}", 1, "{{format.reserved}{format.RESERVED}}",
7728
pfrmt->reserved, pfrmt->RESERVED);
7730
OUT_PRM(" {%s}", 2, "{format.short_id}",
7733
OUT_PRM(" {%s%s}", 3, "{{format.id}{format.ID}}",
7734
pfrmt->id, pfrmt->ID);
7736
OUT_PRM(" {%s%s}", 4, "{{format.outer_macro}{format.OUTER_MACRO}}",
7737
pfrmt->id_outer, pfrmt->ID_OUTER);
7739
OUT_PRM(" {%s%s}", 5, "{{format.WEB_macro}{format.WEB_MACRO}}",
7740
pfrmt->id_inner, pfrmt->ID_INNER);
7742
OUT_PRM(" {%s}", 6, "{format.intrinsic}",
7745
OUT_PRM(" {%s%s}", 7, "{{format.keyword}{format.KEYWORD}}",
7746
pfrmt->keyword, pfrmt->KEYWORD);
7748
OUT_PRM(" {%s}", 8, "{format.typewriter}",
7751
OUT_PRM(" {}", 9, "(For future use)");
7753
OUT_PRM("}\n{%s}", 7, "{encap.prefix}",
7754
w_style.indx.encap_prefix);
7756
OUT_PRM("{%s;%s}", 8, "{doc.preamble;doc.postamble}",
7757
w_style.misc.doc_preamble, w_style.misc.doc_postamble);
7759
OUT_PRM("{%s}", 9, "{index.name}",
7760
prn_index ? w_style.indx.name : OC("NoIndex"));
7769
out_prm FCN(VA_ALIST((fmt, n, cmt VA_ARGS)))
7771
CONST outer_char *fmt C0("")@;
7772
int n C0("Arg number")@;
7773
CONST outer_char *cmt C2("")@;)@;
7775
#define TEMP_LEN (MAX_FILE_NAME_LENGTH + 100)
7778
outer_char temp0[TEMP_LEN];
7779
outer_char HUGE *temp1 = GET_MEM("temp1", TEMP_LEN, outer_char);
7781
#if(NUM_VA_ARGS == 1)
7782
CONST outer_char *fmt;
7783
CONST outer_char *cmt;
7786
VA_START(arg_ptr, cmt);
7788
#if(NUM_VA_ARGS == 1)
7789
fmt = va_arg(arg_ptr, outer_char *);
7790
cmt = va_arg(arg_ptr, outer_char *);
7797
vsprintf((char *)temp0, (CONST char *)fmt, arg_ptr);
7800
num_char = (int)STRLEN(temp0);
7803
if(num_char >= TEMP_LEN)
7804
OVERFLW("out_prm:temp0", "");
7806
OUT_STR(xpn_name(&temp1, TEMP_LEN, temp0, wbflnm0));
7809
sprintf((char *)temp1, " %% #%i --- ", n);
7810
OUT_STR(temp1); OUT_STR(cmt);
7813
FREE_MEM(temp1, "temp1", TEMP_LEN, outer_char);
7818
@ The output file will contain the control sequence~\.{\\WY} between
7819
non-null sections of a module, e.g., between the \TeX\ and definition parts
7820
if both are nonempty. This puts a little white space between the parts when
7821
they are printed. However, we don't want \.{\\WY} to occur between two
7822
definitions within a single module. The variables |out_line| or |out_ptr|
7823
will change if a section is non-null, so the following macros
7824
`|save_position|' and `|emit_space_if_needed|' are able to handle the
7827
@d save_position save_line=out_line; save_place=out_ptr@;
7828
@d emit_space_if_needed if (save_line!=out_line || save_place!=out_ptr)
7837
EXTERN LINE_NUMBER save_line; // Former value of |out_line|.
7838
EXTERN ASCII HUGE *save_place; // Former value of |out_ptr|.
7839
EXTERN boolean in_module SET(NO); // Between \.{\\WN} and \.{\\fi}?
7840
EXTERN boolean yskipped SET(NO); // Did we skip between parts?
7843
@<Translate the current module@>=
7847
/* Again, all modules start off in the global language. */
7848
params = global_params;
7850
scanning_meta = NO; // For safety.
7854
@<Output the code for the beginning of a new module@>;
7857
the_type = NO_TYPE; // For use with \.{@@R} and \.{@@E}.
7865
@<Show cross-references to this module@>;
7866
@<Output the code for the end of a module@>;
7869
@ Modules beginning with the \.{WEB} control sequence~`\.{@@\ }' start in the
7870
output with the \TeX\ control sequence~`\.{\\WM}', followed by the module
7871
number. Similarly, `\.{@@*}'~modules lead to the control sequence~`\.{\\WN}'.
7872
If this is a changed module, we put~\.{*} just before the module number.
7874
@<Output the code for the beginning...@>=
7876
@<Output the include file name if necessary@>;
7878
if(!in_module && output_on)
7880
OUT_STR(*(loc-1) == @'*' ? "\\WN" : "\\WM");
7885
out_mod(module_count,NO_ENCAP); OUT_STR(". ");
7888
progress(); // Progress report to terminal.
7891
@ These variables remember the last and current name of the include file.
7894
IN_COMMON outer_char last_include_file[], this_include_file[];
7897
@<Output the include file name...@>=
7899
if(STRCMP(last_include_file,this_include_file) != 0)
7901
STRCPY(last_include_file,this_include_file);
7902
OUT_STR("\\WIF{"); @~ out_fname(this_include_file); @~
7907
@ In the \TeX\ part of a module, we simply copy the source text, except that
7908
index entries are not copied and \cee\ text within \Cb\ is translated.
7916
parsing_mode = OUTER;
7920
next_control = copy_TeX();
7922
switch(next_control)
7924
@<Cases to set |language| and |break|@>@:@;
7930
case @'|': ini_stack; output_C(); break;
7933
out(@'|'); // Literal vertical bar.
7937
out(@'@@'); // Literal '\.{@@}'.
7940
case invisible_cmnt: loc = limit + 1; break;
7943
OUT_STR(w_style.misc.meta.TeX.begin);
7947
OUT_STR(w_style.misc.meta.TeX.end);
7951
case xref_roman: case xref_wildcard: case xref_typewriter:
7952
case macro_module_name: case module_name:
7953
loc-=2; next_control=get_next(); /* skip to \.{@@>} */
7955
if (next_control==TeX_string)
7956
ERR_PRINT(W,"@@t (TeX string) should be in code text only");
7957
@.TeX string should be...@>
7962
loc-=2; next_control=get_next(); /* skip to \.{@@>} */
7963
@<Output an RCS-like keyword@>@;
7967
case line_break: case ln_break_outdent:
7968
case big_line_break: case no_line_break: case join:
7969
case pseudo_semi: case pseudo_expr: case pseudo_colon:
7970
case Compiler_Directive:
7972
case begin_bp: case insert_bp:
7974
@.You can't do that...@>
7979
ERR_PRINT(W, "@@p should be immediately followed by '|'");
7981
output_protect = YES;
7984
case USED_BY_NEITHER:
7985
err_print(W, "Invalid `@@%c' ignored", XCHR(*(loc-1)));
7989
while (next_control<formatt);
7991
output_protect = NO;
7994
@ We need a flag to suppress phase~2 declarations of stuff recognized
7995
during macro definitions. Some other flags are useful too.
7998
EXTERN boolean ok_to_define SET(YES);
7999
EXTERN boolean q_protected SET(NO); // For protecting with quotes.
8000
EXTERN boolean suppress_defn SET(NO); // For masking out formats, etc.
8001
EXTERN boolean output_protect SET(NO); // For writing \.{\\protect}.
8003
@ When we get to the following code we have |next_control>=formatt|, and
8004
the token memory is in its initial empty state.
8006
@d SUPPRESS(name) if(!defn_mask.name) suppress_defn = YES@;
8013
boolean overload_ops0 = overload_ops;
8015
the_part = DEFINITION;
8016
parsing_mode = OUTER;
8018
if (next_control<begin_code)
8019
{ /* definition part non-empty */
8020
emit_space_if_needed; save_position;
8021
@<Store the output switch@>@;
8022
@% @<Append \.{\\WP}@>@;
8025
while (next_control<begin_code)
8026
@<Translate a |definition|, |formatt|, etc.@>@;
8029
@ Now deal with a |formatt|, |definition|, |undefinition|, |WEB_definition|,
8030
|limbo_text|, |op_def|, |macro_def|, or \.{@@\#...} command.
8032
@<Translate a |definition|...@>=
8034
eight_bits last_control = next_control;
8035
boolean nuweb_mode0;
8039
switch(next_control)
8042
case invisible_cmnt:
8046
@<Store the output switch@>@;
8050
nuweb_mode0 = nuweb_mode;
8053
switch(next_control)
8056
@<Start a format definition@>@;
8060
@<Start a limbo text definition@>@;
8064
@<Start an overloaded operator definition@>@;
8068
@<Start an overloaded identifier definition@>@;
8075
case invisible_cmnt:
8076
loc = limit + 1; // Skip the line.
8077
/* Skip any other extraneous material that doesn't belong in the definition
8079
while((next_control=get_next()) < formatt
8080
&& next_control!=begin_comment);
8084
@<Start a macro definition@>@;
8089
nuweb_mode = nuweb_mode0;
8091
outr_parse(); // Scan the definition or whatever.
8093
if(auto_app_semi && last_control==WEB_definition)
8094
{app_scrap(semi,maybe_math);}
8096
overload_ops = overload_ops0;
8097
fin_C(); // Finish up the definition or whatever.
8101
@ The switch into code mode is appended rather than just written directly
8102
out in order to deal with the |output_on| status properly.
8103
@<Append \.{\\WP}@>=
8109
@ The |fin_C| procedure outputs the translation of the current scraps,
8110
preceded by the control sequence~`\.{\\WP}' and followed by the control
8111
sequence~`\.{\\par}'. It also restores the token and scrap memories to
8112
their initial empty state.
8114
A |force| token is appended to the current scraps before translation takes
8115
place, so that the translation will normally end with~\.{\\6} or~\.{\\7}
8116
(the \TeX\ macros for |force| and |big_force|). This~\.{\\6} or~\.{\\7} is
8117
replaced by the concluding \.{\\par} or by \.{\\WY\\par}.
8122
fin_C(VOID) // Finishes a definition or a \cee\ part.
8124
text_pointer p; // Translation of the scraps.
8125
boolean current_output_state = output_on;
8132
app_tok(force); // Last thing in the translation.
8133
app_scrap(ignore_scrap,no_math);
8134
// The last stuff doesn't count for syntax.
8136
/* We've accumulated all the stuff for one part. Translate it, then print
8138
p = translate(OUTER);
8140
APP_FLAG(tok,p,tok_start);
8141
make_output(); // Output the list.
8143
if (out_ptr>out_buf+1)
8144
@<Tidy up the end of the part@>@;
8146
OUT_STR(the_part == CODE ? "\\Wendc" : "\\Wendd");
8150
/* Accumulate statistics. */
8151
if (text_ptr>mx_text_ptr)
8152
mx_text_ptr=text_ptr;
8153
if (tok_ptr>mx_tok_ptr)
8155
if (scrp_ptr>mx_scr_ptr)
8156
mx_scr_ptr=scrp_ptr;
8161
/* Forget the tokens and the scraps. */
8162
tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrp_ptr=scrp_info;
8165
if(strt_off) output_on = strt_off = ending_off = NO;
8168
strt_off = ending_off = NO;
8173
output_on = current_output_state;
8179
if (*(out_ptr-1)==@'\\')
8185
out_ptr -= 2; // Throw away the \.{\\6}.
8186
else if (*out_ptr==@'7')
8188
out_ptr -= 2; // Throw away the \.{\\7}\dots
8190
// and replace it with \.{\\WY}.
8195
@ Here is a nucleus that writes out the appropriate macro for the
8196
preprocessor command.
8198
@d APP_TEMP(letter,arg) app_temp(OC(letter),OC(arg))
8203
app_temp FCN((letter,arg))
8204
CONST outer_char letter[] C0("")@;
8205
CONST outer_char arg[] C1("")@;
8209
sprintf(temp,"\\W%s{%s}", (char *)letter, (char *)arg);
8213
@ This nucleus appends stuff for the preprocessor commands, macro
8214
definitions, formats, etc.
8219
app_proc FCN((next_control))
8220
eight_bits next_control C1("")@;
8222
if(the_part == DEFINITION)
8224
@<Append \.{\\WP}@>@;
8228
@<Append the scrap header for the definition part@>@;
8233
switch(next_control)
8235
case WEB_definition: // ``\.{@@m}''
8236
APP_STR(upper_case_code ? "\\WMD" : "\\WMd"); @~ break;
8238
case undefinition: // ``\.{@@u}''
8239
APP_LANG("Ud"); @~ break;
8241
case definition: // ``\.{@@d}''
8242
APP_LANG(upper_case_code ? "D" : "d"); @~ break;
8244
case formatt: // ``\.{@@f}''
8245
APP_LANG(upper_case_code ? "F" : "f"); @~ break;
8247
case limbo_text: // ``\.{@@l}''
8248
APP_LANG("l"); @~ break;
8250
case op_def: // ``\.{@@v}''
8251
APP_LANG("v"); @~ break;
8253
case macro_def: // `\.{@@w}'.
8254
APP_LANG(upper_case_code ? "WW" : "w"); @~ break;
8257
APP_TEMP("E","ifdef"); @~ break;
8260
APP_TEMP("E","ifndef"); @~ break;
8263
APP_TEMP("E","line"); @~ break;
8266
APP_TEMP("E","undef"); @~ break;
8269
APP_TEMP("E","if"); @~ break;
8272
APP_TEMP("E","elif"); @~ break;
8275
APP_TEMP("E","else");
8276
app_scrap(ignore_scrap,no_math);
8280
APP_TEMP("E","for"); @~ break;
8283
APP_TEMP("E","endfor");
8284
app_scrap(ignore_scrap,no_math);
8288
APP_TEMP("E","endif");
8289
app_scrap(ignore_scrap,no_math);
8297
@ The following helps with error processing.
8299
@d IMPROPER(m_type, msg) improper(OC(m_type), OC(msg))
8303
improper FCN((m_type, msg))
8304
outer_char *m_type C0("")@;
8305
outer_char *msg C1("")@;
8307
err_print(W, "Improper %s definition: expected %s", m_type, msg);
8310
@ This function helps keep the code short.
8312
@d APP_LANG(suffix) app_lang(OC(suffix))
8317
app_lang FCN((suffix))
8318
CONST outer_char *suffix C1("")@;
8320
APP_TEMP(suffix,(CONST outer_char *)(LANGUAGE_SYMBOL(language)));
8323
@ Macro definitions have the syntax `\.{@@m\ A\ b}' or `\.{@@m\ A(x)\ y}'.
8324
Keeping in line with the conventions of the C and~\.{WEB} preprocessors
8325
(and otherwise contrary to the rules of \.{WEB}) we distinguish here
8326
between the case that `\.('~immediately follows an identifier and the case
8327
that the two are separated by a space. In the latter case, and if the
8328
identifier is not followed by~`\.(' at all, the replacement text starts
8329
immediately after the identifier. In the former case, it starts after we
8330
scan the matching~`\.)'.
8332
@<Start a macro...@>=
8334
LANGUAGE saved_language = language;
8336
if(next_control == definition)
8337
SUPPRESS(outer_macros);
8339
if(next_control == WEB_definition)
8342
app_proc(next_control); // Macro command for \.{@@m}.
8347
if( ((C_LIKE(language) || language==LITERAL) &&
8348
next_control<=WEB_definition) ||
8349
next_control==WEB_definition ||
8350
next_control==m_ifdef ||
8351
next_control==m_ifndef || next_control==m_undef)
8353
next_control = get_next();
8355
if( !(next_control == identifier || next_control == AUTO_INSERT
8356
|| next_control == MAKE_RECURSIVE
8357
|| next_control == PROTECTED) )
8359
IMPROPER("macro", "'[', '*', '!', or identifier");
8360
@.Improper macro definition@>
8364
if(next_control == MAKE_RECURSIVE || next_control == PROTECTED)
8366
app(next_control); // Second argument to \.{\\WMd}.
8367
next_control = get_next();
8371
APP_STR("{}"); // Empty argument to \.{\\WMd}.
8373
if(next_control == @'[')
8374
@<Format auto insertion@>@;
8377
if(next_control != identifier)
8378
IMPROPER("macro", "identifier");
8383
/* Note use of |*loc| here rather than |next_control| to check for space. */
8385
@<Append argument of \WEB\ macro@>@;
8387
{ /* Id not followed by parenthesis. */
8388
next_control = get_next();
8392
app_scrap(ignore_scrap,no_math); /* scrap won't take part in
8398
next_control = get_next();
8400
if(saved_language == TEX)
8401
language = saved_language;
8405
@<Format auto insert...@>=
8408
get_string(@'[','\0');
8410
app_ASCII_str(id_first);
8411
next_control = get_next();
8414
@ The parenthesized macro argument will be put into math mode, because we
8417
@<Append argument of \WEB\ macro@>=
8419
app(@'$'); // Begin math mode for parenthesized argument.
8421
#ifdef DBGM // For debugging macros; define from gcc command line.
8426
next_control = get_next();
8429
switch(next_control)
8433
next_control = get_next();
8435
if(next_control == @')')
8437
APP_STR("\\;"); // Extra space for beauty.
8444
app(next_control); goto reswitch;
8453
if( (next_control=get_next()) != @')')
8455
ERR_PRINT(M,"Improper macro \
8456
definition: expected ')' after ellipsis");
8462
app(next_control); // |app(@'~');|
8463
next_control=get_next(); break;
8466
ERR_PRINT(M,"Improper macro definition: \
8467
unrecognized token in argument list");
8475
app(@'$'); // End math mode for parenthesized argument.
8478
@ Here we append a format command, which has the two possible forms
8479
``\.{@@f\ a\ b}'' or ``\.{@@f\ `\{\ 11}''.
8481
@<Start a format...@>=
8483
LANGUAGE saved_language = language;
8484
scrap_pointer scrp_ptr0;
8495
/* Mark formats that are not in the global language. */
8496
app_proc(next_control); // |formatt|.
8497
scrp_ptr0 = scrp_ptr; // Save to help check valid format.
8498
app_scrap(expr,maybe_math); /* this will produce `\&{format}'. The
8499
macro inserts a blank after \&{format}. */
8503
language = C; // This kludge ought to be removed!
8505
next_control=get_next(); /* First field: identifier, module name, or~'\.`'. */
8507
if (next_control==identifier || next_control==module_name)
8508
@<Format an identifier or module name@>@;
8509
else if(next_control==@'`')
8510
@<Format a category code@>@;
8512
if (scrp_ptr!=scrp_ptr0+3)
8513
ERR_PRINT(W,"Improper format definition");
8514
@.Improper format definition@>
8516
/* The following doesn't work right if the format command is immediately
8517
followed by a language-changing command. */
8518
if(saved_language == TEX)
8519
language = saved_language;
8523
@<Format an identifier or mod...@>=
8525
if(next_control==identifier)
8528
APP_FLAG(mod,cur_module,name_dir);
8532
next_control=get_next(); /* Second field: identifier. */
8534
if (next_control==identifier)
8537
@<Finish appending format definition@>@;
8542
@<Finish appending format...@>=
8544
app_scrap(expr,maybe_math);
8545
app_scrap(semi,maybe_math); // Pseudo-semi.
8547
sharp_include_line = NO;
8549
next_control=get_next();
8552
@ Here we typeset a format command that changes a category code, such as
8553
``\.{@@f\ `a\ 10}''.
8555
@<Format a cat...@>=
8557
@<Append commands for beginning of string@>@;
8559
if( (next_control = get_TeX()) == constant)
8560
APP_STR((outer_char *)id_first);
8565
next_control = get_next(); // Integer category code.
8567
if(next_control == constant)
8571
while(id_first < id_loc)
8572
app_tok(*id_first++);
8576
@<Finish appending format...@>@;
8580
@ Here we append a limbo text definition of the form ``\.{@@l\ "text"}''.
8582
@<Start a limbo...@>=
8586
app_proc(next_control);
8587
app_scrap(expr,maybe_math);
8589
/* First field: String. */
8590
if((next_control = get_next()) != stringg)
8591
ERR_PRINT(W,"A string must follow @@l");
8594
@ Here we append an operator-overload command, of the form ``\.{@@v\ .IN.\
8597
@<Start an overloaded op...@>=
8603
app_proc(next_control);
8604
app_scrap(expr,maybe_math);
8606
/* First field: The operator to be overloaded. */
8607
if(valid_op(next_control = get_next()))
8609
@<Append an operator name@>@;
8611
app(@' '); @~ app_scrap(expr,no_math);
8613
/* Second field: Replacement text. */
8614
if((next_control = get_next()) == stringg)
8616
@<Append commands for beginning of string@>@;
8617
@<Append the basic str...@>@;
8618
app_scrap(expr,yes_math);
8620
/* Third field: Cat of this operator. */
8621
if(valid_op(next_control=get_next()))
8623
app(@' '); @~ app_scrap(expr,no_math);
8625
@<Append an operator...@>@;
8627
next_control = get_next();
8633
@ The last field of an \.{@@v}~command can be either an operator like~`\.+'
8634
or an identifier like~`\.{.IN.}'.
8636
@<Append an operator...@>=
8638
switch(next_control)
8641
ERR_PRINT(W,"For future compatibility, please use syntax .NAME. for \
8642
overloading dot operators");
8648
@<Append commands for beginning of string@>@;
8649
app(wt_style.dot_delimiter.begin);
8650
app_ASCII_str(dot_op.name + 1);
8651
app(wt_style.dot_delimiter.end);
8662
app_scrap(expr,yes_math);
8666
@<Start an overloaded id...@>=
8670
app_proc(next_control);
8671
app_scrap(expr,maybe_math);
8673
/* First field: The identifier to be overloaded. */
8674
if((next_control = get_next()) == identifier)
8676
ASCII HUGE *id_first0, HUGE *id_loc0;
8678
/* Remember first identifier. */
8679
id_first0 = id_first;
8684
app(@' '); @~ app_scrap(expr,no_math);
8686
/* Second field: Replacement text. */
8687
switch(next_control = get_next())
8690
if((next_control=get_next()) != identifier) break;
8694
id_first = id_first0;
8698
@<Append commands for beginning of string@>@;
8700
*id_loc = '\0'; // Make name into string.
8701
app_ASCII_str(id_first);
8703
app_scrap(expr,yes_math);
8704
next_control = get_next();
8708
@<Append commands for beginning of string@>@;
8709
@<Append the basic str...@>@;
8710
app_scrap(expr,yes_math);
8711
next_control = get_next();
8717
@ Finally, when the \TeX\ and definition parts have been treated, we have
8718
|next_control>=begin_code|. We will make the global variable |this_module|
8719
point to the current module name, if it has a name; otherwise, it will be
8720
equal to |name_dir|.
8724
EXTERN name_pointer this_module; // The current module name, or zero.
8725
EXTERN name_pointer the_module; /* The module we're working on; equal to
8726
|cur_module| at the beginning of the entire module. */
8735
this_module = name_dir;
8736
parsing_mode = OUTER;
8738
if (next_control<=module_name)
8740
@% emit_space_if_needed;
8743
@<Store the output switch@>@;
8744
@<Append \.{\\WP}@>@;
8746
if (next_control==begin_code)
8747
{ /* We've hit an \.{@@a}. */
8748
boolean nuweb_mode0 = nuweb_mode;
8750
unnamed_section = YES;
8751
params = global_params;// Unnamed module is in global language.
8752
nuweb_mode = nuweb_mode0;
8755
@<Maybe start column mode.@>@;
8757
@<Append the scrap header for code@>@; // !!!!!
8760
{ /* Named module. */
8761
unnamed_section = NO;
8763
if(cur_module != NULL)
8765
params = cur_module->mod_info->params;
8766
// Restore state for this module.
8768
this_module = cur_module;
8770
the_module = cur_module;
8771
@<Check that |=| or |==| follows this module name, and
8772
emit the scraps to start the module definition@>;
8775
/* Now scan the whole module. */
8776
while (next_control<=module_name)
8779
@<Emit the scrap for a module name if present@>;
8782
@<Reset the language before translation@>@;
8784
unnamed_section = NO;
8789
@<Append the scrap header for the definition part@>=
8795
@<Append the scrap header for code@>=
8800
@ The scrap header needs the file name as argument to \.{\\Wunnamed}; it
8801
must be escaped. We use the |mod_text| buffer as a scratch area.
8806
app_hdr FCN((section_part))
8807
CONST char *section_part C1("Either \"code\" or \"defs\"")@;
8809
outer_char temp[1000], *temp_end = temp + 1000, *t_first, *t_loc;
8812
STRCPY(t_first, params.OUT_FILE_NAME);
8814
t_first = esc_buf((ASCII HUGE *)t_first+STRLEN(t_first)+1,
8815
(ASCII HUGE *)temp_end, (CONST ASCII HUGE *)t_first, YES);
8816
to_outer((ASCII HUGE *)t_first);
8817
t_loc = t_first + STRLEN(t_first) + 1;
8818
sprintf((char *)t_loc, " \\Wunnamed{%s}{%s}%%\n",
8819
section_part, (char *)t_first);
8821
app_scrap(ignore_scrap,no_math);
8825
@<Check that |=|...@>=
8827
LANGUAGE saved_language = language;
8832
/* Allow optional `\.{+=}'. */
8834
next_control=get_next();
8835
while (next_control==@'+');
8837
language = saved_language;
8839
switch(next_control)
8841
case compound_assignment:
8842
if(assignment_token != plus_eq)
8844
ERR_PRINT(W,"Invalid compound assignment after section \
8845
name; please use one of `=', `==', or `+='");
8846
@.Invalid compound assignment...@>
8850
/* The |plus_eq| falls through to the next case. */
8854
@<Maybe start column mode.@>@; // Positioned after `\.{@@<\dots@@>=}'.
8858
ERR_PRINT(W,"You need an = sign after the section name");
8859
@.You need an = sign...@>
8864
if (out_ptr>out_buf+2 && STRNCMP(out_ptr-2,"\\WY",3)==0)
8867
app(backup); /* The module name will be flush left */
8872
APP_FLAG(mod,this_module,name_dir);
8873
cur_xref = (xref_pointer)this_module->xref;
8876
if(cur_xref->num != module_count+def_flag)
8878
APP_STR("\\WPQ"); // Module name is multiply defined,
8880
this_module=name_dir; // so we won't give cross-reference info here.
8883
APP_STR("\\WSQ"); // Output the equivalence sign~`$\equiv$'.
8887
app_misc(w_style.misc.named_preamble); // Optional stuff from style file.
8888
app(force); // This forces a line break unless `\.{@@~}' follows.
8889
app_scrap(ignore_scrap,no_math);
8892
@ Because the language may have changed in the middle of a module, we must
8893
reset it before we perform the translation of the scraps that have just
8896
@<Reset the language...@>=
8898
boolean nuweb_mode0 = nuweb_mode;
8900
params = (the_module == NULL ? global_params : the_module->mod_info->params);
8901
nuweb_mode = nuweb_mode0;
8905
@ When we append miscellaneous stuff from the style file, we must be a bit
8906
clever. If the stuff contains something like~`\.{\\7}' and we just
8907
appended it raw, it wouldn't be subject to the later output mechanism that
8908
takes the maximum of adjacent |force| and |big_force| tokens. Thus, we
8909
will translate the macros~`\.{\\1}' to~`\.{\\8}' into their internal tokens
8910
before appending them. Other text in the miscellaneous string is just left
8917
outer_char *s C1("")@;
8924
if(isdigit(*s) && *s != '0' && *s != '8' && *s != '9')
8926
*(s-1) = '\0'; // Terminate for |app_str|.
8931
case '1': app(indent); @~ break;
8932
case '2': app(outdent); @~ break;
8933
case '3': app(opt); @~ break;
8934
case '4': app(backup); @~ break;
8935
case '5': app(break_space); @~ break;
8936
case '6': app(force); @~ break;
8937
case '7': app(big_force); @~ break;
8939
*(s-1) = '\\'; // Put it back for the next time.
8940
s0 = ++s; // Skip the digit.
8948
@<Maybe start column mode.@>=
8950
if(!nuweb_mode && ((FORTRAN_LIKE(language) && !free_form_input)
8951
|| (language==TEX)) )
8953
@<Set up column mode@>@;
8954
next_control = ignore;
8958
@<Kill rest of line; no |auto_semi|@>@;
8959
next_control = (nuweb_mode ? begin_meta : get_next()); // !!!!!
8964
@<Kill rest of line; no...@>=
8966
if(Fortran88 && (auto_semi && !free_Fortran))
8973
@ When shifting into \FORTRAN\ mode, we skip any stuff on the same line as
8974
the~\.{@@n}, because surely that text isn't in the appropriate columns.
8977
loc = limit + 1; // Skip rest of line.
8983
@<Emit the scrap...@>=
8985
if (next_control<module_name)
8987
switch(next_control)
8989
case m_if: case m_ifdef: case m_ifndef:
8990
case m_undef: case m_else:
8991
case m_elif: case m_endif:
8992
case m_for: case m_endfor:
8994
case WEB_definition:
8995
pre_scrap(next_control);
9000
@.You can't do that...@>
9003
next_control=get_next();
9005
else if (next_control==module_name)
9007
@<Append a module name@>@;
9008
next_control = (nuweb_mode ? begin_meta : get_next()); // !!!!!
9011
@ Tack on the representation of a module name.
9012
@<Append a mod...@>=
9016
APP_FLAG(mod, cur_module, name_dir);
9019
app_scrap(cur_module != NULL ? cur_module->mod_ilk : expr,maybe_math);
9022
@ Build a preprocessor scrap.
9026
pre_scrap FCN((last_control))
9027
eight_bits last_control C1("")@;
9029
scrap_pointer save_base;
9031
LANGUAGE saved_language = language;
9034
app_proc(last_control);
9036
switch(last_control)
9038
case WEB_definition:
9039
@<Start a deferred macro definition@>;
9043
p = text_ptr; freeze_text;
9045
save_base = scrp_base;
9046
scrp_base = scrp_ptr + 1;
9048
*limit = @'@@'; @~ *(limit+1) = @'m'; /* Stop the |outr_parse|. */
9049
next_control = ignore;
9051
if(language==TEX) language = C;
9053
language = saved_language;
9055
if(last_control==WEB_definition) {app_scrap(semi,maybe_math);}
9057
q = translate(OUTER);
9058
scrp_ptr = scrp_base - 1;
9059
scrp_base = save_base;
9061
APP_FLAG(tok,p,tok_start);
9062
APP_FLAG(tok,q,tok_start);
9063
APP_STR("\\WPs"); app(force); // Terminate preprocessor command.
9064
app_scrap(ignore_scrap,no_math);
9068
@<Start a deferred macro...@>=
9070
if( (next_control=get_next())!=identifier)
9071
ERR_PRINT(M,"Improper deferred macro definition: \
9072
expected identifier");
9073
@.Improper macro definition@>
9080
reswitch: switch (next_control=get_next())
9082
case @'(': case @',':
9083
app(next_control); goto reswitch;
9089
if( (next_control=get_next()) != @')')
9091
ERR_PRINT(M,"Improper deferred macro \
9092
definition: expected ')' after ellipsis");
9095
case @')': app(next_control); app(@' ');
9097
default: ERR_PRINT(M,"Improper deferred macro definition: \
9098
unrecognized token within argument list"); break;
9102
app(@'$'); app(break_space);
9103
app_scrap(ignore_scrap,no_math); /* scrap won't take part
9108
@ Cross references relating to a named module are given after the module ends.
9112
if (this_module>name_dir && output_on)
9114
@<Rearrange the list pointed to by |cur_xref|@>;
9115
footnote(def_flag); footnote(0);
9118
@ To rearrange the order of the linked list of cross-references, we need
9119
four more variables that point to cross-reference entries. We'll end up
9120
with a list pointed to by |cur_xref|.
9124
EXTERN xref_pointer next_xref, this_xref, first_xref, mid_xref;
9125
/* Pointer variables for rearranging a list */
9127
@ We want to rearrange the cross-reference list so that all the entries
9128
with |def_flag| come first, in ascending order; then come all the other
9129
entries, in ascending order. There may be no entries in either one or both
9130
of these categories.
9132
@<Rearrange the list...@>=
9134
first_xref = (xref_pointer)this_module->xref;
9135
this_xref=first_xref->xlink; /* Bypass current module number */
9137
if (this_xref->num>def_flag)
9139
mid_xref=this_xref; cur_xref=0; /* This value doesn't matter */
9143
next_xref=this_xref->xlink; this_xref->xlink=cur_xref;
9144
cur_xref=this_xref; this_xref=next_xref;
9146
while (this_xref->num>def_flag);
9148
first_xref->xlink=cur_xref;
9150
else mid_xref=xmem; /* First list null */
9154
while (this_xref!=xmem)
9156
next_xref=this_xref->xlink; this_xref->xlink=cur_xref;
9157
cur_xref=this_xref; this_xref=next_xref;
9160
if (mid_xref>xmem) mid_xref->xlink=cur_xref;
9161
else first_xref->xlink=cur_xref;
9163
cur_xref=first_xref->xlink;
9165
@ The |footnote| procedure gives cross-reference information about multiply
9166
defined module names (if the |flag| parameter is |def_flag|), or about the
9167
uses of a module name (if the |flag| parameter is zero). It assumes that
9168
|cur_xref| points to the first cross-reference entry of interest, and it
9169
leaves |cur_xref| pointing to the first element not printed. Typical
9170
outputs: `\.{\\WA\ section 101.}'; `\.{\\WU\ sections 370 and 1009.}';
9171
`\.{\\WA\ sections 8, 27\\*, and 64.}'.
9176
footnote FCN((flag)) /* Outputs module cross-references */
9177
sixteen_bits flag C1("")@;
9179
xref_pointer q; /* Cross-reference pointer variable */
9181
if (cur_xref->num<=flag) return;
9183
fin_line(); OUT_STR("\\W");
9187
out( flag==0 ? @'U' : @'A');
9189
OUT_STR(" section"); // English!
9190
@<Output all the module numbers on the reference list |cur_xref|@>;
9195
@ The following code distinguishes three cases, according as the number of
9196
cross-references is one, two, or more than two. Variable~|q| points to the
9197
first cross-reference, and the last link is a zero.
9199
@<Output all the module numbers...@>=
9201
q=cur_xref; if (q->xlink->num>flag) out(@'s'); // Pluralize. English!
9206
out_mod(cur_xref->num-flag,ENCAP);
9207
cur_xref=cur_xref->xlink; /* Point to the next cross-reference to output */
9209
if (cur_xref->num<=flag) break;
9211
if (cur_xref->xlink->num>flag || cur_xref!=q->xlink) out(@',');
9212
/* Not the last of two */
9216
if (cur_xref->xlink->num<=flag)
9217
OUT_STR("and~"); /* The last. English! */
9221
@<Output the code for the end of a module@>=
9223
if(in_module && output_on)
9225
outer_char temp[500];
9227
SPRINTF(500, temp, `"\\fi %% End of %s", MOD_TRANS(module_count)`);
9229
OUT_STR(temp); @~ fin_line();
9234
flush_buffer(out_buf, NO); // Insert a blank line for beauty.
9238
@* PHASE THREE PROCESSING. We are nearly finished! \.{WEAVE}'s only
9239
remaining task is to write out the index and module list, after sorting the
9240
identifiers and index entries. The index and module list are written into
9241
separate files, by default \.{INDEX.tex} and \.{MODULES.tex}.
9243
If the user has set the |no_xref| flag (the \.{-x} option on the command
9244
line), just finish off the page, omitting the index, module name list, and
9245
table of contents. (Fix this up.)
9247
@d NEW_TeX(file_name)
9248
if(tex_file != stdout)
9251
if((tex_file=FOPEN(file_name,"w"))==NULL)
9254
"Can't open output file %s.",
9263
language = global_language;
9265
if (no_xref && !prn_contents)
9268
@<Finish off |phase3|@>@;
9271
{ // Print cross-reference information.
9272
temp_ndx = GET_MEM("temp_ndx",MAX_FILE_NAME_LENGTH,outer_char);
9273
temp_mds = GET_MEM("temp_mds",MAX_FILE_NAME_LENGTH,outer_char);
9276
nuweb_mode = NO; // Force full output of identifiers.
9280
OUT_STR("\\input ");
9281
OUT_STR(xpn_name(&temp_ndx,MAX_FILE_NAME_LENGTH,
9282
w_style.indx.tex,wbflnm0));
9288
OUT_STR("\\input ");
9289
OUT_STR(xpn_name(&temp_mds,MAX_FILE_NAME_LENGTH,
9290
w_style.modules.tex,wbflnm0));
9295
@<Print the command line, etc.@>@;
9301
outer_char temp[20];
9303
OUT_STR(w_style.contents.preamble);
9305
SPRINTF(20, temp, `"{%i}", module_count`);
9308
OUT_STR(w_style.contents.postamble);
9311
OUT_STR("\\FWEBend"); @~ fin_line();
9314
@<Finish off |phase3|@>@;
9317
@<Output the index@>@;
9320
@<Output all the module names@>@;
9323
if(tex_file != stdout)
9324
fclose(tex_file); // |tex_file| is actually the last open file.
9326
CLR_PRINTF(SHORT_INFO, info, ("\nDone."));
9327
chk_complete(); // Was all of the change file used?
9331
@<Finish off |phase3|@>=
9333
OUT_STR("\\vfill"); @~ fin_line();
9334
OUT_STR("\\FWEBend"); @~ fin_line();
9341
@<Print the command line...@>=
9343
outer_char HUGE *temp;
9346
temp = GET_MEM("temp",N_CMD,outer_char);
9348
OUT_STR(w_style.modules.info);
9349
OUT_STR(cmd_ln_buf); @~ fin_line();
9351
/* Print a message identifying the global language. */
9352
SPRINTF(N_CMD,temp,`" {%s}", XLANGUAGE_NAME_PTR(global_language)`);
9353
OUT_STR(temp); @~ fin_line();
9355
@<Print the RCS keywords@>@;
9357
FREE_MEM(temp,"temp",N_CMD,outer_char);
9360
@ The values of any RCS keywords encountered during the
9361
\.{\AT!z}--\.{\AT!x} scan are printed at the end of the run.
9363
@<Print the RCS...@>=
9366
// Dynamic array of RCS-like keywords.
9367
IN_COMMON unsigned num_keywords;
9369
RCS HUGE *rcs_ptrs[1000]; // Kludge; to be upgraded.
9371
/* Construct an array of pointers to the |RCS| entries. */
9372
for(prcs=prms[WEB_FILE].rcs_list.start, num_keywords=0; prcs;
9373
prcs=prcs->next, num_keywords++)
9374
rcs_ptrs[num_keywords] = prcs;
9376
QSORT(rcs_ptrs, num_keywords, sizeof(RCS *), cmpr_rcs);
9380
if(num_keywords > 0)
9382
out_str(w_style.modules.kwd);
9387
for(k=0; k<num_keywords; k++)
9388
{ /* Construct format of form \.{\\Wkwd\{kwd\}\{txt\}}. */
9391
out_str(w_style.modules.kwd); // (No escapes)
9393
out_atext(prcs->keyword); // (Escaped)
9396
out_atext(prcs->txt); // (Escaped)
9402
@ Here's the comparison routine for use with |qsort|ing the RCS keywords.
9407
cmpr_rcs FCN((pp0, pp1))
9408
RCS HUGE **pp0 C0("")@;
9409
RCS HUGE **pp1 C1("")@;
9411
return STRCMP((*pp0)->keyword, (*pp1)->keyword);
9414
@ Here we escape an |ASCII| string into another |ASCII| buffer. We return the
9415
beginning of the output buffer.
9421
OVERFLW("Esc_buf:temp","")@;
9426
esc_buf FCN((temp,temp_end,buf,all_cases))
9427
ASCII HUGE *temp C0("Put it into here.")@;
9428
CONST ASCII HUGE *temp_end C0("End of |temp|.")@;
9429
CONST ASCII HUGE *buf C0("Translate from here.")@;
9430
boolean all_cases C1("")@;
9432
ASCII HUGE *temp0 = temp;
9438
@<Special \TeX\ cases@>:
9439
if(!all_cases) break;
9441
@<Other string cases@>:
9450
return temp0; // Return the beginning of the output buffer.
9453
@ Just before the index comes a list of all the changed modules, including
9454
the index module itself.
9458
EXTERN sixteen_bits k_module; /* Runs through the modules */
9461
@<Tell about changed modules@>=
9463
/* Remember that the index is already marked as changed */
9466
while (!chngd_module[++k_module]);
9470
out_mod(k_module,ENCAP);
9472
while (k_module < module_count)
9474
while (!chngd_module[++k_module]); /* Skip over
9475
unchanged modules. */
9477
OUT_STR(", "); out_mod(k_module,ENCAP);
9483
@ A left-to-right radix sorting method is used, since this makes it easy to
9484
adjust the collating sequence and since the running time will be at worst
9485
proportional to the total length of all entries in the index. We put the
9486
identifiers into different lists based on their first characters.
9487
(Uppercase letters are put into the same list as the corresponding
9488
lowercase letters, since we want to have `$t<\\{TeX}<\&{to}$'.) The list
9489
for character~|c| begins at location |bucket[c]| and continues through the
9494
EXTERN name_pointer bucket[128]; // One for each standard |ASCII char|.
9495
EXTERN name_pointer next_name; /* Successor of |cur_name| when sorting */
9496
IN_COMMON hash_pointer h; /* Index into |hash| */
9498
IN_COMMON BUF_SIZE max_names; /* number of identifiers, strings, module names;
9499
must be less than~10240 */
9500
EXTERN name_pointer HUGE *blink; /* Links in the buckets */
9501
EXTERN ASCII last_letter SET('\0'); /* Used for separating groups in the
9507
ALLOC(name_pointer,blink,ABBREV(max_names),max_names,0);
9509
@ To begin the sorting, we go through all the hash lists and put each entry
9510
having a nonempty cross-reference list into the proper bucket.
9512
@<Do the first pass of sorting@>=
9517
for (c=0; c<=127; c++) bucket[c]=NULL;
9519
for (h=hash; h<=hash_end; h++)
9525
cur_name=next_name; next_name=cur_name->link;
9527
if ((xref_pointer)cur_name->xref != xmem)
9529
c=(cur_name->byte_start)[0];
9533
blink[cur_name-name_dir]=bucket[c];
9540
@ During the sorting phase we shall use the |cat| and |trans| arrays from
9541
\.{WEAVE}'s parsing algorithm and rename them |depth| and |head|. They now
9542
represent a stack of identifier lists for all the index entries that have
9543
not yet been output. The variable |sort_ptr| tells how many such lists are
9544
present; the lists are output in reverse order (first |sort_ptr|, then
9545
|sort_ptr-1|, etc.). The |j|th list starts at |head[j]|, and if the first
9546
|k| characters of all entries on this list are known to be equal we have
9550
@<Rest of |trans_plus| union@>=
9555
@f sort_pointer scrap_pointer
9557
@d depth cat /* reclaims memory that is no longer needed for parsing */
9558
@d head trans_plus.Head /* ditto */
9559
@d sort_pointer scrap_pointer /* ditto */
9560
@d sort_ptr scrp_ptr /* ditto */
9561
@d max_sorts max_scraps /* ditto */
9565
EXTERN eight_bits cur_depth; /* Depth of current buckets */
9566
EXTERN ASCII HUGE *cur_byte; /* Index into |byte_mem| */
9567
EXTERN sixteen_bits cur_val; /* Current cross-reference number */
9569
EXTERN sort_pointer mx_sort_ptr; /* largest value of |sort_ptr| */
9574
mx_sort_ptr=scrp_info;
9577
@ The desired alphabetic order is specified by the |collate| array; namely,
9578
|collate[0]==0 <collate[1]<@t$\cdots$@><collate[max_collate]|. The collate
9579
array can be set by the style file entry \.{collate}.
9583
EXTERN ASCII collate[128]; // collation order.
9584
EXTERN int max_collate; // Last index in |collate|.
9586
@ We use the order $\hbox{null}<\.\ <\hbox{other characters}<\.\_<
9587
\.A=\.a<\cdots<\.Z=\.z<\.0<\cdots<\.9.$
9593
@ Procedure |unbucket| goes through the buckets and adds nonempty lists to
9594
the stack, using the collating sequence specified in the |collate| array.
9595
The parameter to |unbucket| tells the current depth in the buckets. Any
9596
two sequences that agree in their first 255 character positions are
9597
regarded as identical.
9599
@d INFTY 255 // $\infty$ (approximately).
9604
unbucket FCN((d)) /* Empties buckets having depth |d| */
9605
eight_bits d C1("")@;
9607
int c; /* Index into |bucket|. {\it Must be |int|.} */
9609
for (c=max_collate; c>= 0; c--) if (bucket[collate[c]]) {
9610
if (sort_ptr>=scrp_end) OVERFLW("sort levels",ABBREV(max_scraps));
9614
if (sort_ptr>mx_sort_ptr) mx_sort_ptr = sort_ptr;
9616
sort_ptr->depth = (eight_bits)(c==0 ? INFTY : d);
9617
sort_ptr->head = bucket[collate[c]];
9618
bucket[collate[c]] = NULL;
9623
@<Sort and output the index@>=
9625
w_style.indx.collate = x__to_ASCII((outer_char *)w_style.indx.collate);
9626
max_collate = STRLEN(w_style.indx.collate);
9627
STRNCPY(collate+1,w_style.indx.collate,max_collate);
9629
sort_ptr=scrp_info; unbucket(1);
9631
while (sort_ptr>scrp_info)
9633
cur_depth=sort_ptr->depth;
9635
if (blink[sort_ptr->head-name_dir]==0 || cur_depth==INFTY)
9636
@<Output index entries for the list at |sort_ptr|@>@;
9637
else @<Split the list at |sort_ptr| into further lists@>;
9641
@<Split the list...@>=
9646
next_name=sort_ptr->head;
9650
cur_name=next_name; next_name=blink[cur_name-name_dir];
9651
cur_byte=cur_name->byte_start+cur_depth;
9653
if (cur_byte==(cur_name+1)->byte_start) c=0; /* hit end of the name */
9660
blink[PTR_DIFF(size_t,cur_name,name_dir)]=bucket[c];
9665
--sort_ptr; unbucket((eight_bits)(cur_depth+(eight_bits)1));
9669
@<Output index...@>=
9671
cur_name = sort_ptr->head;
9673
@<Separate the groups if necessary@>@;
9677
if(cur_name->defined_type(language) < 0x80)
9678
{ /* Write index entry for one identifier. */
9679
OUT_STR(w_style.indx.item_0);
9681
@<Output the name at |cur_name|@>;
9682
@<Output the cross-references at |cur_name|@>;
9685
cur_name = blink[cur_name-name_dir];
9692
@ Here we insert an optional macro between the different groups.
9694
@d NON_TEX_MACRO '\1'
9696
@<Separate the groups...@>=
9698
ASCII letter = *cur_name->byte_start;
9700
/* In some special cases in \Cpp, the identifier may be a \TeX\ macro
9701
beginning with~'\.\\' at this point. We must then take special precautions.
9702
In particular, we assign a non-null, non-printable value to |letter|. */
9703
if(letter == @'\\' && cur_name->ilk==normal && language!=TEX)
9704
letter = NON_TEX_MACRO;
9706
letter = A_TO_LOWER(letter);
9708
if(letter != last_letter)
9711
{ /* Separate groups, but not for the very first one. */
9712
OUT_STR(w_style.indx.group_skip);
9715
if(w_style.indx.lethead_flag && letter != NON_TEX_MACRO)
9717
OUT_STR(w_style.indx.lethead_prefix);
9721
@<Special string cases@>: out(@'\\');
9723
out((w_style.indx.lethead_flag > 0 ? A_TO_UPPER(letter) :
9724
A_TO_LOWER(letter)));
9726
if(w_style.indx.m_headings_flag)
9729
OUT_STR(w_style.indx.lethead_suffix);
9733
last_letter = letter;
9737
@<Output the name...@>=
9739
boolean all_uc = cur_name->info.upper_case;
9743
m_start = out_ptr + 1;
9745
switch (cur_name->ilk)
9748
output_type = IDENTIFIER;
9750
if(is_intrinsic(cur_name))
9751
OUT_STR(pfrmt->intrinsic);
9753
else if(is_keyword(cur_name))
9754
OUT_STR(ALL_UC ? pfrmt->KEYWORD : pfrmt->keyword);
9755
// E.g., |@r BLOCKSIZE|.
9758
OUT_STR(pfrmt->typewritr);
9759
// E.g., \.{\\hfill}.
9760
else if (length(cur_name)==1)
9761
OUT_STR(pfrmt->short_id); // E.g., |a|.
9763
@<Output the appropriate identifier prefix@>@;
9768
case roman: output_type = INDEX_ENTRY; @~ break;
9769
case wildcard: OUT_STR(pfrmt->wildcrd); @~ output_type = INDEX_ENTRY; @~ break;
9771
case typewriter: OUT_STR(pfrmt->typewritr);
9772
output_type = INDEX_ENTRY; @~ break;
9775
OUT_STR(ALL_UC ? pfrmt->RESERVED : pfrmt->reserved);
9776
output_type = IDENTIFIER; @~ break; // E.g., |int|.
9780
out_name(m_temp1, YES, output_type,cur_name);
9783
@ Section numbers that are to be underlined are enclosed in
9784
`\.{\\[}$\,\ldots\,$\.]'.
9789
@<Output the cross-references...@>=
9791
@<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>;
9793
OUT_STR(w_style.indx.delim_0); /* Immediately before identifier. */
9799
m_start = out_ptr + 1;
9802
out_name(m_temp0, NO, output_type, cur_name);
9804
MX_STR(mx_quote(m_temp, m_temp0));
9806
MX_STR(mx_quote(m_temp, m_temp1));
9808
cur_val=cur_xref->num;
9812
/* Write `\.{pg\{\}}' --- file id unspecified for now. */
9815
MX_OUT_C(arg_close);
9817
if (cur_val<def_flag)
9819
MX_OUT_C(arg_open); // Empty action macro line \.{\\underline}.
9820
MX_OUT_C(arg_close);
9822
MX_OUT_C(arg_close); // End of \.{\\indexentry}.
9823
out_mod(cur_val, ENCAP);
9827
OUT_STR(w_style.indx.underline_prefix);
9829
/* Write action macro like \.{\\underline}. */
9831
MX_OUT_S(underline);
9832
MX_OUT_C(arg_close);
9834
out_mod(cur_val-def_flag, ENCAP);
9835
OUT_STR(w_style.indx.underline_suffix);
9839
/* If the language of this module isn't the global language, mark it in the
9841
if((LANGUAGE)cur_xref->Language != global_language)
9845
sprintf(temp,"%s%s%s",
9846
(char *)w_style.indx.language_prefix,
9847
(char *)LANGUAGE_SYMBOL((LANGUAGE)cur_xref->Language),
9848
(char *)w_style.indx.language_suffix);
9852
MX_CHAR('\n'); // Finish off one page.
9854
cur_xref=cur_xref->xlink;
9856
if(cur_xref == xmem)
9857
break; // No more pages.
9859
OUT_STR(w_style.indx.delim_n); /* Between page numbers. */
9862
out(@'.'); @~ fin_line();
9868
mx_quote FCN((m_out, s))
9869
outer_char *m_out C0("Escape into here")@;
9870
outer_char *s C1("Input")@;
9876
INDEX HUGE *q = &w_style.indx;
9884
|| c == q->m_actual)
9895
@ List inversion is best thought of as popping elements off one stack and
9896
pushing them onto another. In this case |cur_xref| will be the head of
9897
the stack that we push things onto.
9899
@<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>=
9901
this_xref = (xref_pointer)cur_name->xref; cur_xref=xmem;
9905
next_xref=this_xref->xlink; this_xref->xlink=cur_xref;
9906
cur_xref=this_xref; this_xref=next_xref;
9908
while (this_xref!=xmem);
9910
@ The following recursive procedure walks through the tree of module names and
9917
mod_print FCN((p)) /* Print all module names in subtree |p|. */
9918
name_pointer p C1("")@;
9922
mod_print(p->llink); OUT_STR("\\:");
9924
tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrp_ptr=scrp_info; ini_stack;
9925
APP_FLAG(mod, p, name_dir);
9927
footnote(0); /* |cur_xref| was set by |make_output| */
9930
mod_print(p->rlink);
9937
if(makeindex) fprintf(mx_file, "%s", str)@;
9940
if(makeindex) fprintf(mx_file, "%c", c)@;
9943
MX_STR(w_style.indx.m_##name)
9946
MX_CHAR(w_style.indx.m_##name)
9949
if(makeindex) fprintf(mx_file, "%i", w_style.indx.m_##name)@;
9953
EXTERN FILE *mx_file;
9954
EXTERN outer_char HUGE *m_start;
9955
EXTERN outer_char m_temp[100], m_temp0[100], m_temp1[100];
9956
EXTERN boolean output_type;
9957
EXTERN outer_char HUGE *temp_ndx,HUGE *temp_mds;
9958
IN_COMMON outer_char wbflnm0[];
9961
@<Output the index@>=
9963
writing(YES, temp_ndx);
9965
if(tex_file == stdout)
9972
@<Write \.{makeindex} style file@>@;
9974
mx_open(w_style.indx.m_out);
9975
fprintf(mx_file, "%% %s\n\n", wbflnm0);
9980
@<Tell about changed modules@>;
9985
OUT_STR(w_style.indx.preamble); @~ fin_line();
9988
@<Do the first pass of sorting@>;
9989
@<Sort and output the index@>;
9991
OUT_STR(w_style.indx.postamble); @~ fin_line();
9998
fprintf(mx_file, "%s \"%s\"\n", #name,
9999
dbl_bslash(m_temp0, w_style.indx.m_##name))
10002
fprintf(mx_file, "%s '%s'\n", #name,
10003
dbl_cslash(m_temp0, w_style.indx.m_##name))
10006
fprintf(mx_file, "%s %i\n", #name, w_style.indx.m_##name)
10008
@<Write \.{make...@>=
10010
mx_open(w_style.indx.m_sty);
10012
MX_STR("% Produced automatically by fweave.\n\n");
10014
sprintf((char *)m_temp0,
10015
" \\Wequate{%s%s} {%s} {%s%s} {%s%s} {%s%s} {%s} {%s%s} {%s} {%s}\n\n",
10016
pfrmt->reserved, pfrmt->RESERVED,@\ \
10017
pfrmt->short_id,@\ \
10018
pfrmt->id, pfrmt->ID,@\ \
10019
pfrmt->id_outer, pfrmt->ID_OUTER,@\ \
10020
pfrmt->id_inner, pfrmt->ID_INNER,@\ \
10021
pfrmt->intrinsic,@\ \
10022
pfrmt->keyword, pfrmt->KEYWORD,@\ \
10023
pfrmt->typewritr, "");
10025
fprintf(mx_file, "%s \"%s\\\n%s\"\n",
10027
dbl_bslash(m_temp, w_style.indx.m_preamble),
10028
dbl_bslash(m_temp1, m_temp0));
10030
MX_STY_S(postamble);
10032
MX_STY_C(arg_open);
10033
MX_STY_C(arg_close);
10034
MX_STY_C(range_open);
10035
MX_STY_C(range_close);
10041
MX_STY_S(setpage_prefix);
10042
MX_STY_S(setpage_suffix);
10043
MX_STY_S(group_skip);
10044
MX_STY_I(headings_flag);
10045
MX_STY_S(heading_prefix);
10046
MX_STY_S(symhead_positive);
10047
MX_STY_S(symhead_negative);
10048
MX_STY_S(numhead_positive);
10049
MX_STY_S(numhead_negative);
10063
MX_STY_S(encap_prefix);
10064
MX_STY_S(encap_infix);
10065
MX_STY_S(encap_suffix);
10066
MX_STY_I(line_max);
10067
MX_STY_S(indent_space);
10068
MX_STY_I(indent_length);
10073
@ Translate a string, inserting appropriate backslashes.
10076
dbl_bslash FCN((m_temp, s))
10077
outer_char *m_temp C0("Buffer")@;
10078
outer_char *s C1("String to expand")@;
10082
for(p=m_temp; *s; )
10086
if(iscntrl(c) || c == '\\')
10087
@<Translate a control character |c|@>@;
10097
@ Make a string out of a single character.
10101
dbl_cslash FCN((m_temp, c))
10102
outer_char *m_temp C0("Buffer")@;
10103
outer_char c C1("Char to expand")@;
10105
outer_char *p = m_temp;
10107
if(iscntrl(c) || c == '\\')
10108
@<Translate a control character |c|@>@;
10117
@<Translate a cont...@>=
10123
case '\a': c = 'a'; break;
10124
case '\b': c = 'b'; break;
10125
case '\f': c = 'f'; break;
10126
case '\n': c = 'n'; break;
10127
case '\r': c = 'r'; break;
10128
case '\t': c = 't'; break;
10129
case '\v': c = 'v'; break;
10140
SRTN mx_open FCN((ext))
10141
outer_char *ext C1("File extension")@;
10143
xpn_name(&temp_ndx, MAX_FILE_NAME_LENGTH, ext, wbflnm0);
10144
mx_file = FOPEN(temp_ndx, "w");
10147
writing(NO, temp_ndx);
10150
CLR_PRINTF(WARNINGS, info,
10151
("\n! Can't open makeindex file %s\n", temp_ndx));
10158
@<Output all the module names@>=
10160
writing(BOOLEAN(!prn_index),temp_mds);
10163
OUT_STR(w_style.modules.preamble); @~ fin_line();
10168
OUT_STR(w_style.modules.postamble); @~ fin_line();
10171
@ Statistics are printed when the command-line option~\.{-s} is used.
10176
see_statistics(VOID)
10178
CLR_PRINTF(ALWAYS, info,("\n\nMEMORY USAGE STATISTICS:\n"));
10180
STAT0("names",sizeof(*name_ptr),
10181
SUB_PTRS(name_ptr,name_dir),max_names,UPPER(max_names),",");
10183
STAT0("cross-references",sizeof(*xref_ptr),
10184
SUB_PTRS(xref_ptr,xmem),max_refs,UPPER(max_refs),",");
10186
STAT0("bytes",sizeof(*byte_ptr),
10187
SUB_PTRS(byte_ptr,byte_mem),max_bytes,UPPER(max_bytes),";");
10189
CLR_PRINTF(ALWAYS, info,(" parsing required\n"));
10191
STAT0("scraps",sizeof(*mx_scr_ptr),
10192
SUB_PTRS(mx_scr_ptr,scrp_base),max_scraps,UPPER(max_scraps),",");
10194
STAT0("texts",sizeof(*mx_text_ptr),
10195
SUB_PTRS(mx_text_ptr,tok_start),max_texts,UPPER(max_texts),",");
10197
STAT0("tokens",sizeof(*mx_tok_ptr),
10198
SUB_PTRS(mx_tok_ptr,tok_mem),max_toks,UPPER(max_toks_w),",");
10200
STAT0("stack levels",sizeof(*mx_stck_ptr),
10201
SUB_PTRS(mx_stck_ptr,stack),stck_size,UPPER(stck_size_w),";");
10203
CLR_PRINTF(ALWAYS, info, (" sorting required"));
10205
printf(" %lu level(s).\n", SUB_PTRS(mx_sort_ptr,scrp_info));
10207
mem_avail(1); // How much memory left at end of run?
10210
@ The following routines are invoked by \.{common.web}, but are used only by
10215
predefine_macros(VOID)
10223
was_opened FCN((name,global_scope,pname,pptr))
10224
CONST outer_char HUGE *name C0("")@;
10225
boolean global_scope C0("")@;
10226
outer_char HUGE * HUGE *pname C0("")@;
10227
FILE **pptr C1("")@;
10229
*pname = GET_MEM("*pname",STRLEN(name)+1,outer_char);
10230
STRCPY(*pname,name);
10235
SRTN ini_tokens FCN((language0))
10236
LANGUAGE language0 C1("")@;
10239
@* STYLE FILE. The style file is common to \FWEAVE\ and \FTANGLE. See
10244
#include "map.h" // Relations between style file keywords and internal arrays.
10246
@* INDEX. If you have read and understood the code for Phase~III above,
10247
you know what is in this index and how it got here. All modules in which an
10248
identifier is used are listed with that identifier, except that reserved
10249
words are indexed only when they appear in format definitions, and the
10250
appearances of identifiers in module names are not indexed. Underlined
10251
entries correspond to where the identifier was declared. Error messages,
10252
control sequences put into the output, and a few other things like
10253
``recursion'' are indexed here too.