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-----------------------------------------------------------------------------
9
\Title{PROD.WEB} % Productions for the FWEAVE processor.
14
In order to accomodate memory-starved personal computers, the productions
15
have been split off from the main part of \FWEAVE.
20
@<Possibly split into parts@>@;
23
@<Typedef declarations@>@;
25
@<Global variables@>@;
27
/* For PC's, the file is split into two compilable parts using the
28
compiler-line macro |part|, which must equal either~1 or~2. */
43
@ The function prototypes must appear before the global variables.
51
@* PARSING. The most intricate part of \.{WEAVE} is its mechanism for
52
converting \cee-like code into \TeX\ code, and we might as well plunge into
53
this aspect of the program now. A ``bottom up'' approach is used to parse
54
the \cee-like material, since \.{WEAVE} must deal with fragmentary
55
constructions whose overall ``part of speech'' is not known.
57
At the lowest level, the input is represented as a sequence of entities
58
that we shall call {\it scraps}, where each scrap of information consists
59
of two parts, its {\it category} and its {\it translation}. The category is
60
essentially a syntactic class, and the translation is a token list that
61
represents \TeX\ code. Rules of syntax and semantics tell us how to combine
62
adjacent scraps into larger ones, and if we are lucky an entire \cee\ text
63
that starts out as hundreds of small scraps will join together into one
64
gigantic scrap whose translation is the desired \TeX\ code. If we are
65
unlucky, we will be left with several scraps that don't combine; their
66
translations will simply be output, one by one.
68
The combination rules are given as context-sensitive productions that are
69
applied from left to right. Suppose that we are currently working on the
70
sequence of scraps $s_1\,s_2\ldots s_n$. We try first to find the longest
71
production that applies to an initial substring $s_1\,s_2\ldots\,$; but if
72
no such productions exist, we find to find the longest production
73
applicable to the next substring $s_2\,s_3\ldots\,$; and if that fails, we
74
try to match $s_3\,s_4\ldots\,$, etc.
76
A production applies if the category codes have a given pattern. For
77
example, one of the productions is $$\hbox{|expr| |binop| |expr| $\RA$
78
|expr|}$$ and it means that three consecutive scraps whose respective
79
categories are |expr|, |binop|, and |expr| are con\-verted to one scraps
80
whose category is |expr|. The scraps are simply concatenated. The case of
81
$$\hbox{|expr| |comma| |expr| $\RA$ |expr|}$$ is only slightly more
82
complicated: here the resulting |expr| scrap consists not only of the three
83
original scraps, but also of the tokens~|opt| and~9 between the |comma| and
84
the following |expr|. In the \TeX\ file, this will specify an additional
85
thin space after the comma, followed by an optional line break with penalty~90.
87
At each opportunity the longest possible production is applied: for
88
example, if the current sequence of scraps is |struct_like| |expr| |lbrace|
89
this is transformed into a |struct_hd| by rule~31, but if the sequence is
90
|struct_like| |expr| followed by anything other than |lbrace| only two
91
scraps are used (by rule~32) to form an |int_like|.
95
@ For debugging, we need to append a newline to the output of certain
96
routines so the output gets flushed.
98
@d DFLUSH if(dflush) puts("");
102
IN_PROD boolean dflush PSET(NO); // Turn this on from debugger.
104
@ The following function symbolically prints out a category. (In using the
105
|OUT1| macro, we take advantage of the fact that the \.{\#}~operator does
106
not put a second set of quotes around a string. By enclosing the |name|
107
arguments in quotes, we keep \FWEAVE\ from getting confused about the part
108
of speech under discussion; it's not used to seeing a reserved word in the
109
location of an argument.)
111
@m OUT(cs) case cs: printf(#*cs); @~ break@;
112
@m OUT1(cs,name) case cs: printf(#*name); @~ break@;
119
eight_bits c C1("Category.")@;
123
OUT1(language_scrap,"@@L");
126
OUT1(_EXPR,$_EXPR); @~ OUT1(EXPR_,$EXPR_); @~ OUT1(_EXPR_,$_EXPR_);
131
OUT1(Decl_hd,$Decl_hd);
136
OUT1(else_like,"else");
137
OUT1(ELSE_like,ELSE);
143
OUT1(UNOP,$UNOP_ @e);
145
OUT1(BINOP,@e $_BINOP_ @e);
150
OUT1(COMMA,@e $_COMMA_ @e);
162
OUT1(slash_like,"slash");
163
OUT1(private_like, "private");
168
OUT1(ignore_scrap,"ignore");
170
OUT1(define_like,define);
173
OUT1(while_do, "while");
177
OUT1(for_like,"for");
178
OUT1(program_like,program);
181
OUT1(huge_like,"huge");
182
OUT1(CASE_like,CASE);
183
OUT1(case_like,"case");
184
OUT1(sizeof_like,sizeof @e);
186
OUT1(proc_like,"proc");
187
OUT1(class_like,"class");
188
OUT1(struct_like,"struct");
189
OUT1(typedef_like,"typedef");
190
OUT1(imp_reserved,"imp_rsrvd");
191
OUT1(extern_like,"extern");
192
OUT1(common_like,common);
193
OUT1(read_like,read);
194
OUT1(entry_like,entry);
195
OUT1(implicit_like,implicit);
198
OUT1(endif_like,endif);
206
OUT1(until_like,until);
215
OUT1(kill_newlines, killnl);
218
default: printf("UNKNOWN(%i)", c); @~ break;
228
@ Here is a table of all the productions. The reader can best get a feel for
229
@^productions, table of@>
230
how they work by trying them out by hand on small examples; no amount of
231
explanation will be as effective as watching the rules in action. Parsing
232
can also be watched by debugging with~`\.{@@2}' or by using the
233
command-line option ``\.{-2}''. [Please see file
234
\.{examples/prod.web}.]
238
@ This dummy module keeps \FTANGLE\ from complaining. (It's needed only by
242
@<Rest of |trans_plus| union@>=
244
@ The following functions prints a token list. It is intended to be called
252
text_pointer p C1("The token list.")@;
254
token_pointer j; /* index into |tok_mem| */
255
sixteen_bits r; /* remainder of token after the flag has been stripped off */
259
else for (j=*p; j<*(p+1); j++)
261
r = (sixteen_bits)(*j % id_flag);
265
case 1: printf("\\\\{"); prn_id((name_dir+r)); printf("}"); break;
267
case 2: printf("\\&{"); prn_id((name_dir+r)); printf("}"); break;
269
case 3: printf("<"); prn_id((name_dir+r)); printf(">"); break;
271
case 4: printf("[[%d]]",r); break; /* |tok_flag| */
272
case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */
273
default: @<Print token |r| in symbolic form@>;
282
scrap_pointer p C1("")@;
284
prn_text(indirect(p->trans));
290
@<Print token |r|...@>=
294
case math_bin: printf("\\mathbin}"); @~ break;
295
case math_rel: printf("\\mathrel}"); @~ break;
296
case big_cancel: printf("[ccancel]"); @~ break;
297
case cancel: printf("[cancel]"); @~ break;
298
case indent: printf("[indent]"); @~ break;
299
case outdent: printf("[outdent]"); @~ break;
300
case backup: printf("[backup]"); @~ break;
301
case opt: printf("[opt]"); @~ break;
302
case break_space: printf("[break]"); @~ break;
303
case force: printf("[force]"); @~ break;
304
case big_force: printf("[fforce]"); @~ break;
305
case end_translation: printf("[quit]"); @~ break;
306
default: putxchar(XCHR(r));
309
@ The production rules listed above are embedded directly into the
310
\.{WEAVE} program, since it is easier to do this than to write an
311
interpretive system that would handle production systems in general.
312
Several macros are defined here so that the program for each production is
315
All of our productions conform to the general notion that some~|k|
316
consecutive scraps starting at some position~|j| are to be replaced by a
317
single scrap of some category~|c| whose translations is composed from the
318
translations of the disappearing scraps. After this production has been
319
applied, the production pointer~|pp| should change by an amount~|d|. Such a
320
production can be represented by the quadruple |(j,k,c,d)|. For example,
321
the production `|expr@,comma@,expr| $\RA$ |expr|' would be represented by
322
`|(pp,3,expr,-2)|'; in this case the pointer |pp| should decrease by~2
323
after the production has been applied, because some productions with |expr|
324
in their second or third positions might now match, but no productions have
325
|expr| in the fourth position of their left-hand sides. Note that the value
326
of~|d| is determined by the whole collection of productions, not by an
327
individual one. The determination of~|d| has been done by hand in each
328
case, based on the full set of productions but not on the grammar of the
329
language or on the rules for constructing the initial scraps.
331
We also attach a serial number of each production, so that additional
332
information is available when debugging. For example, the program below
333
contains the statement `|REDUCE(pp,3,expr,-2,4)|' when it implements the
334
production just mentioned.
336
Before calling |reduce|, the program should have appended the tokens of the
337
new translation to the |tok_mem| array. We commonly want to append copies
338
of several existing translations, and macros are defined to simplify these
339
common cases. For example, |b_app2(pp)| will append the translations of
340
two consecutive scraps, |pp->trans| and |(pp+1)->trans|, to the current
341
token list. If the entire new translation is formed in this way, we write
342
`|SQUASH(j,k,c,d)|' instead of `|REDUCE(j,k,c,d)|'. For example,
343
`|SQUASH(pp,3,expr,-2,3)|' is an abbreviation for `|b_app3(pp);
344
REDUCE(pp,3,math,-2,3)|'.
346
The code below is an exact translation of the production rules into~C
347
using such macros, and the reader should have no difficulty understanding
348
the format by comparing the code with the symbolic productions as they were
351
To understand the routines that append tokens or scraps in detail, we must
352
discuss the concept of \It{mathness}. This is used to determine how to
353
enclose things in dollar signs---i.e., what things should be treated in
356
Routines such as |app| or |app_str| append stuff to the list without
357
changing the mathness.
359
Routines such as |b_app| or |b_app1| (the 'b' stands for 'big')
360
provisionally change the mathness depending on what's come before and
361
what's being appended.
363
Three flags handle the mathness. |cur_mathness| is the mathness at this
364
point in the construction. |ini_mathness| is the initial mathness of the
365
stuff that's been appended so far. |last_mathness| is the mathness of the
366
last stuff that's been appended. (|cur_mathness| and |last_mathness| appear
367
to be redundant, but we're not changing the code right now.)
369
The next macros \It{big\_appn} append $n$~consective tokens.
371
@D b_app2(a) b_app1(a); @~ b_app1(a+1)
372
@D b_app3(a) b_app2(a); @~ b_app1(a+2)
373
@D b_app4(a) b_app3(a); @~ b_app1(a+3)
377
IN_PROD int cur_mathness, ini_mathness, last_mathness;
379
@ Append an entire string, converting to |ASCII| if necessary. (Don't
380
change the mathness.)
386
CONST outer_char HUGE *s C1("String to be appended.")@;
392
/* Append a string that's already Ascii. */
394
app_ASCII_str FCN((s))
395
CONST ASCII HUGE *s C1("")@;
401
@ Append a token, possibly changing the mathness.
407
Token a C1("Token to be appended.")@;
409
if (a==@' ' || (a>=big_cancel && a<=big_force))
410
{/* Appending a non-math token, including a space. */
411
if (cur_mathness ==maybe_math)
412
ini_mathness=no_math;
413
else if (cur_mathness==yes_math)
418
app(@'$'); // End math mode.
421
cur_mathness=last_mathness=no_math;
424
{ /* Append a math token. (Tokens can't be |maybe_math|.) */
425
if (cur_mathness==maybe_math)
426
ini_mathness=yes_math;
427
else if (cur_mathness==no_math)
429
app(@'$'); // Begin math mode.
435
cur_mathness=last_mathness=yes_math;
441
@ Append an entire scrap, possibly changing the mathness. The mathness for
442
scraps is stored in an |eight_bits| in the form |4*last_mathness +
445
@d INI_MATHNESS(p) ((p)->mathness % 4)
446
/* Left boundary (|ini_mathness|) of the current scrap. */
447
@d LAST_MATHNESS(p) ((p)->mathness / 4)
448
/* Right boundary (|last_mathness|) */
454
scrap_pointer a C1("Scrap to be appended.")@;
456
switch(INI_MATHNESS(a))
459
if (cur_mathness==maybe_math)
460
ini_mathness = no_math;
461
else if (cur_mathness==yes_math)
466
APP_STR("$"); /* End math mode. (The braces take care of
467
ending the math part with something like a~$+$.) */
470
cur_mathness = last_mathness = LAST_MATHNESS(a);
474
if (cur_mathness==maybe_math)
475
ini_mathness=yes_math;
476
else if (cur_mathness==no_math)
478
APP_STR("$"); /* Begin math mode. (The braces take care
479
of beginning the math part with something like a~$+$.) */
485
cur_mathness = last_mathness = LAST_MATHNESS(a);
489
break; // No changes in mathness.
492
app(a->trans + tok_flag - tok_start);
495
@ Let us consider the big switch for productions now, before looking at its
496
context. We want to design the program so that this switch works, so we
497
might as well not keep ourselves in suspense about exactly what code needs
498
to be provided with a proper environment.
500
\Ratfor\ and \Fortran\ are treated as two dialects of the same language,
501
because almost all of the rules are the same. The most important exception
502
is in the \&{if} statements.
504
The first thing we do is to process any language scrap. Such scraps begin
505
with |begin_language|, then the language number as the next token. We use
506
that token to reset the language.
508
If it's not a language scrap, we gobble up any |ignore_scrap|. For reasons
509
that are now obscure, we regress by $-2$ after that. This doesn't work
510
quite right; the logic of some of the |if| statements gets screwed up if
511
there's a comment in the wrong place.
513
@<Match a production at |pp|, or increase |pp| if there is no match@>=
515
if(cat0 == language_scrap)
517
language = lan_enum(get_language(pp->trans)); /* Get language from
519
ini0_language(); // Reset params like |auto_semi|.
520
SQUASH(pp,1,ignore_scrap,-1,0);
522
else if(cat1==ignore_scrap) SQUASH(pp,2,cat0,-2,0);//Gobble an |ignore_scrap|.
523
@% else if(cat0==ignore_scrap) SQUASH(pp,2,cat1,0,0); // Screws language cmd.
524
else switch(language)
527
CONFUSION("match production",
528
"Language hasn't been defined yet");
537
if(!RAT_OK("(translate)"))
538
CONFUSION("match production",
539
"Language shouldn't be Ratfor here");
556
CONFUSION("match a production","Invalid language");
559
pp++; // if no match was found, we move to the right and try again.
565
get_language FCN((xp))
566
text_pointer xp C1("")@;
568
token_pointer tp,tp1;
571
tp1 = *(xp+1) - 1; /* The |-1| is because we should always have the
572
combination |begin_language| followed by the language number. */
575
if(*tp++ == begin_language) return *tp;
577
return CONFUSION("get_language",
578
"Can't find |begin_language| token in language_scrap");
581
@* PRODUCTIONS for C. The productions have been made into individual
582
functions to accomodate memory-starved pc's.
591
case ignore_scrap: @<CASES for |ignore_scrap| (C)@>@; break;
592
case built_in: @<CASES for |built_in| (R)@>@; @~ break;
593
case expr: @<CASES for |expr| (C)@>@; @~ break;
594
case exp_op: @<CASES for |exp_op| (R)@>@; @~ break;
595
case _EXPR: @<CASES for |_EXPR| (C)@>@; @~ break;
596
case _EXPR_: @<CASES for |_EXPR_| (C)@>@; @~ break;
597
case EXPR_: @<CASES for |EXPR_| (C)@>@; @~ break;
598
case new_like: @<CASES for |new_like| (C)@>@; @~ break;
599
case lpar: @<CASES for |lpar| (C)@>@; @~ break;
600
case lbracket: @<CASES for |lbracket| (C)@>@; @~ break;
601
case rbracket: @<CASES for |rbracket| (C)@>@; @~ break;
602
case question: @<CASES for |question| (C)@>@; @~ break;
603
case unop: @<CASES for |unop| (C)@>@; @~ break;
604
case UNOP: @<CASES for |UNOP| (C)@>@; @~ break;
605
case unorbinop: @<CASES for |unorbinop| (C)@>@; @~ break;
606
case binop: @<CASES for |binop| (C)@>@; @~ break;
607
case BINOP: @<CASES for |BINOP| (C)@>@; @~ break;
608
case COMMA: @<CASES for |COMMA| (C)@>@; @~ break;
609
case cast: @<CASES for |cast| (C)@>@; @~ break;
610
case sizeof_like: @<CASES for |sizeof_like| (C)@>@; @~ break;
611
case int_like: @<CASES for |int_like| (C)@>@; @~ break;
612
case extern_like: @<CASES for |extern_like| (C)@>@; @~ break;
613
case modifier: @<CASES for |modifier| (C)@>@; @~ break;
614
case huge_like: @<CASES for |huge_like| (C)@>@; @~ break;
615
case decl_hd: @<CASES for |decl_hd| (C)@>@; @~ break;
616
case decl: @<CASES for |decl| (C)@>@; @~ break;
617
case typedef_like: @<CASES for |typedef_like| (C)@>@; @~ break;
618
case imp_reserved: @<CASES for |imp_reserved| (C)@>@; @~ break;
619
case op_like: @<CASES for |op_like| (C)@>@; @~ break;
620
case class_like: @<CASES for |class_like| (C)@>@; @~ break;
621
case struct_like: @<CASES for |struct_like| (C)@>@; @~ break;
622
case struct_hd: @<CASES for |struct_hd| (C)@>@; @~ break;
623
case fn_decl: @<CASES for |fn_decl| (C)@>@; @~ break;
624
case functn: @<CASES for |functn| (C)@>@; @~ break;
625
case lbrace: @<CASES for |lbrace| (C)@>@; @~ break;
626
case do_like: @<CASES for |do_like| (C)@>@; @~ break;
627
case while_do: @<CASES for |while_do| (C)@>@; @~ break;
628
case if_like: @<CASES for |if_like| (C)@>@; @~ break;
629
case IF_like: @<CASES for |IF_like| (C)@>@; @~ break;
630
case IF_top: @<CASES for |IF_top| (C)@>@; @~ break;
631
case for_like: @<CASES for |for_like| (C)@>@; @~ break;
632
case for_hd: @<CASES for |for_hd| (C)@>@; @~ break;
633
case else_like: @<CASES for |else_like| (C)@>@; @~ break;
635
case ELSE_like: @<CASES for |ELSE_like| (C)@>@; @~ break;
637
case if_hd: @<CASES for |if_hd| (C)@>@; @~ break;
638
case else_hd: @<CASES for |else_hd| (C)@>@; @~ break;
639
case case_like: @<CASES for |case_like| (C)@>@; @~ break;
640
case stmt: @<CASES for |stmt| (C)@>@; @~ break;
641
case tag: @<CASES for |tag| (C)@>@; @~ break;
642
case semi: @<CASES for |semi| (C)@>@; @~ break;
643
case lproc: @<CASES for |lproc| (C)@>@; @~ break;
644
case LPROC: @<CASES for |LPROC| (C)@>@; @~ break;
645
case space: @<CASES for |space| (C)@>@; @~ break;
647
case template: @<CASES for |template| (C++)@>@; @~ break;
648
case langle: @<CASES for |langle| (C++)@>@; @~ break;
649
case rangle: @<CASES for |rangle| (C++)@>@; @~ break;
650
case tstart: @<CASES for |tstart| (C++)@>@; @~ break;
651
case tlist: @<CASES for |tlist| (C++)@>@; @~ break;
653
case virtual: @<CASES for |virtual| (C++)@>@; @~ break;
654
case reference: @<CASES for |reference| (C++)@>@; @~ break;
655
case namespace: @<CASES for |namespace| (C++)@>@; @~ break;
657
case kill_newlines: @<CASES for |kill_newlines| (C++)@>@; @~ break;
661
@ In~C, new specifier names can be defined via |typedef|, and we want
662
to make the parser recognize future ocurrences of the identifier thus
663
defined as specifiers. This is done by the procedure |make_reserved|,
664
which changes the |ilk| of the relevant identifier. (One difficulty with
665
this solution is that it is implemented in phase~2, so if one uses an
666
identifier before it is actually |typedef|'d, it won't typeset properly. In
667
these cases, an explicit~\.{@@f} is required as well.)
669
The original \CWEB\ design of |make_reserved| didn't handle a situation such as
670
|typedef int (*I)()|, because |I|~was inside parentheses. The procedure has
671
been augmented to handle this situation by following the indirection chain
677
make_reserved FCN((p)) /* Make the first identifier in |p->trans| like
679
scrap_pointer p C1("")@;
681
sixteen_bits tok_value = first_id(p->trans);
682
// The first identifier, plus its flag.
683
name_pointer pname = name_dir + tok_value - id_flag;
685
if(!tok_value || tok_value==@'(')
686
return; // Emergency return; no identifier found.
688
if(DEFINED_TYPE(pname) == M_MACRO || DEFINED_TYPE(pname) == D_MACRO)
689
return; // Don't |typedef| macro names.
691
/* Change categories of all future occurrences of the identifier. */
692
for (; p<=scrp_ptr; p++)
696
if (**(p->trans)==tok_value)
699
**(p->trans)+=res_flag-id_flag; // Mark as reserved.
704
pname->ilk = int_like;
705
pname->reserved_word |= (boolean)language;
707
if(mark_defined.typedef_name)
709
pname->defined_in(language) = module_count;
710
SET_TYPE(pname,TYPEDEF_NAME);
714
@ This function hunts through a translation until it finds the first
715
identifier, if there is one.
717
@d FIRST_ID(p) ( ((tok0=first_id(p->trans)) && tok0!=@'(') ? name_dir + tok0 -
718
id_flag : name_dir) // Ptr to actual id.
722
IN_PROD sixteen_bits tok0;
724
@ This function considers a token list between~|pk| and~|pk1|; it returns
725
the first (flagged) identifier token it finds, or 0~if there's none.
726
Because each component of the token list may itself be a token list, this
727
routine is called recursively.
733
text_pointer t C1("Pointer to start of token list")@;
735
token_pointer pk = *t; // Start of end.
736
token_pointer pk1 = *(t+1); // End of list.
737
sixteen_bits tok_value; // Current element.
739
for(; pk < pk1; pk++)
743
if(tok_value > inner_tok_flag) tok_value -= (inner_tok_flag -
746
if(tok_value <= tok_flag)
747
{ // It's an ordinary (non-flagged) token.
748
if( tok_value >= id_flag && tok_value < res_flag)
749
return tok_value; // Found identifier.
750
else if(tok_value == @'(') return tok_value; // STOP!!!
753
{ // Flagged token; use indirection.
754
t = tok_start + (int)(tok_value - tok_flag); /* Flagged token
755
corresponds to a |text_pointer|; |*t|~points to beginning of translation. */
756
tok_value = first_id(t);// Check that translation recursively.
757
if(tok_value) return tok_value;
761
return 0; // Really couldn't find anything!
764
@ In the following situations we want to mark the occurrence of an
765
identifier as a definition: when |make_reserved| has just been used; after
766
a specifier, as in |char **argv|; before a colon, as in |found:|; and in
767
the declaration of a function, as in |main(){@t\dots@>;}|. This is
768
accomplished by the invocation of |make_underlined| at appropriate times.
769
Since, in the declaration of a function, we only find out that the
770
identifier is being defined after it has been swallowed up by an |expr|, we
771
must hunt through an indirection chain.
776
make_underlined FCN((p)) /* underline the entry for the first
777
identifier in |p->trans| */
778
scrap_pointer p C1("")@;
780
sixteen_bits tok_value; /* the name of this identifier, plus its flag */
782
tok_value=**(p->trans);
784
if (tok_value>inner_tok_flag) tok_value-=(inner_tok_flag-tok_flag);
786
if (tok_value>tok_flag) {
788
{ /* Follow an indirection chain to a real identifier. {\bf
789
Watch the 16-bit arithmetic!} */
790
tok_value=**(tok_start +
791
(int)(tok_value-tok_flag)); /* {\bf Don't
792
remove the parens!} */
794
while(tok_value > tok_flag);
796
if (tok_value<id_flag || tok_value>=res_flag) return NULL; /* shouldn't
799
xref_switch=def_flag; underline_xref(tok_value-id_flag+name_dir);
802
if (tok_value<id_flag || tok_value>=res_flag) return NULL;
805
xref_switch=def_flag; return underline_xref(tok_value-id_flag+name_dir);
808
@ We cannot use |new_xref| to underline a cross-reference at this point
809
because this would just make a new cross-reference at the end of the list.
810
We actually have to search through the list for the existing
816
underline_xref FCN((p))
817
name_pointer p C1("")@;
819
xref_pointer q = (xref_pointer)p->xref; /* Pointer to cross-reference
821
xref_pointer r; /* Temporary pointer for permuting cross-references */
822
sixteen_bits m; /* Cross-reference value to be installed */
823
sixteen_bits n; /* Cross-reference value being examined */
824
extern boolean strt_off;
826
if (no_xref || (strt_off && !index_hidden))
829
xref_switch = def_flag;
830
m = (sixteen_bits)(module_count + xref_switch);
836
if (n==m) return p; /* Same status; need to do nothing. */
837
else if (m==n+def_flag) /* Module numbers match; update to
842
else if (n>=def_flag && n<m) break;
847
@<Insert new cross-reference at |q|, not at beginning of list@>;
852
@ Record the module at which an identifier was defined. A global variable
853
distinguishes between |INNER| and |OUTER| modes.
857
IN_PROD PARSING_MODE translate_mode; // Set by |translate|.
864
name_pointer p C1("")@;
866
extern boolean ok_to_define;
868
if(ok_to_define && translate_mode==OUTER && p > name_dir)
870
sixteen_bits mod_defined = p->defined_in(language);
872
if(mod_defined && mod_defined != module_count && language!=C_PLUS_PLUS)
874
if(msg_level >= WARNINGS)
876
printf("\n! (FWEAVE): Implicit phase 2 declaration of `");
879
repeats or conflicts with declaration at %s.\n",
880
(char *)MOD_TRANS(module_count),
881
(char *)MOD_TRANS(mod_defined));
886
else if(mark_defined.fcn_name)
888
p->defined_in(language) = module_count;
889
SET_TYPE(p,FUNCTION_NAME);
894
@ We get to this module only when the identifier is one letter long, so it
895
didn't get a non-underlined entry during phase one. But it may have got
896
some explicitly underlined entries in later modules, so in order to
897
preserve the numerical order of the entries in the index, we have to insert
898
the new cross-reference not at the beginning of the list (namely, at
899
|p->xref|), but rather right before~|q|.
901
@<Insert new cross-reference at |q|...@>=
903
append_xref(0); /* This number doesn't matter */
904
xref_ptr->xlink = (xref_pointer)p->xref;
905
r = xref_ptr; p->xref = (ASCII *)xref_ptr;
907
while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;}
909
r->num=m; /* Everything from |q| on is left undisturbed */
911
@ Now comes the code that tries to match each production that starts with a
912
particular type of scrap. Whenever a match is discovered, the |squash| or
913
|reduce| procedures will cause the appropriate action to be performed,
914
followed by |goto found|.
923
@d indent_force b_app(indent); @~ b_app(force)@;
925
/* Append $m$~things, followed by a space, followed by $n$~things. */
926
@m PP_PP(m,n) b_app##m(pp); @~ b_app(@' '); @~ b_app##n(pp+m)@;
928
@<CASES for |ignore_scrap| (C)@>=
933
@<Cases for |ignore_scrap| (C)@>@;
940
@[SRTN C_ignore_scrap(VOID)
942
@<Cases for |ignore_scrap| (C)@>@;
947
@<Cases for |ignore_scrap| (C)@>=
953
SQUASH(pp,2,cat1,0,1);
958
@ Ordinary expressions.
959
@<CASES for |expr| (C)@>=
963
@<Cases for |expr| (C)@>@;
971
@<Cases for |expr| (C)@>@;
977
@d OPT9 APP_SPACE; app(opt); app(@'9')@;
979
@<Cases for |expr| (C)@>=
981
if (cat1==lbrace || ((!Cpp) && cat1==int_like))
982
{ /* ``|f(x) {}|'' or ``|f(x) float x;|'' (old-style) */
983
defined_at(make_underlined(pp)); /* Recognized function name;
984
remember current module number. */
986
SQUASH(pp, 1, fn_decl, 0, 111);
989
SQUASH(pp,2,expr,-2,2); /* ``|x--|'' */
990
else if (cat1==binop)
993
SQUASH(pp,3,expr,-2,3); /* ``|x + y|'' */
994
else if(cat2==decl_hd)
995
SQUASH(pp, 3, tstart, 0, 6061);
996
/* Trap for ``|@c++ A<int>|'', with |A| undefined. */
998
else if (cat1==unorbinop && cat2==expr)
1000
sixteen_bits *s = *(pp+1)->trans;
1003
/* If the translation of the next scrap begins with an escape character, we
1004
assume we're seeing \.{\\amp}. */
1005
if( (s[0] == (sixteen_bits)@'\\') && s[1] == (sixteen_bits)@'a'
1006
&& s[2] == (sixteen_bits)@'m')
1008
APP_SPACE; b_app1(pp+1); @~ APP_SPACE; /* ``|x & y|'' */
1010
else b_app1(pp+1); /* ``|x*y|'' */
1013
REDUCE(pp,3,expr,-2,3000);
1015
else if (cat1==comma)
1017
if((cat2==expr || cat2==int_like)) /* ``|x,y|'' or ``|x,char|'' */
1021
b_app1(pp+2); REDUCE(pp,3,cat2,-2,4);
1023
else if(cat2==space)
1024
SQUASH(pp, 3, expr, -2, 88); // Macros.
1026
else if (cat1==expr)
1027
SQUASH(pp,2,expr,-2,5); /* ``|f(x)|'' */
1028
else if (cat1==semi)
1029
SQUASH(pp,2,stmt,-1,6); /* ``|x;|'' */
1030
else if (cat1==colon) /* ``|label:|'' */
1032
if(!Cpp || in_function)
1033
{ /* Ordinary C tag. */
1034
make_underlined (pp); /* Label name. */
1035
SQUASH(pp,2,tag,0,7);
1037
else if(cat2==expr || cat2==int_like)
1038
{ /* Put the spaces in explicitly in case we're not in math
1039
mode at the time. */
1040
b_app1(pp); @~ b_app(@' '); @~ b_app1(pp+1); @~ b_app(@' ');
1042
REDUCE(pp,3,expr,-2,701);
1043
/* \Cpp: ``|@c++ derived() : base()|'' */
1046
else if(cat1==space)
1047
SQUASH(pp,2,expr,-2,8); /* For use in macros. */
1050
@ The next several cases are for symbols that are formatted like operators.
1051
These need to get explicit spaces to set them off from their surroundings.
1053
@<Bracket with spaces@>=
1055
APP_SPACE; @~ b_app1(pp); @~ APP_SPACE;
1057
@ Name as unary operator: ``\.{\$UNOP\_\ }''.
1058
@<CASES for |UNOP| (C)@>=
1062
@<Cases for |UNOP| (C)@>@;
1070
@<Cases for |UNOP| (C)@>@;
1075
@<Cases for |UNOP| (C)@>=
1077
b_app1(pp); @~ APP_SPACE;
1078
REDUCE(pp,1,unop,-1,4443);
1081
@ Name as binary operator: ``\.{\ \$\_BINOP\_\ }''.
1082
@<CASES for |BINOP| (C)@>=
1086
@<Cases for |BINOP| (C)@>@;
1092
@[SRTN C_BINOP(VOID)
1094
@<Cases for |BINOP| (C)@>@;
1099
@<Cases for |BINOP| (C)@>=
1101
@<Bracket with spaces@>;
1102
REDUCE(pp,1,binop,-1,4444);
1105
@ Name as comma: ``\.{\ \$\_COMMA\_\ }''.
1106
@<CASES for |COMMA| (C)@>=
1110
@<Cases for |COMMA| (C)@>@;
1116
@[SRTN C_COMMA(VOID)
1118
@<Cases for |COMMA| (C)@>@;
1123
@<Cases for |COMMA| (C)@>=
1125
@<Bracket with spaces@>;
1126
REDUCE(pp,1,comma,-1,4445);
1129
@ Expression with space to left: ``\.{\ \$\_EXPR}''.
1130
@<CASES for |_EXPR| (C)@>=
1134
@<Cases for |_EXPR| (C)@>@;
1142
@<Cases for |_EXPR| (C)@>@;
1147
@<Cases for |_EXPR| (C)@>=
1149
APP_SPACE; @~ b_app1(pp);
1150
REDUCE(pp,1,expr,-2,4446);
1153
@ Expression with spaces on both sides: ``\.{\ \$\_EXPR\_\ }''.
1154
@<CASES for |_EXPR_| (C)@>=
1158
@<Cases for |_EXPR_| (C)@>@;
1166
@<Cases for |_EXPR_| (C)@>@;
1171
@<Cases for |_EXPR_| (C)@>=
1173
@<Bracket with spaces@>;
1174
REDUCE(pp,1,expr,-2,4447);
1177
@ Expression with space to right: ``\.{\$EXPR\_\ }''.
1178
@<CASES for |EXPR_| (C)@>=
1182
@<Cases for |EXPR_| (C)@>@;
1190
@<Cases for |EXPR_| (C)@>@;
1195
@<Cases for |EXPR_| (C)@>=
1197
b_app1(pp); @~ APP_SPACE;
1198
REDUCE(pp,1,expr,-2,4448);
1201
@ There are right and wrong ways of inserting a real space. What we want to
1202
do is to insert the macro \.{\\\ } (which works either in or out of math mode)
1203
without changing the mathness.
1205
@d APP_SPACE APP_STR("\\ ")
1207
@ The next stuff handles C~preprocessing (not very well).
1210
IN_PROD boolean active_space PSET(NO);
1211
IN_PROD boolean in_LPROC PSET(NO);
1212
IN_PROD boolean expanded_lproc PSET(NO);
1214
@ In \Cpp, the syntax for |new| and |delete| is unusual.
1215
@<CASES for |new_like| (C)@>=
1219
@<Cases for |new_like| (C)@>@;
1225
@[SRTN C_new_like(VOID)
1227
@<Cases for |new_like| (C)@>@;
1232
@<Cases for |new_like| (C)@>=
1234
if(cat1==lbracket && cat2==rbracket)
1235
{ /* |@c++ delete [] expr| */
1236
PP_PP(1, 1); @~@<Append thickspace@>; @~ b_app1(pp+2);
1238
REDUCE(pp, 3, expr, -2, 910);
1240
else if(cat1==decl_hd || cat1==expr)
1241
{ /* \Cpp: |@c++ new int| or |@c++ new class(20)| */
1247
REDUCE(pp,2,expr,-2,909);
1251
@ The \CWEB\ code didn't work right here. The present attempt is a mess.
1253
@<CASES for |lproc| (C)@>=
1257
@<Cases for |lproc| (C)@>@;
1263
@[SRTN C_lproc(VOID)
1265
@<Cases for |lproc| (C)@>@;
1269
@ |lproc| signals the beginning of a preprocessor statement. |rproc|
1274
extern boolean did_arg;
1277
@<Cases for |lproc| (C)@>=
1279
expanded_lproc = YES;
1284
if(cat1==define_like)
1285
make_underlined(pp+3); /* ``\.{\#\ define\ M}'' */
1287
if (cat1==else_like || cat1==if_like ||cat1==define_like)
1288
SQUASH(pp, 2, lproc, 0, 10); /* ``\.{\#\ define}'' $\to$
1290
else if (cat1==rproc)
1292
expanded_lproc = active_space = in_LPROC = NO;
1293
SQUASH(pp, 2, ignore_scrap, -1, 11);
1297
SQUASH(pp, 1, LPROC, 0, 12); /* ``|#if(0)|'' (??) */
1306
b_app(@' '); /* ``|#define x|'' */
1310
REDUCE(pp, 2, LPROC, 0, 12);
1312
else if (cat1==space)
1315
SQUASH(pp, 1, lproc, PLUS 2, 1332); // \.{if\ (x)}
1316
/* Following stuff for \&{\#define}.
1317
Absorb the identifier: ``\&{\#define M}'' */
1319
SQUASH(pp,1,lproc,PLUS 3,1333); /* Expand the parens. */
1321
SQUASH(pp,4,LPROC,0,13); /* |expr| should be
1322
``|()|''; get them too. */
1323
else if(cat3==space || cat3==ignore_scrap || cat3==rproc)
1324
SQUASH(pp,3,LPROC,0,14); /* Just the identifier. */
1326
expanded_lproc = NO;
1330
@<CASES for |LPROC| (C)@>=
1334
@<Cases for |LPROC| (C)@>@;
1342
@<Cases for |LPROC| (C)@>@;
1347
@<Cases for |LPROC| (C)@>=
1349
active_space = NO; in_LPROC = YES;
1355
REDUCE(pp, 2, LPROC, 0, 20);
1357
else if(!did_arg && cat1==expr)
1359
SQUASH(pp, 2, LPROC, 0, 24);
1362
else if(cat1==rproc)
1365
SQUASH(pp, 2, ignore_scrap, -1, 21);
1367
else if(cat2==rproc)
1370
SQUASH(pp, 3, ignore_scrap, -1, 22);
1374
if(cat3==lpar && cat4==expr && cat5==rpar)
1377
b_app1(pp); b_app(@' '); b_app2(pp+1);
1378
REDUCE(pp,3,ignore_scrap,-1,53);
1380
else if (cat2==expr && cat3==rproc)
1382
b_app1(pp); b_app(@' '); b_app1(pp+1); b_app(@' ');
1383
b_app2(pp+2); REDUCE(pp,4,ignore_scrap,-1,53);
1389
@<CASES for |space| (C)@>=
1393
@<Cases for |space| (C)@>@;
1399
@[SRTN C_space(VOID)
1401
@<Cases for |space| (C)@>@;
1406
@<Cases for |space| (C)@>=
1411
SQUASH(pp,1,space,-1,5336);
1413
SQUASH(pp,1,space,1,5335);
1416
REDUCE(pp,1,ignore_scrap,-1,5334);
1420
@<CASES for |question| (C)@>=
1424
@<Cases for |question| (C)@>@;
1430
@[SRTN C_question(VOID)
1432
@<Cases for |question| (C)@>@;
1437
@<Cases for |question| (C)@>=
1439
if (cat1==expr && cat2==colon) SQUASH(pp,3,binop,-2,30); /* ``|i==1 ? YES :
1444
@<CASES for |int_like| (C)@>=
1448
@<Cases for |int_like| (C)@>@;
1454
@[SRTN C_int_like(VOID)
1456
@<Cases for |int_like| (C)@>@;
1461
@<Cases for |int_like| (C)@>=
1465
if(cat2==expr || cat2==int_like)
1466
SQUASH(pp,3,expr,-2,35); /* \Cpp: |@c++ class::f| or
1467
constructor: |@c++ class::class| */
1468
else if(cat2==op_like)
1469
SQUASH(pp,1,int_like,PLUS 2,36); /* \Cpp: Expand |@c++ operator|
1472
else if (cat1==int_like|| cat1==struct_like)
1473
{ /* ``|extern int|'' or ``|@c++ typedef int bool|''. */
1475
REDUCE(pp,2,cat1,0,40);
1477
else if(cat1==reference)
1478
SQUASH(pp, 2, int_like, -2, 43); // |@c++ int &ref;|
1479
else if (cat1==expr || cat1==unorbinop || cat1==semi)
1480
{ /* ``|int i|'' or ``|int *|'' */
1487
INDENT; /* Start long declaration. (Note: Whenever we leave
1488
|decl_hd|, we must |OUTDENT|.) */
1491
REDUCE(pp,1,decl_hd,-1,41);
1493
else if(cat1==comma)
1499
REDUCE(pp,1,decl_hd,-2,42); /* Function prototype: |int,|. */
1507
REDUCE(pp,1,decl_hd,-2,502);
1509
else if(Cpp && cat1==lpar && !in_prototype)
1510
{ // The \Cpp\ is a KLUDGE. Consider ``|int (*f)()|''.
1512
@<Append thinspace@>@;
1513
REDUCE(pp,1,expr,-2,5021); /* \Cpp\ constructor: ``|@c++ base()|'';
1514
or ``|@c++ int(x)|''. */
1516
else if(cat1==binop && cat2==expr)
1517
SQUASH(pp,3,int_like,-2,5022); /* \Cpp\ initializer: |@c++ base = 0| */
1518
else if(cat1 == langle)
1519
SQUASH(pp, 1, int_like, PLUS 1, 5997); // |@c++ int<24>|
1520
else if(cat1 == rangle)
1526
REDUCE(pp,1,decl_hd,-2,5998);
1528
else if(cat1 == class_like)
1529
{ // \Cpp: |@c++ friend class|.
1531
REDUCE(pp, 2, class_like, 0, 5995);
1533
else if(cat1 == tlist)
1534
SQUASH(pp, 2, int_like, -2, 5999);
1535
else if(cat1 == namespace)
1536
{ /* |@c++ using namespace| */
1538
REDUCE(pp, 2, namespace, 0, 5996);
1542
@ We need a special case for |extern|, because of constructions like |@c+
1543
extern "C"| in \Cpp.
1545
@<CASES for |extern_like| (C)@>=
1549
@<Cases for |extern_like| (C)@>@;
1555
@[SRTN C_ext_like(VOID)
1557
@<Cases for |extern_like| (C)@>@;
1562
@<Cases for |extern_like| (C)@>=
1564
if(Cpp &&cat1==expr)
1565
{ /* |@c++ extern "C"| */
1567
if(cat2==lbrace || cat2==kill_newlines)
1568
REDUCE(pp, 2, fn_decl, 0, 5025); // ``|@c++ extern "C" {}|''.
1570
REDUCE(pp, 2, int_like, 0, 5023);
1571
// ``|@c++ extern "C" int fcn();|''
1574
SQUASH(pp,1,int_like,0,5024);
1577
@ A case related but not identical to |int_like| is |modifier|, which is
1578
used for things like |const| and |volatile|. The difficulty is that it may
1579
come first in the declaration, but it need not. Compare |const char c| and
1580
|char const c|; also |char *const p| and |const char *p|.
1582
@<CASES for |modifier| (C)@>=
1586
@<Cases for |modifier| (C)@>@;
1592
@[SRTN C_modifier(VOID)
1594
@<Cases for |modifier| (C)@>@;
1599
@<Cases for |modifier| (C)@>=
1601
if(cat1==int_like || cat1==struct_like || cat1==class_like)
1602
SQUASH(pp, 1, cat1, -2, 503);
1603
else if(pp == lo_ptr)
1604
SQUASH(pp, 1, expr, 0, 5040);
1605
else if(cat1==comma || cat1==semi || cat1==lbrace || cat1==kill_newlines)
1606
SQUASH(pp, 1, _EXPR, 0, 5042);
1607
/* |@c++ int f() const, g();| or @c++ int f() const;| or
1608
|@c++ int f() const {}|. */
1610
SQUASH(pp, 1, EXPR_, 0, 5041);
1613
@ Personal computers have a strange syntax with the |HUGE| operator. We
1614
must deal with declarations such as |char HUGE *p;|.
1615
@<CASES for |huge_like| (C)@>=
1619
@<Cases for |huge_like| (C)@>@;
1625
@[SRTN C_huge_like(VOID)
1627
@<Cases for |huge_like| (C)@>@;
1632
@<Cases for |huge_like| (C)@>=
1636
b_app1(pp); @~ APP_SPACE; @~ b_app1(pp+1);
1637
REDUCE(pp,2,unorbinop,-1,505);
1642
@<CASES for |virtual| (C++)@>=
1646
@<Cases for |virtual| (C++)@>@;
1652
@[SRTN C_virtual(VOID)
1654
@<Cases for |virtual| (C++)@>@;
1659
@<Cases for |virtual| (C++)@>=
1664
APP_SPACE; // |@c++ virtual ~base();|
1666
REDUCE(pp,1,int_like,0,506);
1670
@<CASES for |reference| (C++)@>=
1674
@<Cases for |reference| (C++)@>@;
1680
@[SRTN C_reference(VOID)
1682
@<Cases for |reference| (C++)@>@;
1686
@ If we can't figure out that an ampersand is a reference, treat it just
1688
@<Cases for |reference| (C++)@>=
1690
SQUASH(pp, 1, unorbinop, -1, 507);
1693
@ With the advent of ANSI~C, we have to deal with function prototypes,
1694
which look very much like casts.
1696
@d INDENT if(!indented)
1702
@d OUTDENT if(indented)
1710
IN_PROD int in_prototype PSET(NO);
1711
// This is used as a numerical counter.
1712
IN_PROD int indented PSET(NO);
1714
@ For \Cpp, it becomes necessary to know whether one is inside or outside
1719
IN_PROD boolean in_function PSET(NO);
1721
@ A |decl_hd| is something like ``|int i|''.
1723
@<CASES for |decl_hd| (C)@>=
1727
@<Cases for |decl_hd| (C)@>@;
1733
@[SRTN C_decl_hd(VOID)
1735
@<Cases for |decl_hd| (C)@>@;
1740
@<Cases for |decl_hd| (C)@>=
1744
if((pp-1)->cat==lpar)
1745
SQUASH(pp,1,decl_hd,-1,4990); // ``|(int i)|''.
1746
else if((pp-2)->cat==decl_hd)
1747
SQUASH(pp,1,decl_hd,-2,4991); // ``|(int i, int j)|''.
1748
else if((pp-3)->cat==decl_hd)
1749
SQUASH(pp, 1, decl_hd, -3, 4992);
1751
else if(cat1==decl_hd)
1752
SQUASH(pp,2,decl_hd,0,50); // ``|(int,int)|''
1753
else if(cat1==comma)
1756
{ /* For function prototype. */
1757
b_app2(pp); @~ OPT9;
1759
REDUCE(pp,3,decl_hd,0,501);
1761
else if(cat2==ignore_scrap && cat3==decl_hd)
1762
{ /* For function prototype with comment. */
1763
b_app2(pp); @~ OPT9;
1765
REDUCE(pp,4,decl_hd,0,504);
1768
else if(Cpp && (cat2==decl || cat2==stmt))
1769
SQUASH(pp, 3, stmt, -2, 508);
1770
/* ``|@c++ for(int i=0, int j=0;;)|'' or ``|@c++
1771
for(int i=0, int j=0, int k=0;;)|''. */
1774
{ /* ``|int i,|'' */
1775
if(cat2==ignore_scrap && (cat3==int_like || cat3==struct_like ||
1777
{/* Function prototype, with intervening comment. */
1779
if((pp-3)->cat != decl_hd && (pp-2)->cat != decl_hd
1780
&& cat3 != modifier)
1782
REDUCE(pp,1,decl_hd,PLUS 3,5221);
1784
else if(cat2==int_like || cat2==struct_like || cat2==modifier)
1785
{ /* Function prototype. */
1787
if((pp-3)->cat != decl_hd && (pp-2)->cat != decl_hd
1788
&& cat2 != modifier)
1789
in_prototype++; /* The |modifier| clause is to
1790
prevent a situation like |(int, const int)| from thinking it's two levels
1792
REDUCE(pp,1,decl_hd,PLUS 2,52);
1795
{ /* Expecting list of something. */
1796
b_app2(pp); app(@'~');
1800
REDUCE(pp, 2, decl_hd, -2, 540);
1801
// ``|@c++ int i=0, int j=0|'' (e.g., in |for|)
1804
REDUCE(pp,2,decl_hd,-1,54); // ``|int i,j|''
1808
else if (cat1==unorbinop)
1809
{ /* ``|int **p|'' */
1814
REDUCE(pp,2,decl_hd,-1,55);
1816
else if (cat1==expr)
1817
{ /* ``|int i|'' or ``|int i, j|'' */
1818
make_underlined(pp+1);
1819
SQUASH(pp,2,decl_hd,-1,56); /* The |-1| is to pick up a left
1820
paren for function prototype. */
1822
else if ((cat1==binop||cat1==colon
1823
||cat1==expr /* (for initializations) */
1824
) && cat2==expr && (cat3==comma || cat3==semi || cat3==rpar))
1829
REDUCE(pp,3,decl_hd,-1,5660);
1833
SQUASH(pp,3,decl_hd,-1,5661);
1834
else if(cat1==int_like && (cat2==unop || cat2==langle))
1835
SQUASH(pp, 1, decl_hd, PLUS 1, 5662);
1836
/* \Cpp: ``|@c++ void *int::fcn()|'' or ``|@c++ void
1837
*int<int>::fcn()|'' */
1838
else if (cat1==lbrace || (cat1==int_like &&
1839
((pp-1)->trans == NULL || **(pp-1)->trans != @'('))) /*
1840
Recognize beginning of function: ``|float f() {}|'' or ``|float f(x) float
1848
defined_at(FIRST_ID(pp));
1849
REDUCE(pp,1,fn_decl,0,58);
1851
else if (cat1==semi)
1852
{ /* ``|int i;|'' */
1855
OUTDENT; /* Finish long declaration. */
1859
REDUCE(pp, 2, decl, -2, 594);
1860
// ``|@c++ for(int i=0, int j=0;;)|''
1863
REDUCE(pp,2,decl,-1,59);
1865
else if(Cpp && cat1==int_like && cat2==unop)
1866
SQUASH(pp,1,decl_hd,PLUS 1,590); /* \Cpp: |@c++ void *class::f| */
1867
else if(Cpp && cat1 == rangle)
1868
SQUASH(pp, 1, decl_hd, -2, 591); /* \Cpp: end of template. */
1869
else if(Cpp && cat1 == struct_like)
1870
SQUASH(pp, 2, decl_hd, -1, 593);
1871
/* \Cpp: |@c++ template<class C1, class C2>|. */
1874
@ A |decl| is a |decl_hd| followed by a semicolon---i.e., a complete
1877
@<CASES for |decl| (C)@>=
1881
@<Cases for |decl| (C)@>@;
1889
@<Cases for |decl| (C)@>@;
1894
@<Cases for |decl| (C)@>=
1900
b_app1(pp); @~ b_app(big_force);
1902
REDUCE(pp,2,functn,-1,61);
1905
SQUASH(pp,1,stmt,-1,611); // E.g., ``|@c++ for(int i=0;;)|''
1910
{ /* ``|int i; float x;|'' */
1911
b_app1(pp); @~ b_app(force);
1913
REDUCE(pp,2,decl,-1,60);
1915
else if (cat1==stmt || cat1==functn)
1916
{ /* ``|int i; x=0;|'' or ``|int i; f(){}|'' */
1917
b_app1(pp); @~ b_app(big_force);
1919
REDUCE(pp,2,cat1,-1,61);
1924
@ A |fn_decl| is the beginning of a function.
1926
@<CASES for |fn_decl| (C)@>=
1930
@<Cases for |fn_decl| (C)@>@;
1936
@[SRTN C_fn_decl(VOID)
1938
@<Cases for |fn_decl| (C)@>@;
1943
@<Cases for |fn_decl| (C)@>=
1945
if(cat1 == semi && Cpp)
1946
{ /* |@c++ using namespace X;| */
1948
REDUCE(pp, 2, stmt, -1, 72);
1950
else if (cat1==decl)
1951
{ /* ``|f(x) float x;|'' */
1953
b_app(indent); @~ indent_force;
1954
b_app1(pp+1); /* Accrete old-style declarations. */
1955
b_app(outdent); @~ b_app(outdent);
1956
REDUCE(pp,2,fn_decl,0,70);
1958
else if (cat1==stmt)
1961
b_app(backup); /* Beginning of function. */
1963
b_app1(pp); @~ b_app(force);
1965
b_app1(pp+1); /* Function body */
1967
in_function = kill_nl = NO;
1968
REDUCE(pp,2,functn,-1,71);
1972
@ Deal with a complete function. Handle ``|f(){} g(){}|'' or ``|f(){}
1974
@<CASES for |functn| (C)@>=
1978
@<Cases for |functn| (C)@>@;
1984
@[SRTN C_functn(VOID)
1986
@<Cases for |functn| (C)@>@;
1990
@ The |stmt| clause takes care of \Cpp\ constructions like |@c++ try{}
1992
@<Cases for |functn| (C)@>=
1994
if (cat1==functn || cat1==decl || cat1==stmt)
1996
b_app1(pp); @~ b_app(big_force);
1997
b_app1(pp+1); REDUCE(pp,2,cat1,-1,80); /* |-1| for \Cpp */
2001
@ Handle syntaxes like ``|typedef int I;|'' or ``|typedef int
2003
@<CASES for |typedef_like| (C)@>=
2007
@<Cases for |typedef_like| (C)@>@;
2013
@[SRTN C_typedef_like(VOID)
2015
@<Cases for |typedef_like| (C)@>@;
2022
IN_PROD boolean typedefing PSET(NO); // Are we inside a |typedef|?
2025
@<Cases for |typedef_like| (C)@>=
2027
if (cat1==decl_hd && (cat2==expr || cat2 == int_like))
2029
make_underlined(pp+2); make_reserved(pp+2); /* NEEDS TO BE IMPROVED! */
2031
REDUCE(pp+1,2,decl_hd,0,90);
2036
REDUCE(pp,2,decl,-1,91);
2039
SQUASH(pp, 2, stmt, -1, 94);
2040
/* ``|typedef|''. */
2044
REDUCE(pp, 2, stmt, -1, 95);
2045
/* ``|typedef int I[3]|''. (|I| is defined in first pass.) */
2051
@<CASES for |imp_reserved| (C)@>=
2055
@<Cases for |imp_reserved| (C)@>@;
2061
@[SRTN C_imp_reserved(VOID)
2063
@<Cases for |imp_reserved| (C)@>@;
2067
@ The special type |imp_reserved| is needed for forward referencing, but
2068
when it's encountered within a |typedef| it should be interpreted as an
2070
@<Cases for |imp_reserved| (C)@>=
2072
if(typedefing) SQUASH(pp,1,expr,-2,92);
2073
else SQUASH(pp,1,int_like,-2,93);
2076
@ In \Cpp, operator overloading has a somewhat unusual syntax, in that
2077
constructions like |operator -=| plays the role of a function name.
2079
@d MAX_OP_TOKENS 5 /* Maximum \# of tokens that could conceivably make up
2080
the function name. */
2082
@<CASES for |op_like| (C)@>=
2086
@<Cases for |op_like| (C)@>@;
2092
@[SRTN C_op_like(VOID)
2094
@<Cases for |op_like| (C)@>@;
2099
@<Cases for |op_like| (C)@>=
2102
// The actual number of tokens that make up the effective function name.
2104
if((cat1==lpar && cat2==rpar) || (cat1==lbracket && cat2==rbracket))
2105
{ /* |@c++ operator ()()| is a special case because it begins with
2106
left paren. |@c++ operator []()| is handled as a special case because we
2107
now have the categories |lbracket| and |rbracket|, and |lbracket| doesn't
2108
regress when it's reduced to |lpar|. */
2109
APP_STR("\\Woperator");
2111
b_app1(pp+1); // |lpar| or |lbracket|
2112
@<Append thinspace@>@;
2113
b_app1(pp+2); // |rpar| or |rbracket|
2118
{ /* We'll search for the obligatory left paren that indicates the
2121
int k; /* Counter. */
2123
/* If the paren is missing, we could end up appending the entire rest of
2124
the code, so we limit the search. */
2125
for(q = pp+1; q <= scrp_ptr && q-pp <= MAX_OP_TOKENS; q++)
2129
n = (q->cat == lpar) ? PTR_DIFF(short, q, pp) : 0;
2131
/* Append all the tokens between |operator| and left paren. */
2135
token_pointer tp,tp1;
2138
b_app1(pp); // |@c++ operator|; really \.{\\Woperator}.
2139
b_app(@'{'); /* Braces prevent possible spurious blanks
2140
before the left paren. */
2142
APP_STR("\\Woperator");
2145
id_first = id_loc = mod_text + 1;
2151
xp = indirect((pp+k)->trans);
2155
*id_loc++ = (ASCII)(*tp++);
2158
underline_xref(id_lookup(id_first,id_loc,0));
2165
REDUCE(pp, n, expr, -2, 6666);
2168
APP_STR("\\Woperatoro");
2169
REDUCE(pp, 1, expr, -2, 6668);
2173
@ |@c++ class| is almost like |struct|, but it has to reserve the class name.
2174
(Note that it might have been declared earlier, hence the |int_like| option.)
2176
@<CASES for |class_like| (C)@>=
2180
@<Cases for |class_like| (C)@>@;
2186
@[SRTN C_class_like(VOID)
2188
@<Cases for |class_like| (C)@>@;
2193
@<Cases for |class_like| (C)@>=
2195
if(cat1==expr || cat1==int_like)
2196
{ /* \Cpp: |@c++ class A| */
2197
make_underlined(pp+1); @~ make_reserved(pp+1);
2201
if((pp-1)->cat == tstart || (pp-1)->cat == decl_hd
2202
|| (pp-1)->cat == lpar)
2203
REDUCE(pp, 2, decl_hd, -1, 8998);
2205
REDUCE(pp, 2, struct_like, 0, 8999);
2207
else if(cat1==lbrace)
2208
SQUASH(pp, 1, struct_like, 0, 8987);
2209
// |@c++ class{}| or |@c++ struct{}|.
2212
@ Deal with beginning of a structure.
2214
@<CASES for |struct_like| (C)@>=
2218
@<Cases for |struct_like| (C)@>@;
2224
@[SRTN C_struct_like(VOID)
2226
@<Cases for |struct_like| (C)@>@;
2234
@<Cases for |struct_like| (C)@>=
2237
{ /* ``|struct {int i;} S;|'' or \Cpp: ``|@c++ class A{int i;};|'' */
2238
b_app1(pp); @~ indent_force;
2239
b_app1(pp+1); REDUCE(pp,2,struct_hd,0,100);
2241
else if (cat1==expr)
2242
{ /* Structure name: ``|struct s|'' */
2243
if (cat2==lbrace) /* ``|struct s {}|'' */
2245
/* In \Cpp, this construction defines a new type. */
2247
{make_underlined(pp+1); @~ make_reserved(pp+1);}
2252
REDUCE(pp,3,struct_hd,0,101);
2255
{ /* ``|struct s ss|'' */
2257
REDUCE(pp,2,int_like,-1,102);
2260
else if(cat1==colon && cat2==int_like && Cpp)
2261
{ /* |@c++ class A: base| */
2263
SQUASH(pp, 1, struct_like, PLUS 3, 1023);
2266
b_app1(pp); @~ b_app(@' '); @~ b_app1(pp+1); @~ b_app(@' '); @~
2268
REDUCE(pp,3,struct_like,0,1021);
2271
else if(cat1==comma && cat2==int_like && Cpp)
2272
{ /* |@c++ class A: base, base | */
2274
SQUASH(pp, 1, struct_like, PLUS 3, 1024);
2278
REDUCE(pp,3,struct_like,0,1022);
2281
else if(cat1==tlist)
2282
SQUASH(pp, 2, struct_like, 0, 1025); // \Cpp: |@c++ class A<int>|.
2284
SQUASH(pp,2,decl,-1,103); /* \Cpp: |@c++ class base;| */
2285
else if(cat1 == rangle)
2286
SQUASH(pp, 1, decl_hd, -2, 592); /* \Cpp: end of template. */
2289
@ Handle ``|enum{red,yellow}|;''.
2290
@<CASES for |struct_hd| (C)@>=
2294
@<Cases for |struct_hd| (C)@>@;
2300
@[SRTN C_str_hd(VOID)
2302
@<Cases for |struct_hd| (C)@>@;
2307
@<Cases for |struct_hd| (C)@>=
2309
if ((cat1==decl || cat1==stmt
2310
|| cat1==expr /* (For enum) */
2311
|| cat1==functn /* \Cpp */
2314
b_app1(pp); /* ``|struct {|'' */
2316
b_app1(pp+2); /* ``|}|'' */
2321
REDUCE(pp,3,int_like,-1,110);
2323
else if(cat1==rbrace)
2325
b_app1(pp); @~ @<Append thin...@>@; b_app1(pp+1);
2327
REDUCE(pp,2,int_like,-1,1101);
2332
@<CASES for |lpar| (C)@>=
2336
@<Cases for |lpar| (C)@>@;
2344
@<Cases for |lpar| (C)@>@;
2349
@<Cases for |lpar| (C)@>=
2351
if (cat2==rpar && (cat1==expr || cat1==unorbinop))
2352
SQUASH(pp,3,expr,-2,120); /* ``|(x)|'' or ``|(*)|''*/
2353
else if (cat1==rpar)
2354
{ /* ``|()|''. This looks better with a bit of extra space between
2356
b_app1(pp); @~ @<Append thickspace@>; @~ b_app1(pp+1);
2357
REDUCE(pp,2,expr,-2,121);
2359
else if ((cat1==decl_hd) && cat2==rpar)
2360
{ /* Function prototype or cast, like ``|typedef (*T)|'' where |T|
2361
was |typedef|d on the first pass. */
2369
REDUCE(pp,3,cast,-1,122);
2371
else if (cat1==stmt)
2372
{ /* ``|for(x;y;z)|'' */
2373
b_app2(pp); b_app(@' '); REDUCE(pp,2,lpar,0,123);
2375
else if(cat1==for_like && cat2==rpar)
2376
SQUASH(pp,3,expr,-2,1201); /* Macros: |(for)| */
2380
@<CASES for |lbracket| (C)@>=
2384
@<Cases for |lbracket| (C)@>@;
2390
@[SRTN C_lbracket(VOID)
2392
@<Cases for |lbracket| (C)@>@;
2397
@<Cases for |lbracket| (C)@>=
2406
REDUCE(pp,1,lpar,0,5000);
2410
@<CASES for |rbracket| (C)@>=
2414
@<Cases for |rbracket| (C)@>@;
2420
@[SRTN C_rbracket(VOID)
2422
@<Cases for |rbracket| (C)@>@;
2427
@<Cases for |rbracket| (C)@>=
2431
text_pointer t = indirect(pp->trans);
2433
if(**t == @']') **t = @'}';
2438
REDUCE(pp,1,rpar,-5,5001);
2442
@<CASES for |kill_newlines| (C++)@>=
2446
@<Cases for |kill_newlines| (C++)@>@;
2452
@[SRTN C_killnl(VOID)
2454
@<Cases for |kill_newlines| (C++)@>@;
2458
@ The |kill_nl| flag is intended to make prettier short functions for such
2459
things as simple \Cpp\ constructors. The scrap of ilk |kill_newlines| is
2460
appended by \.{@@\{}.
2463
IN_PROD boolean kill_nl PSET(NO);
2466
@<Append a |force| or thinspace@>=
2469
@<Append thinspace@>@;
2475
@<Cases for |kill_newlines| (C++)@>=
2478
SQUASH(pp, 1, lbrace, -2, 8888);
2482
@<CASES for |lbrace| (C)@>=
2486
@<Cases for |lbrace| (C)@>@;
2492
@[SRTN C_lbrace(VOID)
2494
@<Cases for |lbrace| (C)@>@;
2499
@<Cases for |lbrace| (C)@>=
2501
if (cat1==rbrace) /* ``|{}|'' */
2503
b_app1(pp); @~ @<Append thinspace@>; @~ b_app1(pp+1);
2504
REDUCE(pp,2,stmt,-1,130);
2506
else if ((cat1==stmt || cat1==decl || cat1==functn) && cat2==rbrace)
2507
/* ``|{x;}|'' or \dots\ or \Cpp: |@c++ main(){try{}catch(){}}| */
2510
b_app1(pp); /* ``|{|'' */
2514
b_app1(pp+2); /* ``|}|'' */
2516
REDUCE(pp,3,stmt,-1,131);
2518
else if (cat1==expr)
2521
SQUASH(pp,3,expr,-2,132); /* ``|enum{red}|'' */
2522
else if (cat2==comma && cat3==rbrace)
2523
SQUASH(pp,4,expr,-2,132);
2530
@<Append a |force| or thinspace@>@;
2532
b_app1(pp+1); /* Body */
2534
@<Append a |force| or thinspace@>@;
2540
@<CASES for |unop| (C)@>=
2544
@<Cases for |unop| (C)@>@;
2550
@[SRTN C__unop(VOID)
2552
@<Cases for |unop| (C)@>@;
2557
@<Cases for |unop| (C)@>=
2560
SQUASH(pp,2,expr,-2,140); /* ``|!x|'' or ``|++x|'' */
2561
else if(cat1==int_like)
2562
SQUASH(pp,2,int_like,0,141); /* \Cpp\ destructor:
2567
@<CASES for |unorbinop| (C)@>=
2571
@<Cases for |unorbinop| (C)@>@;
2577
@[SRTN C_unorbinop(VOID)
2579
@<Cases for |unorbinop| (C)@>@;
2584
@<Cases for |unorbinop| (C)@>=
2586
if(cat1==expr || (cat1==int_like && !(cat2 == lpar || cat2 == unop)) )
2587
{ /* ``|*p|'' or ``|&x|''; ``|typedef
2588
(*T)|'' where |T| was |typedef|d on the first pass. Not
2589
\Cpp: ``|@c++ x + int(i)|'' or ``|@c++ x + base::y|''. */
2590
b_app(@'{'); @~b_app1(pp); @~ b_app(@'}');
2592
REDUCE(pp,2,cat1,-2,150);
2594
else if (cat1==binop)
2595
@<Reduce cases like |*=|@>@;
2599
@<Reduce cases like |*=|@>=
2603
b_app(@'{'); @~ b_app1(pp+1); @~ b_app(@'}');
2604
b_app(@'}'); /* End |math_bin| */
2605
REDUCE(pp,2,binop,-1,151);
2609
@<CASES for |cast| (C)@>=
2613
@<Cases for |cast| (C)@>@;
2621
@<Cases for |cast| (C)@>@;
2626
@<Cases for |cast| (C)@>=
2628
if (cat1==expr) /* ``|(int *)p|'' */
2630
b_app1(pp); @~ @<Append thinspace@>; @~ b_app1(pp+1);
2631
REDUCE(pp,2,expr,-2,160);
2633
else if(cat1 == unorbinop || cat1 == reference)
2634
SQUASH(pp, 1, cast, PLUS 1, 162); // ``|(int *)&prms|''.
2636
SQUASH(pp,1,expr,-2,161); // Turn function prototype into expression.
2640
@<CASES for |sizeof_like| (C)@>=
2644
@<Cases for |sizeof_like| (C)@>@;
2650
@[SRTN C_sizeof_like(VOID)
2652
@<Cases for |sizeof_like| (C)@>@;
2657
@<Cases for |sizeof_like| (C)@>=
2660
SQUASH(pp,2,expr,-2,170); /* ``|sizeof (int *)|'' */
2661
else if (cat1==expr)
2662
SQUASH(pp,2,expr,-2,171); /* ``|sizeof(x)|'' */
2666
@<CASES for |binop| (C)@>=
2670
@<Cases for |binop| (C)@>@;
2676
@[SRTN C__binop(VOID)
2678
@<Cases for |binop| (C)@>@;
2683
@<Cases for |binop| (C)@>=
2686
@<Reduce cases like |+=|@>@; /* ``|+=|'' */
2687
else if(cat1==space)
2689
b_app1(pp); // We eat the space in this macro situation.
2690
REDUCE(pp, 2, binop, -1, 181); // |#if(a == b)|.
2692
else if(Cpp && cat1==decl_hd)
2693
SQUASH(pp, 2, tstart, 0, 6063);
2694
/* Trap for ``|@c++ A<int>|'', with |A| undefined. See
2699
@<Reduce cases like |+=|@>=
2701
b_app(math_bin); b_app1(pp);
2702
b_app(@'{'); @~ b_app1(pp+1); @~ b_app(@'}');
2703
b_app(@'}'); /* End |math_bin| */
2704
REDUCE(pp,2,binop,-1,180);
2708
@<CASES for |do_like| (C)@>=
2712
@<Cases for |do_like| (C)@>@;
2718
@[SRTN C_do_like(VOID)
2720
@<Cases for |do_like| (C)@>@;
2725
@<Cases for |do_like| (C)@>=
2731
SQUASH(pp, 1, do_like, PLUS 2, 191);
2733
else if(cat2==expr && cat3==semi)
2734
{ /* ``|do {} while(flag);|'' */
2735
b_app1(pp); // ``\&{do}''
2737
b_app1(pp+1); // stmt
2740
b_app2(pp+2); // ``\&{while}\dots''
2741
REDUCE(pp,4,stmt,-1,190);
2746
@<CASES for |while_do| (C)@>=
2750
@<Cases for |while_do| (C)@>@;
2756
@[SRTN C_wh_do(VOID)
2758
@<Cases for |while_do| (C)@>@;
2763
@<Cases for |while_do| (C)@>=
2766
@<Append thinspace@>;
2767
REDUCE(pp, 1, expr, 0, 192);
2770
@ Identifiers that are |for_like| must in normal usage be followed by a
2771
parenthesized expression. However, since they might be used in isolation in
2772
a macro argument, we allow a default possibility.
2774
@<CASES for |for_like| (C)@>=
2778
@<Cases for |for_like| (C)@>@;
2784
@[SRTN C_for_like(VOID)
2786
@<Cases for |for_like| (C)@>@;
2791
@<Cases for |for_like| (C)@>=
2794
{ /* ``\&{for}\dots'' */
2795
b_app1(pp); @~ @<Append thinspace@>; @~ b_app1(pp+1);
2796
b_app(@' '); // Unnecessary? (Space at end of |for| line?)
2799
{ /* ``|for(;;);|'' */
2800
if(!auto_semi || (auto_semi && cat3==semi))
2803
b_app1(pp+2); // Semi on separate line.
2805
REDUCE(pp,3,stmt,-2,200); /* The $-2$ is for the
2806
\&{do} case. Also get here from Ratfor's \&{until}. */
2809
REDUCE(pp,3,for_hd,0,2011); // Eat the |auto_semi|.
2812
REDUCE(pp,2,for_hd,0,201); // Eat the arguments.
2814
else if(cat1 != lpar)
2815
SQUASH(pp,1,expr,0,2010); // Default possiblity.
2819
@<CASES for |for_hd| (C)@>=
2823
@<Cases for |for_hd| (C)@>@;
2829
@[SRTN C_forhd(VOID)
2831
@<Cases for |for_hd| (C)@>@;
2836
@<Cases for |for_hd| (C)@>=
2839
{ /* ``|for(;;) x;|'' */
2844
REDUCE(pp,2,stmt,-1,210);
2848
@ Begin an \&{if} statement by just absorbing the argument in parentheses.
2849
We check to see if there's a comment coming up, and set a flag. We have to
2850
do that here because |ignore_scrap| is digested before the big switch.
2852
@<CASES for |if_like| (C)@>=
2856
@<Cases for |if_like| (C)@>@;
2862
@[SRTN C_if_like(VOID)
2864
@<Cases for |if_like| (C)@>@;
2869
@<Cases for |if_like| (C)@>=
2871
if (cat1==lpar && cat2==expr && cat3==rpar) /* ``|if(x)|'' */
2873
b_app1(pp); @<Append thinspace@>; b_app3(pp+1);
2875
cmnt_after_IF = (cat4==ignore_scrap); /* Comment coming up? */
2877
REDUCE(pp,4,IF_like,0,220);
2881
@ We need a flag to tell us whether a comment (really, |ignore_scrap|)
2882
follows an |if(x)| construction. If so, we'll put even simple statements on
2883
the next line, properly indented. (Not working yet!)
2888
IN_PROD cmnt_after_IF PSET(NO);
2891
@ Attach |stmt| to |if(x)|. Statements get indented on next line.
2892
If there's no \&{else} following, we're done.
2894
@<CASES for |IF_like| (C)@>=
2898
@<Cases for |IF_like| (C)@>@;
2906
@<Cases for |IF_like| (C)@>@;
2911
@<Cases for |IF_like| (C)@>=
2914
|| cat1==lbrace || cat1==if_like || cat1==for_like || cat1==do_like
2920
SQUASH(pp,1,if_hd,0,230); // |if_hd| does the indenting.
2923
{ /* Attach simple statement. */
2925
REDUCE(pp,2,IF_top,-1,231);
2930
@ The purpose here is to take a complete statement and indent it on the
2932
@<CASES for |if_hd| (C)@>=
2936
@<Cases for |if_hd| (C)@>@;
2942
@[SRTN C_if_hd(VOID)
2944
@<Cases for |if_hd| (C)@>@;
2949
@<Cases for |if_hd| (C)@>=
2951
if (cat1==stmt) /* ``|if(x) {}|'' */
2953
b_app1(pp); /* ``|if(x)|'' */
2955
b_app1(pp+1); /* ``|{}|'' */
2957
REDUCE(pp,2,IF_top,-1,233);
2959
else if(cat1==IF_top && cat2==else_like)
2960
SQUASH(pp,1,if_hd,2,234);
2964
@<CASES for |else_hd| (C)@>=
2968
@<Cases for |else_hd| (C)@>@;
2974
@[SRTN C_els_hd(VOID)
2976
@<Cases for |else_hd| (C)@>@;
2981
@<Cases for |else_hd| (C)@>=
2983
if (cat1==stmt) /* ``|if(x) {}|'' */
2985
b_app1(pp); /* ``|if(x)|'' */
2987
b_app1(pp+1); /* ``|{}|'' */
2989
REDUCE(pp,2,ELSE_like,-1,241);
2994
@<CASES for |else_like| (C)@>=
2998
@<Cases for |else_like| (C)@>@;
3006
@<Cases for |else_like| (C)@>@;
3011
@<Cases for |else_like| (C)@>=
3013
if(cat1==if_like) /* ``|else if|'' */
3016
REDUCE(pp,2,if_like,0,235);
3018
else if(cat1==stmt || cat1==lbrace || cat1==for_like || cat1==do_like)
3019
SQUASH(pp,1,else_hd,0,236); /* ``|else {}|'' */
3020
#if 0 /* The following puts simple statement on same line. */
3021
else if(cat1==stmt) /* ``|else z;|'' */
3024
REDUCE(pp,2,ELSE_like,-1,237);
3029
@ This is commented out above.
3030
@<CASES for |ELSE_like| (C)@>=
3034
@<Cases for |ELSE_like| (C)@>@;
3042
@<Cases for |ELSE_like| (C)@>@;
3047
@<Cases for |ELSE_like| (C)@>=
3050
@<CASES for |IF_top| (C)@>=
3054
@<Cases for |IF_top| (C)@>@;
3060
@[SRTN C_IF_top(VOID)
3062
@<Cases for |IF_top| (C)@>@;
3067
@<Cases for |IF_top| (C)@>=
3069
if(cat1==else_like || cat1==else_hd || cat1==space)
3070
SQUASH(pp,1,IF_top,1,242); /* Expand ahead. */
3071
else if(cat1==IF_top)
3073
b_app1(pp); /* \&{if}\dots */
3075
b_app1(pp+1); /* \&{else if}\dots */
3076
REDUCE(pp,2,IF_top,-1,238);
3078
else if(cat1==ELSE_like)
3080
b_app1(pp); /* \&{if} */
3082
b_app1(pp+1); /* \&{else} */
3083
REDUCE(pp,2,stmt,-1,239);
3085
else if(cat1==IF_like && (cat2==expr || cat2==stmt))
3086
SQUASH(pp,1,IF_top,1,241);
3088
SQUASH(pp,1,stmt,-1,240);
3092
@<CASES for |stmt| (C)@>=
3096
@<Cases for |stmt| (C)@>@;
3104
@<Cases for |stmt| (C)@>@;
3109
@<Cases for |stmt| (C)@>=
3111
if (cat1==stmt || (Cpp && cat1==decl)) /* ``|x; y;|'' */
3115
@<Append a |force| or thinspace@>@;
3119
REDUCE(pp,2,stmt,-1,250);
3121
else if (cat1==functn)
3123
b_app1(pp); @~ b_app(big_force);
3125
REDUCE(pp,2,stmt,-1,251);
3130
@<CASES for |case_like| (C)@>=
3134
@<Cases for |case_like| (C)@>@;
3140
@[SRTN C_case_like(VOID)
3142
@<Cases for |case_like| (C)@>@;
3147
@<Cases for |case_like| (C)@>=
3150
SQUASH(pp,2,stmt,-1,260); /* |return;| */
3151
else if (cat1==colon)
3152
SQUASH(pp,2,tag,-1,261); /* |default:| or \Cpp: |@c++ public:| */
3153
else if (cat1==expr)
3155
if (cat2==semi) /* |return x;| */
3158
REDUCE(pp,3,stmt,-1,262);
3160
else if (cat2==colon) /* |case one:| */
3163
REDUCE(pp,3,tag,-1,263);
3166
else if(cat1==int_like)
3167
{ /* \Cpp: |@c++ public base| */
3169
REDUCE(pp,2,int_like,-2,264);
3174
@<CASES for |tag| (C)@>=
3178
@<Cases for |tag| (C)@>@;
3186
@<Cases for |tag| (C)@>@;
3191
@<Cases for |tag| (C)@>=
3193
if (cat1==tag) /* ``|case one: case two:|'' */
3198
b_app1(pp+1); REDUCE(pp,2,tag,-1,270);
3200
else if (cat1==stmt || cat1==decl || cat1==functn) /* ``|case one:
3201
break;|'' or \Cpp: ``|@c++ public: int constructor();|'' */
3204
b_app(backup); @~ b_app1(pp); @~ b_app(force);
3206
REDUCE(pp,2,cat1,-1,271);
3210
@ To help distinguish a null statement, we preface the semicolon by a space.
3211
@<CASES for |semi| (C)@>=
3215
@<Cases for |semi| (C)@>@;
3223
@<Cases for |semi| (C)@>@;
3228
@<Cases for |semi| (C)@>=
3230
b_app(@' '); @~ b_app1(pp);
3231
REDUCE(pp,1,stmt,-1,280);
3235
@<CASES for |template| (C++)@>=
3239
@<Cases for |template| (C++)@>@;
3245
@[SRTN C_template(VOID)
3247
@<Cases for |template| (C++)@>@;
3252
@<Cases for |template| (C++)@>=
3255
SQUASH(pp, 1, template, PLUS 1, 6000);
3256
else if(cat1 == tlist)
3258
PP_PP(1, 1); @~ b_app(force);
3259
REDUCE(pp, 2, int_like, 0, 6001);
3264
@<CASES for |langle| (C++)@>=
3268
@<Cases for |langle| (C++)@>@;
3274
@[SRTN C_langle(VOID)
3276
@<Cases for |langle| (C++)@>@;
3280
@ If the |langle| isn't grabbed up by |template|, it's just an ordinary
3282
@<Cases for |langle| (C++)@>=
3284
if((pp-1)->cat == template || (pp-1)->cat == int_like || (pp-1)->cat ==
3288
APP_STR("WLA "); // \.{\\WLA} $\equiv$ `$\WLA$'.
3289
REDUCE(pp, 1, tstart, 0, 6050); // Begining of template parameter list.
3291
else if(cat1 == decl_hd && cat2 == rangle)
3298
REDUCE(pp, 3, expr, -1, 6053); // |@c++ f<int, int>|.
3300
else if(cat1 == int_like)
3301
SQUASH(pp, 1, langle, PLUS 1, 6054); // |@c++ f<int>|.
3303
SQUASH(pp, 1, binop, -1, 6051);
3307
@<CASES for |rangle| (C++)@>=
3311
@<Cases for |rangle| (C++)@>@;
3317
@[SRTN C_rangle(VOID)
3319
@<Cases for |rangle| (C++)@>@;
3323
@ If the |rangle| isn't grabbed up by |template|, it's just an ordinary
3325
@<Cases for |rangle| (C++)@>=
3327
if((pp-1)->cat == decl_hd)
3328
SQUASH(pp, 1, rangle, -2, 6055);
3330
SQUASH(pp, 1, binop, -1, 6052);
3334
@<CASES for |tstart| (C++)@>=
3338
@<Cases for |tstart| (C++)@>@;
3344
@[SRTN C_tstart(VOID)
3346
@<Cases for |tstart| (C++)@>@;
3351
@<Cases for |tstart| (C++)@>=
3353
if(cat2 == rangle && (cat1==int_like || cat1==decl_hd || cat1==expr
3354
|| cat1==unorbinop))
3358
APP_STR("WRA "); // Closing of template.
3360
REDUCE(pp, 3, tlist, -1, 6060);
3365
@<CASES for |tlist| (C++)@>=
3369
@<Cases for |tlist| (C++)@>@;
3375
@[SRTN C_tlist(VOID)
3377
@<Cases for |tlist| (C++)@>@;
3382
@<Cases for |tlist| (C++)@>=
3385
@<CASES for |namespace| (C++)@>=
3389
@<Cases for |namespace| (C++)@>@;
3395
@[SRTN C_namespace(VOID)
3397
@<Cases for |namespace| (C++)@>@;
3402
@<Cases for |namespace| (C++)@>=
3404
if(cat1==expr || cat1==int_like)
3405
{ /* \Cpp: |@c++ namespace A| */
3406
make_underlined(pp+1); @~ make_reserved(pp+1);
3410
REDUCE(pp, 2, fn_decl, 0, 7901);
3412
else if(cat1==lbrace)
3413
SQUASH(pp, 1, fn_decl, 0, 7902); // |@c++ namespace{}|
3419
IN_PROD boolean forward_exp PSET(NO);
3421
@* PRODUCTIONS for RATFOR and FORTRAN.
3422
Note that in some cases we use the C~rules for \RATFOR\ as well.
3431
case ignore_scrap: @<CASES for |ignore_scrap| (C)@>@; break;
3432
case expr: @<CASES for |expr| (R)@>@; @~ break;
3433
case key_wd: @<CASES for |key_wd| (R)@>@; @~ break;
3434
case exp_op: @<CASES for |exp_op| (R)@>@; @~ break;
3435
case _EXPR: @<CASES for |_EXPR| (C)@>@; @~ break;
3436
case _EXPR_: @<CASES for |_EXPR_| (C)@>@; @~ break;
3437
case EXPR_: @<CASES for |EXPR_| (C)@>@; @~ break;
3438
case lpar: @<CASES for |lpar| (R)@>@; @~ break;
3439
case lbracket: @<CASES for |lbracket| (C)@>@; @~ break;
3440
case rbracket: @<CASES for |rbracket| (C)@>@; @~ break;
3441
case unop: @<CASES for |unop| (R)@>@; @~ break;
3442
case UNOP: @<CASES for |UNOP| (C)@>@; @~ break;
3443
case unorbinop: @<CASES for |unorbinop| (R)@>@; @~ break;
3444
case binop: @<CASES for |binop| (R)@>@; @~ break;
3445
case BINOP: @<CASES for |BINOP| (C)@>@; @~ break;
3446
case slash_like: @<CASES for |slash_like| (R)@>@; @~ break;
3447
case colon: @<CASES for |colon| (R)@>@; @~ break;
3448
case program_like: @<CASES for |program_like| (R)@>@; @~ break;
3449
case struct_like: @<CASES for |struct_like| (R)@>@; @~ break;
3450
case struct_hd: @<CASES for |struct_hd| (R)@>@; @~ break;
3451
case op_like: @<CASES for |op_like| (R)@>@; @~ break;
3452
case proc_like: @<CASES for |proc_like| (R)@>@; @~ break;
3453
case private_like: @<CASES for |private_like| (R)@>@; @~ break;
3454
case int_like: @<CASES for |int_like| (R)@>@; @~ break;
3455
case decl_hd: @<CASES for |decl_hd| (R)@>@; @~ break;
3456
case decl: @<CASES for |decl| (R)@>@; @~ break;
3457
case fn_decl: @<CASES for |fn_decl| (C)@>@; @~ break;
3458
case fcn_hd: @<CASES for |fcn_hd| (R)@>@; @~ break;
3459
case functn: @<CASES for |functn| (R)@>@; @~ break;
3460
case lbrace: @<CASES for |lbrace| (R)@>@; @~ break;
3461
case do_like: @<CASES for |do_like| (R)@>@; @~ break;
3462
case until_like: @<CASES for |until_like| (R)@>@; @~ break;
3463
case Rdo_like: @<CASES for |Rdo_like| (R)@>@; @~ break;
3464
case if_like: @<CASES for |if_like| (R)@>@; @~ break;
3465
case IF_like: @<CASES for |IF_like| (C)@>@; @~ break; /* The C form serves
3467
case IF_top: @<CASES for |IF_top| (C)@>@; @~ break;
3468
case endif_like: @<CASES for |endif_like| (R)@>@; @~ break;
3469
case end_like: @<CASES for |end_like| (R)@>@; @~ break;
3470
case END_like: @<CASES for |END_like| (R)@>@; @~ break;
3471
case go_like: @<CASES for |go_like| (R)@>@; @~ break;
3472
case for_like: @<CASES for |for_like| (C)@>@; @~ break;
3473
case for_hd: @<CASES for |for_hd| (C)@>@; @~ break; /* C serves both. */
3474
case else_like: @<CASES for |else_like| (R)@>@; @~ break;
3475
case else_hd: @<CASES for |else_hd| (C)@>@; @~ break;
3477
case ELSE_like: @<CASES for |ELSE_like| (C)@>@; @~ break; /* C serves
3480
case if_hd: @<CASES for |if_hd| (R)@>@; @~ break;
3481
case CASE_like: @<CASES for |CASE_like| (R)@>@; @~ break;
3482
case case_like: @<CASES for |case_like| (R)@>@; @~ break;
3483
case stmt: @<CASES for |stmt| (R)@>@; @~ break;
3484
case tag: @<CASES for |tag| (R)@>@; @~ break;
3485
case label: @<CASES for |label| (R)@>@; @~ break;
3486
case semi: @<CASES for |semi| (R)@>@; @~ break;
3488
case common_like: @<CASES for |common_like| (R)@>@; @~ break;
3489
case common_hd: @<CASES for |common_hd| (R)@>@; @~ break;
3490
case read_like: @<CASES for |read_like| (R)@>@; @~ break;
3491
case read_hd: @<CASES for |read_hd| (R)@>@; @~ break;
3492
case entry_like: @<CASES for |entry_like| (R)@>@; @~ break;
3493
case implicit_like: @<CASES for |implicit_like| (R)@>@; @~ break;
3494
case implicit_hd: @<CASES for |implicit_hd| (R)@>@; @~ break;
3495
case assign_like: @<CASES for |assign_like| (R)@>@; @~ break;
3496
case define_like: @<CASES for |define_like| (R)@>@; @~ break;
3497
case built_in: @<CASES for |built_in| (R)@>@; @~ break;
3498
case no_order: @<CASES for |no_order| (R)@>@; @~ break;
3499
case newline: @<CASES for |newline| (R)@>@; @~ break;
3500
case COMMA: @<CASES for |COMMA| (C)@>@; @~ break;
3506
@<CASES for |expr| (R)@>=
3510
@<Cases for |expr| (R)@>@;
3518
@<Cases for |expr| (R)@>@;
3523
@<Cases for |expr| (R)@>=
3525
if (cat1==unop) SQUASH(pp,2,expr,-2,2);
3526
else if ((cat1==binop || cat1==unorbinop || cat1==colon) && cat2==expr)
3527
/* Here we have to worry about constructions such as `|@r #:0|'. */
3528
if(cat1==colon && (*pp->trans)[1]==(sixteen_bits)@'#')
3533
REDUCE(pp,3,expr,-2,3333);
3535
else if(cat1==binop && **(pp+1)->trans == (sixteen_bits)@'/')
3536
SQUASH(pp, 1, expr, PLUS 1, 3334);
3538
SQUASH(pp,3,expr,-2,3); /* ``|@r x = y|'' or ``|@r x + y|'' or
3539
``|@r dimension a(0:100)|'' */
3540
else if (cat1==comma && (cat2==expr || cat2==end_like))
3541
{ /* Note |end_like|; keyword in I/O. */
3544
b_app1(pp+2); REDUCE(pp,3,expr,-2,4);
3546
else if (cat1==expr) SQUASH(pp,2,expr,-2,5); /* ``|@r f(x)|'' */
3547
else if (cat1==semi) SQUASH(pp,2,stmt,-2,6); /* ``|@r x=y;|'' */
3548
else if (cat1==colon && cat2==unorbinop &&
3549
(cat3==rpar || (active_brackets && cat3==rbracket)))
3550
SQUASH(pp,3,expr,-2,299); /* ``|@r 0:*|'' */
3551
else if (cat1==colon && cat2!= lpar) /* label */
3553
make_underlined (pp); SQUASH(pp,2,tag,0,7);
3555
else if (cat1==comma && cat2==int_like) /* For macro usage. */
3559
b_app1(pp+2); REDUCE(pp,3,int_like,-2,4444);
3563
@ This route may be unused now.
3564
@<CASES for |key_wd| (R)@>=
3568
@<Cases for |key_wd| (R)@>@;
3574
@[SRTN R_key_wd(VOID)
3576
@<Cases for |key_wd| (R)@>@;
3581
@<Cases for |key_wd| (R)@>=
3583
SQUASH(pp,1,expr,-2,4445);
3586
@ Exponentiation. We have to watch out for constructions like \.{x\^(a+b)},
3587
which must be typeset |@r x^(a+b)|, and also the construction
3588
\.{x\^y(z)}, which must be typeset |@r x^y(z)|.
3590
@<CASES for |exp_op| (R)@>=
3594
@<Cases for |exp_op| (R)@>@;
3600
@[SRTN R_exp_op(VOID)
3602
@<Cases for |exp_op| (R)@>@;
3607
@<Cases for |exp_op| (R)@>=
3609
if(cat1==lpar) SQUASH(pp,1,exp_op,PLUS 1,2995); /* ``|@r x^(a+b)|'' */
3611
if(cat2==lpar) SQUASH(pp,1,exp_op,PLUS 2,2996); /* Expand array
3613
else if(cat2==expr) SQUASH(pp,1,exp_op,PLUS 1,2997); /* The expr is
3614
the result of expanding the array argument. */
3616
{ /* It's now of the form |@r x^expr|; insert braces around
3617
argument so \TeX\ understands. */
3619
b_app(@'{'); @~ b_app1(pp+1); @~ b_app(@'}');
3620
REDUCE(pp,2,expr,-1,2998);
3624
@ Keep track of where we are in the nested hierarchy of \Fortran\ program
3625
units; for helping with |@r9 contains|.
3628
IN_PROD int fcn_level PSET(0);
3630
@ When we recognize the beginning of a program unit, we increment a counter.
3631
@<CASES for |program_like| (R)@>=
3635
@<Cases for |program_like| (R)@>@;
3641
@[SRTN R_program_like(VOID)
3643
@<Cases for |program_like| (R)@>@;
3648
@<Cases for |program_like| (R)@>=
3650
if(is_FORTRAN_(language))
3652
if(cat1==expr && cat2==semi)
3655
b_app1(pp); @~ b_app(@' ');
3656
b_app(indent); @~ b_app2(pp+1); @~ b_app(outdent);
3657
defined_at(make_underlined(pp+1));
3658
REDUCE(pp,3,fcn_hd,-1,2999);
3660
else if(cat1==no_order)
3661
{ // |@r block data|
3663
REDUCE(pp,2,program_like,0,2997);
3666
{ // |@r block data;|
3669
REDUCE(pp,2,fcn_hd,-1,2996);
3671
else if(cat1==proc_like)
3672
{ // |@n9 module procedure|
3674
REDUCE(pp, 2, int_like, 0, 2887);
3680
SQUASH(pp,1,int_like,-1,2998);
3684
@<CASES for |fcn_hd| (R)@>=
3688
@<Cases for |fcn_hd| (R)@>@;
3694
@[SRTN R_fcn_hd(VOID)
3696
@<Cases for |fcn_hd| (R)@>@;
3701
@<Cases for |fcn_hd| (R)@>=
3705
b_app1(pp); @~ b_app(force);
3707
REDUCE(pp,2,functn,-1,7172);
3709
else if(cat1==stmt && cat2==END_stmt)
3711
b_app1(pp); @~ b_app(force);
3713
b_app1(pp+1); /* Body */
3733
REDUCE(pp,3,functn,-1,7171);
3737
@ The |@r9 module procedure| statement doesn't have an |end| statement.
3738
@<CASES for |proc_like| (R)@>=
3742
@<Cases for |proc_like| (R)@>@;
3748
@[SRTN R_proc_like(VOID)
3750
@<Cases for |proc_like| (R)@>@;
3755
@<Cases for |proc_like| (R)@>=
3757
if(fcn_level == 0) {/* Error message */}
3760
SQUASH(pp,1,int_like,-1,2989);
3762
@ Here we handle Fortran--90's |@r9 private|, |@r9 public|, and |@r9
3763
sequence| statements.
3764
@<CASES for |private_like| (R)@>=
3768
@<Cases for |private_like| (R)@>@;
3774
@[SRTN R_private_like(VOID)
3776
@<Cases for |private_like| (R)@>@;
3781
@<Cases for |private_like| (R)@>=
3783
if(cat1 == (eight_bits)(language==FORTRAN_90 ? semi : colon) )
3787
REDUCE(pp,2,decl,-1,2988);
3789
else SQUASH(pp,1,int_like,-2,2987);
3793
@<CASES for |int_like| (R)@>=
3797
@<Cases for |int_like| (R)@>@;
3803
@[SRTN R_int_like(VOID)
3805
@<Cases for |int_like| (R)@>@;
3810
@<Cases for |int_like| (R)@>=
3816
REDUCE(pp,1,decl_hd,0,940); /* ``|@r block data{}|'' */
3818
else if(cat1==unorbinop && cat2==expr)
3819
{ /* ``|@r character*(*)|'' */
3821
b_app(@'{'); @~ b_app2(pp+1); @~ b_app(@'}');
3822
REDUCE(pp,3,int_like,-1,941);
3824
else if (cat1==int_like || cat1==no_order) /* ``|@r double precision|'' or
3825
F88 things like ``|@r integer, pointer|''; |no_order| takes
3826
care of \&{data} in |@r block data|. */
3829
REDUCE(pp,2,cat0,0,40);
3831
else if(cat1==comma)
3832
SQUASH(pp,2,int_like,0,9001); /* F88: ``|@r logical,|'' */
3833
else if(cat1==binop)
3834
{ /* F88: ``|@r integer :: i|'' */
3837
REDUCE(pp,2,decl_hd,0,9002);
3839
else if(cat1==slashes)
3844
REDUCE(pp,1,decl_hd,0,9002);
3846
else if(cat1==expr && **indirect((pp+1)->trans)==@'(')
3848
b_app1(pp); @~ @<Append thinspace@>@; @~ b_app1(pp+1);
3849
REDUCE(pp,2,int_like,0,9003); /* ``|@r integer (KIND=4)|'' */
3851
else if (cat1==expr || cat1==semi)
3855
if(cat1 != semi) app(@'~');
3857
b_app(indent); /* Start long declaration. */
3859
REDUCE(pp,1,decl_hd,0,41); /* JAK: -1 changed to 0 */
3861
else if(cat1 == rbrace)
3862
SQUASH(pp, 1, decl, -1, 411);
3863
/* See \.{ratfor} example |@r9 module procedure element;|. */
3867
@<CASES for |struct_like| (R)@>=
3871
@<Cases for |struct_like| (R)@>@;
3877
@[SRTN R_struct_like(VOID)
3879
@<Cases for |struct_like| (R)@>@;
3884
@<Cases for |struct_like| (R)@>=
3889
@<Append thinspace@>@; /* Looks nicer with a bit of space. */
3891
REDUCE(pp,1,int_like,0,9075); /* \FORTRAN-88 declaration:
3892
``|@r9 type(triangle)|''. */
3894
else if(cat1==comma && cat2==int_like)
3895
{ /* ``|@r9 type, private|'' */
3896
b_app2(pp); @~ b_app(@' '); @~ b_app1(pp+2);
3897
REDUCE(pp,3,struct_like,0,90750);
3899
else if(cat1==binop && **(pp+1)->trans != (sixteen_bits)@'/')
3900
SQUASH(pp,2,struct_like,0,90751); /* ``|@r9 type, public::|'' The
3901
|!=| precluded the VAX |@n9 structure /stuff/| declaration. */
3902
else if(cat1==expr || cat1==slashes || cat1==struct_like)
3903
{ /* ``|@r9 type person|'', ``|@r9 type /vaxstruct/|'', or ``|@r9
3904
interface operator|'' */
3906
make_underlined(pp+1);
3907
REDUCE(pp,2,language==FORTRAN_90 ? struct_hd : struct_like,0,9076);
3910
SQUASH(pp,1,struct_hd,0,9077); /* |@r9 interface| */
3911
else if (cat1==lbrace) /* ``|@r9 type person {integer i;};|'' */
3913
b_app1(pp); @~ indent_force;
3914
b_app1(pp+1); REDUCE(pp,2,struct_hd,0,100);
3918
@<CASES for |struct_hd| (R)@>=
3922
@<Cases for |struct_hd| (R)@>@;
3928
@[SRTN R_str_hd(VOID)
3930
@<Cases for |struct_hd| (R)@>@;
3935
@<Cases for |struct_hd| (R)@>=
3936
if(is_FORTRAN_(language))
3940
b_app1(pp); @~ @<Append thinspace@>@; b_app1(pp+1); /* ``|@r9
3941
interface operator(.not.)|'' */
3942
REDUCE(pp,2,struct_hd,0,90760);
3949
REDUCE(pp,2,struct_hd,0,90770);
3951
else if(cat1==decl || cat1==functn)
3956
REDUCE(pp,2,struct_hd,0,9078);
3958
else if(cat1==END_stmt)
3964
REDUCE(pp,2,decl,-1,9079);
3967
else @<Cases for |struct_hd| (C)@>@;
3970
@<CASES for |op_like| (R)@>=
3974
@<Cases for |op_like| (R)@>@;
3980
@[SRTN R_op_like(VOID)
3982
@<Cases for |op_like| (R)@>@;
3987
@<Cases for |op_like| (R)@>=
3992
{ /* We'll search for the obligatory right paren that terminates
3995
int k; /* Counter. */
3997
/* If the paren is missing, we could end up appending the entire rest of
3998
the code, so we limit the search. */
3999
for(q=pp+2; q <= scrp_ptr && q-pp < MAX_OP_TOKENS; q++)
4000
if(q->cat == rpar) break;
4002
n = (q->cat == rpar) ? PTR_DIFF(short, q, pp) : 0;
4006
b_app1(pp); @~ b_app(@' '); /* |@r9 operator| */
4007
b_app1(pp+1); /* Left paren. */
4009
APP_STR("\\optrue");
4014
APP_STR("\\opfalse"); /* We need this here in case we
4015
encounter an operator that \FWEAVE\ doesn't know how to overload. */
4019
REDUCE(pp,n+1,expr,-2,6667);
4025
@<CASES for |decl_hd| (R)@>=
4029
@<Cases for |decl_hd| (R)@>@;
4035
@[SRTN R_dcl_hd(VOID)
4037
@<Cases for |decl_hd| (R)@>@;
4042
@<Cases for |decl_hd| (R)@>=
4044
{ /* ``|@r integer i,j|'' */
4045
b_app2(pp); b_app(@' '); REDUCE(pp,2,decl_hd,0,54);
4047
else if (cat1==expr)
4049
make_underlined(pp+1);
4051
if(**(pp+2)->trans == (sixteen_bits)@'=')
4052
{ // Initialization coming up.
4053
SQUASH(pp,1,decl_hd,PLUS 1,55);
4057
SQUASH(pp,2,decl_hd,0,56);
4060
else if(cat1==slashes)
4061
{ /* |@r integer i/1/| */
4062
SQUASH(pp,2,decl_hd,0,57);
4065
else if(cat1==binop && cat2==expr && (cat3==comma || cat3==semi))
4068
REDUCE(pp,3,decl_hd,-1,5660); /* Initialization */
4071
else if (cat1==lbrace || cat1==int_like || cat1==implicit_like)
4072
/* |@r subroutine f {}| or |@r function f(x) real x;| or |@r
4073
program main implicit none;| */
4076
b_app(outdent); /* Turn off |indent|. */
4077
defined_at(FIRST_ID(pp));
4078
REDUCE(pp,1,fn_decl,0,58);
4080
else if (cat1==semi && (!auto_semi || (auto_semi && cat2 != lbrace)))
4083
b_app(outdent); /* Finish long declaration. */
4085
(eight_bits)(intermingle ? (intermingle=NO,ignore_scrap) : decl),
4088
else if(cat1==built_in)
4089
{ /* |@r9 use a, only| */
4091
REDUCE(pp,2,decl_hd,0,5901);
4094
else if(cat1==lpar && cat2==expr) make_underlined(pp+2); /* For
4099
@<CASES for |decl| (R)@>=
4103
@<Cases for |decl| (R)@>@;
4111
@<Cases for |decl| (R)@>@;
4116
@<Cases for |decl| (R)@>=
4117
if(is_FORTRAN_(language) && cat1==END_like) SQUASH(pp,1,stmt,-1,960);
4118
/* `` |@r program main; end;|'' */
4119
else if (cat1==decl)
4121
b_app1(pp); @~ b_app(force);
4123
REDUCE(pp,2,decl,-1,60);
4125
else if (cat1==stmt || cat1==functn)
4127
b_app1(pp); @~ b_app(big_force);
4128
b_app1(pp+1); REDUCE(pp,2,cat1,-1,61);
4131
@ |@r subroutine f1{} subroutine f2{}|.
4132
@<CASES for |functn| (R)@>=
4136
@<Cases for |functn| (R)@>@;
4142
@[SRTN R_functn(VOID)
4144
@<Cases for |functn| (R)@>@;
4149
@<Cases for |functn| (R)@>=
4151
if (cat1==functn || (is_RATFOR_(language) && (cat1==decl || cat1==stmt)))
4153
b_app1(pp); @~ b_app(big_force);
4154
b_app1(pp+1); REDUCE(pp,2,cat1,0,80);
4156
else if(free_Fortran && cat1==semi)
4157
{ /* Handle possible auto-inserted pseudo-semi after function. */
4159
REDUCE(pp, 2, functn, 0, 8088);
4162
else if(cat1==END_like)
4165
REDUCE(pp,1,stmt,-1,9050);
4170
@<CASES for |lpar| (R)@>=
4174
@<Cases for |lpar| (R)@>@;
4182
@<Cases for |lpar| (R)@>@;
4187
@<Cases for |lpar| (R)@>=
4189
if (cat1==expr && cat2==rpar)
4190
SQUASH(pp,3,expr,-2,120); /* ``|@r (x)|'' */
4191
else if(cat1==expr && cat2==colon && cat3==rpar) /* ``|@r (lower:)|'' */
4193
b_app3(pp); @~ @<Append thinspace@>; @~ b_app1(pp+3);
4194
REDUCE(pp,4,expr,-2,9120);
4196
else if(cat1==colon && cat2 != comma) /* ``|@r (:x)|''; watch out for
4197
deferred-shape-spec-lists. */
4199
b_app1(pp); @~ @<Append thinspace@>; @~ b_app1(pp+1);
4200
REDUCE(pp,2,lpar,0,9121);
4202
else if (cat1==rpar) /* ``|@r ()|'' */
4204
b_app1(pp); @~ @<Append thinspace@>; @~ b_app1(pp+1);
4205
REDUCE(pp,2,expr,-2,121);
4207
else if (cat1==stmt) /* `` |@r for(x;y;z)|'' */
4209
b_app2(pp); b_app(@' '); REDUCE(pp,2,lpar,0,123);
4213
@<CASES for |colon| (R)@>=
4217
@<Cases for |colon| (R)@>@;
4223
@[SRTN R_colon(VOID)
4225
@<Cases for |colon| (R)@>@;
4230
@<Cases for |colon| (R)@>=
4232
if(cat1==expr || cat1==unorbinop)
4233
SQUASH(pp,2,expr,-2,9500); /* ``|@r (:upper)|'' */
4234
else if(cat1==comma && cat2==colon)
4235
SQUASH(pp,3,colon,-2,9502);
4236
/* Deferred-shape-spec-list: |@n9 (:,:,:)|.
4237
|colon| used to be |expr| */
4239
SQUASH(pp,1,expr,0,9501); /* |@r (:)| */
4242
@<CASES for |lbrace| (R)@>=
4246
@<Cases for |lbrace| (R)@>@;
4252
@[SRTN R_lbrace(VOID)
4254
@<Cases for |lbrace| (R)@>@;
4259
@<Cases for |lbrace| (R)@>=
4260
if (cat1==rbrace) /* ``|@r {}|'' */
4262
b_app1(pp); @~ @<Append thinspace@>; @~ b_app1(pp+1);
4263
REDUCE(pp,2,stmt,-2,130);
4265
else if ((cat1==stmt || cat1==decl) && cat2==rbrace) /* ``|@r {x;}|'' */
4268
b_app1(pp); @~ b_app(force);
4269
b_app1(pp+1); @~ b_app(force);
4271
REDUCE(pp,3,stmt,-2,131);
4275
@<CASES for |unop| (R)@>=
4279
@<Cases for |unop| (R)@>@;
4287
@<Cases for |unop| (R)@>@;
4292
@<Cases for |unop| (R)@>=
4294
if (cat1==expr) SQUASH(pp,2,expr,-2,33); /* ``|@r !flag|'' */
4297
@<CASES for |unorbinop| (R)@>=
4301
@<Cases for |unorbinop| (R)@>@;
4307
@[SRTN R_unorbinop(VOID)
4309
@<Cases for |unorbinop| (R)@>@;
4314
@<Cases for |unorbinop| (R)@>=
4316
if (cat1==expr) /* ``|@r +1.0|'' */
4318
b_app(@'{'); @~ b_app1(pp); @~ b_app(@'}');
4320
REDUCE(pp,2,expr,-2,140);
4322
else if(cat1==binop)
4323
@<Reduce cases like |*=|@>@;
4324
else if (cat1== comma || cat1==rpar)
4325
SQUASH(pp,1,expr,-2,141); /* ``|@r *,|'' or ``|@r *)|'' */
4328
@<Append thinspace@>=
4330
b_app(@'\\'); @~ b_app(@',');
4334
@<Append thickspace@>=
4336
b_app(@'\\'); @~ b_app(@';');
4340
@<CASES for |slash_like| (R)@>=
4344
@<Cases for |slash_like| (R)@>@;
4350
@[SRTN R_slash_like(VOID)
4352
@<Cases for |slash_like| (R)@>@;
4357
@<Cases for |slash_like| (R)@>=
4358
if(cat1==slash_like)
4359
{ // The slash already has braces around it (appended by \FWEAVE).ac
4361
@<Append thinspace@>;
4363
REDUCE(pp,2,slashes,-1,1801);
4365
else if(cat1==expr && cat2==slash_like)
4366
SQUASH(pp,3,slashes,-1,1802);
4369
@<CASES for |binop| (R)@>=
4373
@<Cases for |binop| (R)@>@;
4379
@[SRTN R_binop(VOID)
4381
@<Cases for |binop| (R)@>@;
4386
@<Cases for |binop| (R)@>=
4388
sixteen_bits tok = **pp->trans;
4391
{ /* ``|@r / /|'' */
4392
if(tok == (sixteen_bits)@'/')
4394
if(**(pp+1)->trans == tok)
4395
@<Append empty slashes@>@;
4399
REDUCE(pp, 1, binop, -1, 1803);
4403
@<Reduce cases like |+=|@>@;
4407
if(tok == (sixteen_bits)@'/')
4409
if(cat1==expr && cat2==binop && **(pp+2)->trans == tok)
4410
@<Append full slashes@>@; // |@n common/dia/|
4414
REDUCE(pp, 1, binop, -1, 1804);
4421
@<Append empty slashes@>=
4424
b_app1(pp); @~ @<Append thinspace@>; @~ b_app1(pp+1);
4426
REDUCE(pp,2,slashes,-1,180);
4430
@<Append full slashes@>=
4434
b_app1(pp); /* |'/'| */
4438
make_underlined(pp+1); /* Index common block name. */
4440
b_app1(pp+1); /* expr/common-block name */
4444
b_app1(pp+2); /* |'/'| */
4448
REDUCE(pp,3,slashes,-1,9181);
4454
IN_PROD text_pointer label_text_ptr[50];
4456
@ Follow translations until one gets down to the actual tokens.
4462
text_pointer t C1("")@;
4466
if(t==NULL) return t;
4470
if(tok_value <= tok_flag) return t;
4472
if(tok_value > inner_tok_flag) tok_value -= (inner_tok_flag - tok_flag);
4474
if(tok_value > tok_flag)
4477
Token tok_value0 = tok_value;
4479
t = tok_start + (int)(tok_value - tok_flag);
4482
if(tok_value == tok_value0) return t; /* Emergency return;
4483
otherwise infinite loop. */
4485
while(tok_value > tok_flag);
4490
@ The following compares the texts of two translations, and is needed for
4491
labeled loops in Fortran.
4494
compare_text FCN((t0,t1))
4495
text_pointer t0 C0("")@;
4496
text_pointer t1 C1("")@;
4498
token_pointer p0,p0_end,p1;
4500
if(t0==NULL || t1==NULL) return NO;
4502
t0 = indirect(t0); t1 = indirect(t1);
4504
p0 = *t0; @~ p0_end = *(t0+1);
4509
if(*p0 == @':') return YES; /* Ends label */
4510
if(*p0++ != *p1++) return NO;
4516
@ Return the value of a token that may be buried deep in indirection chains.
4520
scrap_pointer p C1("")@;
4522
sixteen_bits tok_value;
4524
tok_value = **(p->trans);
4526
if(tok_value > inner_tok_flag)
4527
tok_value -= (inner_tok_flag- tok_flag);
4529
if(tok_value > tok_flag)
4532
tok_value = **(tok_start + (int)(tok_value - tok_flag));
4534
while(tok_value > tok_flag);
4540
@<CASES for |Rdo_like| (R)@>=
4544
@<Cases for |Rdo_like| (R)@>@;
4550
@[SRTN R_Rdo_like(VOID)
4552
@<Cases for |Rdo_like| (R)@>@;
4557
@<Cases for |Rdo_like| (R)@>=
4559
if(is_FORTRAN_(language))
4561
if(cat1==for_like) /* \&{do} \&{while} */
4564
REDUCE(pp,2,Rdo_like,0,9600);
4566
else if(cat1==expr && ( (cat2==expr && cat3==binop) || cat2==if_like) )
4567
{ /* ``|@r do 10 i=@e|'' */
4568
label_text_ptr[indent_level] = (pp+1)->trans; /* Pointer to
4569
a |token_pointer|---namely, index into |tok_start|. */
4570
b_app1(pp); // |@n do|
4572
b_app1(pp+1); // Loop number.
4573
REDUCE(pp,2,Rdo_like,0,9601); /* Swallow only the loop number. */
4575
else if(cat1==stmt) /* ``|@r do i=1,10;|'' */
4577
loop_num[indent_level++] = ++max_loop_num;
4579
b_app1(pp); /* \&{do} */
4581
b_app1(pp+1); /* $i=1,10;$ */
4582
app_loop_num(max_loop_num);
4585
REDUCE(pp,2,stmt,-2,9602);
4589
else if(cat1==stmt || (cat1==expr && cat2==lbrace)) /* ``|@r do i=1,10;|''
4590
or ``|@r do i=1,10{|'' */
4593
REDUCE(pp,2,for_hd,0,9603);
4596
@ The following flag handles the option |@r until| in a ``|@r
4597
repeat{}until|'' construction.
4601
IN_PROD boolean found_until PSET(NO);
4603
@ We have to be slightly tricky here, because in ``|@r repeat{}until|'' the
4604
\&{until} is optional.
4605
@<CASES for |do_like| (R)@>=
4609
@<Cases for |do_like| (R)@>@;
4615
@[SRTN R_do_like(VOID)
4617
@<Cases for |do_like| (R)@>@;
4622
@<Cases for |do_like| (R)@>=
4626
if(cat2==until_like)
4629
SQUASH(pp,1,do_like,PLUS 2,9190); /* ``|@r repeat
4630
{} until @e@;|''; expand the \&{until}. */
4640
if(found_until && cat2==stmt) /* Get here by expanding the
4644
b_app1(pp+2); REDUCE(pp,3,stmt,-2,9191);
4646
else REDUCE(pp,2,stmt,-2,9192); /* ``|@r repeat {}|'';
4651
@ Get here from above by expanding the |@r until|.
4652
@<CASES for |until_like| (R)@>=
4656
@<Cases for |until_like| (R)@>@;
4662
@[SRTN R_until_like(VOID)
4664
@<Cases for |until_like| (R)@>@;
4669
@<Cases for |until_like| (R)@>=
4671
SQUASH(pp,1,for_like,0,9195);
4676
IN_PROD int indent_level PSET(0); // Indent level.
4677
IN_PROD int loop_num[50], max_loop_num PSET(0);
4680
@<CASES for |if_like| (R)@>=
4684
@<Cases for |if_like| (R)@>@;
4690
@[SRTN R_if_like(VOID)
4692
@<Cases for |if_like| (R)@>@;
4697
@<Cases for |if_like| (R)@>=
4701
PP_PP(1,1); /* |@r9 select case| */
4702
REDUCE(pp,2,if_like,0,9196);
4705
if(is_FORTRAN_(language))
4711
if( (if_form=BOOLEAN(cat2==built_in && cat3==semi)) || cat2==semi)
4712
{ /* ``|@n if(x) then;|'' or ``|@n where(x); |'' */
4713
short n; /* Number to append. Things are annoying because the |@n if|
4714
and |@n where| statements aren't completely symmetrical. */
4716
loop_num[indent_level++] = ++max_loop_num;
4718
b_app1(pp); /* \&{if} */
4719
@<Append thinspace@>;
4720
b_app1(pp+1); /* $(x)$ */
4726
b_app2(pp+2); /* \&{then}; */
4731
b_app1(pp+2); /* semi */
4734
app_loop_num(max_loop_num);
4736
REDUCE(pp,n,stmt,-2,9800);
4738
else if(cat2==stmt) /* ``|@n if(x) a=b;|'' */
4740
b_app1(pp); /* \&{if} */
4741
@<Append thinspace@>;
4742
b_app1(pp+1); /* $(x)$ */
4745
b_app1(pp+2); /* Statement */
4746
REDUCE(pp,3,stmt,-2,9801);
4751
@<Append thinspace@>;
4753
REDUCE(pp,2,if_hd,0,9802);
4758
else @<Cases for |if_like| (C)@>@;
4761
@ Attach a comment with the loop number.
4766
app_loop_num FCN((n))
4767
int n C1("Loop number.")@;
4771
if(!block_nums) return; // We're not supposed to number the blocks/loops.
4773
sprintf(loop_id,"\\Wblock{%d}",n); /* Output the block number. */
4778
@ For the |@r go| keyword, we just have to handle optional white space.
4779
@<CASES for |go_like| (R)@>=
4783
@<Cases for |go_like| (R)@>@;
4789
@[SRTN R_go_like(VOID)
4791
@<Cases for |go_like| (R)@>@;
4796
@<Cases for |go_like| (R)@>=
4798
if(cat1==built_in) /* ``|@r go to|'' */
4800
b_app1(pp); /* \&{go} */
4802
b_app1(pp+1); /* \&{to} */
4803
REDUCE(pp,2,case_like,0,9850); /* \&{goto} */
4805
else SQUASH(pp,1,expr,-2,9851);
4807
@ The keyword |@r end| has two possible meanings: end a loop, or end a
4809
@<CASES for |end_like| (R)@>=
4813
@<Cases for |end_like| (R)@>@;
4819
@[SRTN R_end_like(VOID)
4821
@<Cases for |end_like| (R)@>@;
4826
@<Cases for |end_like| (R)@>=
4827
if(cat1==Rdo_like || cat1==if_like) /* ``|@r end do|'' or ``|@r end if|'' */
4829
b_app1(pp); /* \&{end} */
4831
b_app1(pp+1); /* \&{do} or \&{if} */
4832
REDUCE(pp,2,endif_like,0,9860); /* Now turned into \&{enddo} or
4838
SQUASH(pp,1,END_like,-1,9861); /* \&{end} of function. */
4843
@<CASES for |END_like| (R)@>=
4847
@<Cases for |END_like| (R)@>@;
4855
@<Cases for |END_like| (R)@>@;
4860
@<Cases for |END_like| (R)@>=
4862
if(cat1==program_like || cat1==struct_like)
4868
b_app(@' '); @~ b_app1(pp+2);
4869
REDUCE(pp,3,END_like,0,9860);
4872
REDUCE(pp,2,END_like,0,9861);
4875
SQUASH(pp,2,END_stmt,-2,9862);
4878
@ Handle end of loop. Note that in \Fortran-90, the \It{if-construct-name}
4881
@<CASES for |endif_like| (R)@>=
4885
@<Cases for |endif_like| (R)@>@;
4891
@[SRTN R_endif_like(VOID)
4893
@<Cases for |endif_like| (R)@>@;
4898
@<Cases for |endif_like| (R)@>=
4901
boolean no_construct_name;
4903
if((no_construct_name=BOOLEAN(cat1==semi)) || (cat1==expr && cat2==semi) )
4908
if(no_construct_name)
4911
b_app2(pp); /* \&{endif}; or \&{enddo}; */
4914
{ /* Include \It{if-construct-name} */
4919
if(--indent_level < 0)
4922
app_loop_num(loop_num[indent_level]);
4923
REDUCE(pp,n,stmt,-2,9880);
4928
@<CASES for |if_hd| (R)@>=
4932
@<Cases for |if_hd| (R)@>@;
4938
@[SRTN R_if_hd(VOID)
4940
@<Cases for |if_hd| (R)@>@;
4945
@<Cases for |if_hd| (R)@>=
4947
if(is_FORTRAN_(language))
4952
b_app1(pp); @~ b_app(break_space); @~ b_app1(pp+1);
4958
REDUCE(pp,2,stmt,-2,9900);
4962
@<Cases for |if_hd| (C)@>@;
4965
@<CASES for |else_like| (R)@>=
4969
@<Cases for |else_like| (R)@>@;
4975
@[SRTN R_else_like(VOID)
4977
@<Cases for |else_like| (R)@>@;
4982
@<Cases for |else_like| (R)@>=
4984
if(is_FORTRAN_(language))
4986
if(cat1==if_like) /* ``|@n else if|'' */
4988
b_app1(pp); /* \&{else} */
4990
b_app1(pp+1); /* \&{if} */
4991
REDUCE(pp,2,else_like,0,9910); /* \&{elseif} */
4993
else if(cat1==semi) /* \&{else}; */
4997
b_app2(pp); /* \&{else} or \&{elseif} */
4998
app_loop_num(loop_num[indent_level-1]);
5000
REDUCE(pp,2,stmt,-2,9911);
5002
else if(cat1==expr && cat2==built_in && cat3==semi) /* ``|@n else if(x)
5008
b_app1(pp); /* \&{elseif} */
5009
@<Append thinspace@>;
5010
b_app1(pp+1); /* $(x)$ */
5012
b_app2(pp+2); /* \&{then}; */
5013
app_loop_num(loop_num[indent_level-1]);
5016
REDUCE(pp,4,stmt,-2,9912);
5020
else @<Cases for |else_like| (C)@>@;
5023
@<CASES for |stmt| (R)@>=
5027
@<Cases for |stmt| (R)@>@;
5035
@<Cases for |stmt| (R)@>@;
5040
@<Cases for |stmt| (R)@>=
5043
if(is_FORTRAN_(language) && cat1==program_like)
5044
SQUASH(pp, 1, functn, PLUS 1, 9960);
5046
if(is_FORTRAN_(language) && (cat1==END_like && cat2==semi) ) /* Finally
5047
recognized a function. */
5048
SQUASH(pp,1,stmt,-1,99661);
5051
b_app(indent); /* The function body will be indented. */
5052
b_app(backup); /* But not the first line of function. */
5054
b_app1(pp); /* The body. */
5058
if(containing) b_app(big_force);
5068
/* The \&{end} statement. */
5073
REDUCE(pp,3,functn,-1,9961);
5077
if(cat1==stmt || (free_Fortran && cat1==decl))
5083
REDUCE(pp,2,stmt,-2,2501);
5085
else if (cat1==functn)
5087
b_app1(pp); @~ b_app(big_force);
5089
REDUCE(pp,2,stmt,-2,2511);
5093
@<CASES for |CASE_like| (R)@>=
5097
@<Cases for |CASE_like| (R)@>@;
5105
@<Cases for |CASE_like| (R)@>@;
5110
@<Cases for |CASE_like| (R)@>=
5112
if(is_FORTRAN_(language))
5116
REDUCE(pp,1,case_like,0,9258);
5118
else SQUASH(pp,1,case_like,0,9259);
5121
@<CASES for |case_like| (R)@>=
5125
@<Cases for |case_like| (R)@>@;
5131
@[SRTN R_case_like(VOID)
5133
@<Cases for |case_like| (R)@>@;
5138
@<Cases for |case_like| (R)@>=
5139
if(cat1==read_like) /* ``|@r call open|'' */
5141
b_app1(pp); /* \&{call} */
5143
b_app1(pp+1); /* \&{close}, \&{open}, etc. */
5144
REDUCE(pp,2,case_like,0,9260);
5146
else if (cat1==semi) SQUASH(pp,2,stmt,-2,260); /* ``|@r return;|'' */
5147
else if (cat1==colon) @<Append an ordinary colon@>@;
5148
else if (cat1==expr && cat2==semi)
5149
{ /* ``|@r return 1;|'' */
5151
REDUCE(pp,3,stmt,-2,262);
5153
else if ((cat1==expr || cat1==label) && cat2==colon)
5154
{ /* ``|@r case 1:|'' */
5156
APP_STR("\\Colon\\ ");
5157
REDUCE(pp,3,tag,-1,263);
5161
@<Append an ordinary colon@>=
5163
b_app1(pp); @~ APP_STR("\\Colon\\ ");
5164
REDUCE(pp,2,tag,-1,261);
5168
@<CASES for |tag| (R)@>=
5172
@<Cases for |tag| (R)@>@;
5180
@<Cases for |tag| (R)@>@;
5185
@<Cases for |tag| (R)@>=
5187
if (cat1==tag) /* ``|@r case 1: case 2:|'' */
5189
b_app1(pp); @~ b_app(force);
5191
b_app1(pp+1); REDUCE(pp,2,tag,-1,270);
5193
else if (cat1==stmt || cat1==END_like) /* ``|@r 10 continue;|'' */
5195
boolean end_of_loop;
5199
/* Unwind indent levels for labeled loops. */
5200
while(indent_level > 0 &&
5201
compare_text(pp->trans,label_text_ptr[indent_level-1]) )
5208
if(is_FORTRAN_(language) && Fortran_label)
5209
{ /* ``|@n EXIT: continue@;|'' */
5211
APP_STR("\\Wlbl{"); @~ b_app1(pp); @~ app(@'}');
5215
{ /* Label on separate line. */
5218
b_app1(pp); /* Tag (Includes colon.) */
5222
b_app1(pp+1); /* Stmt. */
5225
app_loop_num(loop_num[indent_level]);
5227
REDUCE(pp,2,cat1,-2,271);
5232
@<CASES for |label| (R)@>=
5236
@<Cases for |label| (R)@>@;
5242
@[SRTN R_label(VOID)
5244
@<Cases for |label| (R)@>@;
5249
@<Cases for |label| (R)@>=
5253
REDUCE(pp,2,label,0,9270); /* Swallow the colon. (Numerical
5254
statement labels won't have any.) Then, for all labels, we put a colon in
5255
during the next block. */
5257
else if(cat1==stmt || cat1==END_like)
5259
b_app1(pp); @~ APP_STR("\\Colon\\ ");
5261
if(is_FORTRAN_(language) && Fortran_label)
5264
REDUCE(pp,1,tag,0,9271); /* Convert the label into a tag. Don't
5265
swallow the statement. */
5269
@<CASES for |semi| (R)@>=
5273
@<Cases for |semi| (R)@>@;
5281
@<Cases for |semi| (R)@>@;
5286
@<Cases for |semi| (R)@>=
5287
if(is_RATFOR_(language) && auto_semi)
5288
{ /* Just throw away semi. */
5291
t = indirect(pp->trans);
5293
if(**t == @';') **t = 0;
5294
SQUASH(pp,1,ignore_scrap,-1,9280);
5298
b_app(@' '); b_app1(pp); REDUCE(pp,1,stmt,-2,280);
5302
@<CASES for |common_like| (R)@>=
5306
@<Cases for |common_like| (R)@>@;
5312
@[SRTN R_common_like(VOID)
5314
@<Cases for |common_like| (R)@>@;
5322
@<Cases for |common_like| (R)@>=
5323
if(cat1==expr || cat1==slashes || cat1==semi)
5324
{ /* ``|@r common x| or |@r common/dia/|'' */
5332
REDUCE(pp,1,common_hd,0,9950);
5334
SQUASH(pp, 1, common_hd, 0, 9950);
5338
@<CASES for |common_hd| (R)@>=
5342
@<Cases for |common_hd| (R)@>@;
5348
@[SRTN R_cmn_hd(VOID)
5350
@<Cases for |common_hd| (R)@>@;
5355
@<Cases for |common_hd| (R)@>=
5359
SQUASH(pp,2,common_hd,0,9951); /* ``|@r common x|'' */
5360
else if(cat1==slashes) /* ``|@r common/dia/|'' */
5366
REDUCE(pp,2,common_hd,0,9952);
5368
else if(cat1==comma) /* ``|@r common x,y|'' */
5372
REDUCE(pp,2,common_hd,0,9953);
5380
REDUCE(pp,2,common_hd,0,9951); /* ``|@r common x|'' */
5382
else if(cat1==slashes)
5383
{ /* ``|@r common/dia/|'' */
5384
SQUASH(pp,2,common_hd,0,9952);
5386
else if(cat1==comma) /* ``|@r common x,y|'' */
5388
SQUASH(pp,2,common_hd,0,9953);
5394
REDUCE(pp,2,decl,-1,9954); /* ``|@r common x;|'' */
5398
SQUASH(pp, 2, int_like, 0, 9952); // `` |@4 common/dia/|''
5400
SQUASH(pp, 1, int_like, 0, 9951); // ``|@r common x|''
5403
@<CASES for |read_like| (R)@>=
5407
@<Cases for |read_like| (R)@>@;
5413
@[SRTN R_read_like(VOID)
5415
@<Cases for |read_like| (R)@>@;
5420
@<Cases for |read_like| (R)@>=
5422
if(cat1==lpar && cat2==expr && cat3==rpar) /* |@r read(6,100)| */
5425
@<Append thinspace@>;
5428
REDUCE(pp,4,read_hd,0,9960);
5430
else if(cat1==expr && cat2==comma) /* ``|@r TYPE 100, i@;|'' */
5436
REDUCE(pp,3,read_hd,0,9961);
5438
else if(cat1==expr || cat1==unorbinop) /* ``|@r TYPE *|'' */
5442
if(cat2==expr) b_app(@' '); /* Takes care of |"TYPE 100 i"|. */
5444
REDUCE(pp,2,read_hd,0,9962);
5446
else if(cat1==semi) SQUASH(pp,1,read_hd,0,9963);
5450
@<CASES for |read_hd| (R)@>=
5454
@<Cases for |read_hd| (R)@>@;
5460
@[SRTN R_rd_hd(VOID)
5462
@<Cases for |read_hd| (R)@>@;
5467
@<Cases for |read_hd| (R)@>=
5468
if(cat1==comma) /* ``|@r read(6,100),|'' */
5472
REDUCE(pp,2,read_hd,0,9965);
5476
if(cat2==comma || cat2==semi)
5477
SQUASH(pp,2,read_hd,0,9966); /* ``|@r write(6,100) i,j@;|'' */
5479
else if(cat1==semi && cat2==read_like) /* Two I/O statements back-to-back. */
5488
REDUCE(pp,3,read_like,0,9967);
5494
b_app(big_cancel); /* Supposed to kill off preceding blanks. */
5497
REDUCE(pp,2,stmt,-2,9968);
5502
@f implicit_none implicit
5504
@<CASES for |implicit_like| (R)@>=
5508
@<Cases for |implicit_like| (R)@>@;
5514
@[SRTN R_implicit_like(VOID)
5516
@<Cases for |implicit_like| (R)@>@;
5521
@<Cases for |implicit_like| (R)@>=
5522
if(cat1==int_like || cat1==expr) /* ``|@r implicit integer|'' or
5523
``|@r implicit none|'' */
5527
b_app(indent); /* Start possible long declaration. */
5528
REDUCE(pp,1,implicit_hd,0,9970);
5531
{ /* ``|@r implicit_none;|''. */
5534
REDUCE(pp,1,implicit_hd,0,99700);
5538
@<CASES for |implicit_hd| (R)@>=
5542
@<Cases for |implicit_hd| (R)@>@;
5548
@[SRTN R_imp_hd(VOID)
5550
@<Cases for |implicit_hd| (R)@>@;
5555
@<Cases for |implicit_hd| (R)@>=
5556
if(cat1==unorbinop && cat2==expr)
5557
{ /* ``|@r implicit real*8|'' */
5559
b_app(@'{'); @~ b_app2(pp+1); @~ b_app(@'}');
5560
@<Append thinspace@>;
5561
REDUCE(pp,3,implicit_hd,0,9971);
5563
else if(cat1==expr) SQUASH(pp,2,implicit_hd,0,9972); /* ``|@r implicit
5565
else if(cat1==comma || cat1==int_like)
5569
if(cat2 != unorbinop)
5570
if(cat2==int_like) b_app(@' '); /* ``|@r implicit real x,
5572
else @<Append thinspace@>;
5574
REDUCE(pp,2,implicit_hd,0,9973);
5576
else if(cat1==semi) SQUASH(pp,1,decl_hd,0,9974); /* ``|@r implicit
5580
@<CASES for |assign_like| (R)@>=
5584
@<Cases for |assign_like| (R)@>@;
5590
@[SRTN R_assign_like(VOID)
5592
@<Cases for |assign_like| (R)@>@;
5597
@<Cases for |assign_like| (R)@>=
5598
if(cat1==expr && cat2==built_in && cat3==expr) /* ``|@r assign 100 to k|'' */
5607
REDUCE(pp,4,expr,0,9980);
5610
@ The following flag is used in \FORTRAN-90 to determine whether a |@r9
5611
contains| is in force, and what level in the block structure we're in.
5615
IN_PROD int containing PSET(0);
5618
@<CASES for |entry_like| (R)@>=
5622
@<Cases for |entry_like| (R)@>@;
5628
@[SRTN R_entry_like(VOID)
5630
@<Cases for |entry_like| (R)@>@;
5635
@<Cases for |entry_like| (R)@>=
5636
if(cat1==expr && cat2==semi) /* ``|@r entry E(x);|'' */
5639
b_app(backup); @~ PP_PP(1,2); @~ b_app(force);
5640
REDUCE(pp,3,stmt,-2,9990);
5642
else if(cat1== (eight_bits)(language==FORTRAN_90 ? semi : colon))
5643
{ /* ``|@r9 contains:|'' */
5645
b_app(backup); @~ b_app2(pp); @~ b_app(force);
5651
REDUCE(pp,2,stmt,-2,9991);
5655
@<CASES for |define_like| (R)@>=
5659
@<Cases for |define_like| (R)@>@;
5665
@[SRTN R_define_like(VOID)
5667
@<Cases for |define_like| (R)@>@;
5672
@<Cases for |define_like| (R)@>=
5676
b_app(backup); @~ b_app2(pp); @~ b_app(force);
5677
REDUCE(pp,2,ignore_scrap,-1,9995);
5680
@ \&{data} statements can be intermixed with everything. (VAX). For such
5681
statements, we raise a flag.
5683
@<CASES for |no_order| (R)@>=
5687
@<Cases for |no_order| (R)@>@;
5693
@[SRTN R_no_order(VOID)
5695
@<Cases for |no_order| (R)@>@;
5700
@<Cases for |no_order| (R)@>=
5703
b_app1(pp); @~ b_app(@' ');
5704
REDUCE(pp,1,int_like,0,9996);
5708
@<CASES for |built_in| (R)@>=
5712
@<Cases for |built_in| (R)@>@;
5718
@[SRTN R_built_in(VOID)
5720
@<Cases for |built_in| (R)@>@;
5725
@<Cases for |built_in| (R)@>=
5728
@<Append thinspace@>;
5729
REDUCE(pp,1,expr,-2,9998);
5733
@<CASES for |newline| (R)@>=
5737
@<Cases for |newline| (R)@>@;
5743
@[SRTN R_newline(VOID)
5745
@<Cases for |newline| (R)@>@;
5750
@<Cases for |newline| (R)@>=
5751
SQUASH(pp,1,ignore_scrap,-1,9999);
5753
@* PRODUCTIONS for LITERAL.
5760
case expr: @<Cases for |expr| (M)@>@; @~ break;
5761
case stmt: @<Cases for |stmt| (M)@>@; @~ break;
5766
@<Cases for |expr| (M)@>=
5769
@<Cases for |stmt| (M)@>=
5771
@* PRODUCTIONS for TEX. The productions have been made into individual
5772
functions to accomodate memory-starved pc's.
5779
case expr: @<Cases for |expr| (X)@>@; @~ break;
5780
case stmt: @<Cases for |stmt| (X)@>@; @~ break;
5785
@<Cases for |expr| (X)@>=
5787
if(cat1==expr) SQUASH(pp,2,expr,0,5);
5791
REDUCE(pp,2,stmt,-1,6);
5796
@<Cases for |stmt| (X)@>=
5803
REDUCE(pp,2,stmt,-1,250);
5807
@* CHANGING the SCRAP LIST; APPLYING the PRODUCTIONS.
5808
The `|reduce|' procedure makes the appropriate changes to the scrap list.
5812
typedef unsigned long RULE_NO; // Rule number for the productions.
5815
@d REDUCE(j,k,c,d,n) reduce(j,k,(eight_bits)(c),d,(RULE_NO)(n))
5818
reduce FCN((j,k,c,d,n))
5819
scrap_pointer j C0("")@;
5820
short k C0("Number of items to be reduced.")@;
5821
eight_bits c C0("Reduce to this type.")@;
5822
short d C0("Move by this amount.")@;
5823
RULE_NO n C1("Rule number.")@;
5825
scrap_pointer i, i1; /* Pointers into scrap memory */
5827
/* Store the translation. */
5828
j->cat=c; j->trans=text_ptr;
5829
j->mathness= (eight_bits)(4*last_mathness+ini_mathness);
5832
/* More stuff to the left, overwriting the $k$~items that have been
5836
for (i=j+k, i1=j+1; i<=lo_ptr; i++, i1++)
5838
i1->cat=i->cat; i1->trans=i->trans;
5839
i1->mathness=i->mathness;
5845
@<Change |pp| to $\max(|scrp_base|,|pp+d|)$@>;
5848
@<Print a snapshot of the scrap list if debugging @>;
5849
#endif /* |DEBUG| */
5851
pp--; /* we next say |pp++| */
5855
@<Change |pp| to $\max...@>=
5857
if (pp+d>=scrp_base) pp=pp+d;
5860
@ The |squash| procedure takes advantage of the simplification that occurs
5863
@d SQUASH(j,k,c,d,n) squash(j,k,c,d,(RULE_NO)(n))
5867
squash FCN((j,k,c,d,n))
5868
scrap_pointer j C0("")@;
5869
short k C0("Number to be squashed.")@;
5870
eight_bits c C0("Make it this type.")@;
5871
short d C0("Move by this amount.")@;
5872
RULE_NO n C1("Rule number.")@;
5874
scrap_pointer i; /* pointers into scrap memory */
5878
j->cat=c; @<Change |pp|...@>;
5881
@<Print a snapshot...@>;
5882
#endif /* |DEBUG| */
5884
pp--; /* we next say |pp++| */
5888
for (i=j; i<j+k; i++) b_app1(i);
5893
@ Here now is the code that applies productions as long as possible. It
5894
requires two local labels (|found| and |done|), as well as a local
5897
@<Reduce the scraps using the productions until no more rules apply@>=
5899
in_prototype = indented = NO;
5903
@<Make sure the entries |pp| through |pp+3| of |cat| are defined@>;
5905
if (tok_ptr+8>tok_m_end)
5907
if (tok_ptr>mx_tok_ptr) mx_tok_ptr=tok_ptr;
5908
OVERFLW("tokens","tw");
5911
if(text_ptr+4>tok_end)
5913
if (text_ptr>mx_text_ptr) mx_text_ptr=text_ptr;
5914
OVERFLW("texts",ABBREV(max_texts));
5920
@<Match a production...@>;
5921
ini_mathness=cur_mathness=last_mathness=maybe_math;
5925
@ If we get to the end of the scrap list, category codes equal to zero are
5926
stored, since zero does not match anything in a production.
5928
@<Make sure the entries...@>=
5932
while (hi_ptr<=scrp_ptr && lo_ptr!=pp+3)
5934
(++lo_ptr)->cat=hi_ptr->cat; lo_ptr->mathness=(hi_ptr)->mathness;
5935
lo_ptr->trans=(hi_ptr++)->trans;
5938
for (i=lo_ptr+1;i<=pp+3;i++) i->cat=0;
5943
@<Check for infinite loop@>=
5945
static RULE_NO last_rule = ULONG_MAX;
5946
static int ncycles = 0;
5948
if(n && n == last_rule)
5950
if(ncycles++ > MAX_CYCLES)
5952
CONFUSION("reduce", "Infinite production loop, rule %lu", n);
5963
@<Print a snapsh...@>=
5965
scrap_pointer k; /* pointer into |scrap_info| */
5968
@<Check for infinite loop@>@;
5970
if (tracing==VERBOSE)
5972
printf("%5lu", n); // The rule number.
5975
printf(".%i", in_prototype);
5979
for (k=scrp_base; k<=lo_ptr; k++)
5982
putxchar('*'); // Current one.
5989
if (hi_ptr<=scrp_ptr) printf("..."); /* indicate that more is
5992
@<Print the last translation@>@;
6002
scrap_pointer k C1("")@;
6004
if (INI_MATHNESS(k) == yes_math)
6006
else if (INI_MATHNESS(k) == no_math)
6011
if (LAST_MATHNESS(k) == yes_math)
6013
else if (LAST_MATHNESS(k) == no_math)
6019
@ For debugging, it's helpful to see the translation of the last several scraps
6020
that's printed explicitly.
6021
@<Print the last trans...@>=
6025
if(lo_ptr > scrp_base)
6027
prn_trans(lo_ptr-1); // The second-to-last scrap.
6031
prn_trans(lo_ptr); // Last scrap.
6035
@ The |translate| function assumes that scraps have been stored in
6036
positions |scrp_base| through |scrp_ptr| of |cat| and |trans|. It appends
6037
a |terminator| scrap and begins to apply productions as much as possible.
6038
The result is a token list containing the translation of the given sequence
6041
After calling |translate|, we will have |text_ptr+3<=max_texts| and
6042
|tok_ptr+6<=max_toks|, so it will be possible to create up to three token
6043
lists with up to six tokens without checking for overflow. Before calling
6044
|translate|, we should have |text_ptr<max_texts| and
6045
|scrp_ptr<max_scraps|, since |translate| might add a new text and a new
6046
scrap before it checks for overflow.
6050
translate FCN((mode0))
6051
PARSING_MODE mode0 C1("")@;
6053
LANGUAGE saved_language = language;
6054
scrap_pointer i, /* index into |cat| */
6055
j; /* runs through final scraps */
6057
translate_mode = mode0;
6059
pp=scrp_base; lo_ptr=pp-1; hi_ptr=pp;
6060
@<If tracing, print an indication of where we are@>;
6061
@<Reduce the scraps...@>@;
6062
@<Combine the irreducible scraps that remain@>;
6064
language = saved_language;
6068
@ If the initial sequence of scraps does not reduce to a single scrap, we
6069
concatenate the translations of all remaining scraps, separated by blank
6070
spaces, with dollar signs surrounding the translations of scraps whose
6071
category code is |max_math| or less.
6073
@<Combine the irreducible...@>=
6075
EXTERN int math_flag;
6077
@<If semi-tracing, show the irreducible scraps@>;
6079
for (j=scrp_base; j<=lo_ptr; j++)
6082
app(@' '); // Separate scraps by blanks.
6084
if ((INI_MATHNESS(j) == yes_math) && math_flag==NO)
6092
if ((INI_MATHNESS(j) == no_math) && math_flag==YES)
6104
if ((LAST_MATHNESS(j) == yes_math) && math_flag==NO)
6112
if ((LAST_MATHNESS(j) == no_math) && math_flag==YES)
6121
if (tok_ptr+6>tok_m_end) OVERFLW("tokens","tw");
6128
@<If semi-tracing, show the irreducible scraps@>=
6132
scrap_pointer scrap0 = scrp_base;
6134
while(scrap0->cat == ignore_scrap) scrap0++;
6136
if (lo_ptr>scrap0 && tracing==BRIEF)
6138
CLR_PRINTF(ALWAYS, warning,
6139
("\nIrreducible scrap sequence in %s:",
6140
MOD_TRANS(module_count)));
6144
for (j=scrap0; j<=lo_ptr; j++)
6146
printf(" "); prn_cat(j->cat);
6150
#endif /* |DEBUG| */
6152
@ Print a header for each section of translated code.
6157
if (tracing==VERBOSE)
6159
CLR_PRINTF(ALWAYS, warning,
6160
("\nTracing after l. %u (language = %s): ",
6161
cur_line,languages[lan_num(language)]));
6164
if (loc>=cur_buffer+OUT_WIDTH)
6167
ASCII_write(loc-OUT_WIDTH,OUT_WIDTH);
6169
else ASCII_write(cur_buffer,loc-cur_buffer);
6173
#endif /* |DEBUG| */