cweave.w
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:159k
源码类别:

通讯编程

开发平台:

Visual C++

  1.     case question: @<Cases for |question|@>; @+break;
  2.     case unop: @<Cases for |unop|@>; @+break;
  3.     case unorbinop: @<Cases for |unorbinop|@>; @+break;
  4.     case binop: @<Cases for |binop|@>; @+break;
  5.     case cast: @<Cases for |cast|@>; @+break;
  6.     case sizeof_like: @<Cases for |sizeof_like|@>; @+break;
  7.     case int_like: @<Cases for |int_like|@>; @+break;
  8.     case decl_head: @<Cases for |decl_head|@>; @+break;
  9.     case decl: @<Cases for |decl|@>; @+break;
  10.     case typedef_like: @<Cases for |typedef_like|@>; @+break;
  11.     case struct_like: @<Cases for |struct_like|@>; @+break;
  12.     case struct_head: @<Cases for |struct_head|@>; @+break;
  13.     case fn_decl: @<Cases for |fn_decl|@>; @+break;
  14.     case function: @<Cases for |function|@>; @+break;
  15.     case lbrace: @<Cases for |lbrace|@>; @+break;
  16.     case do_like: @<Cases for |do_like|@>; @+break;
  17.     case if_like: @<Cases for |if_like|@>; @+break;
  18.     case for_like: @<Cases for |for_like|@>; @+break;
  19.     case else_like: @<Cases for |else_like|@>; @+break;
  20.     case if_clause: @<Cases for |if_clause|@>; @+break;
  21.     case if_head: @<Cases for |if_head|@>; @+break;
  22.     case else_head: @<Cases for |else_head|@>; @+break;
  23.     case case_like: @<Cases for |case_like|@>; @+break;
  24.     case stmt: @<Cases for |stmt|@>; @+break;
  25.     case tag: @<Cases for |tag|@>; @+break;
  26.     case semi: @<Cases for |semi|@>; @+break;
  27.     case lproc: @<Cases for |lproc|@>; @+break;
  28.     case section_scrap: @<Cases for |section_scrap|@>; @+break;
  29.     case insert: @<Cases for |insert|@>; @+break;
  30.     case prelangle: @<Cases for |prelangle|@>; @+break;
  31.     case prerangle: @<Cases for |prerangle|@>; @+break;
  32.     case langle: @<Cases for |langle|@>; @+break;
  33.     case public_like: @<Cases for |public_like|@>; @+break;
  34.     case colcol: @<Cases for |colcol|@>; @+break;
  35.     case new_like: @<Cases for |new_like|@>; @+break;
  36.     case operator_like: @<Cases for |operator_like|@>; @+break;
  37.     case catch_like: @<Cases for |catch_like|@>; @+break;
  38.     case base: @<Cases for |base|@>; @+break;
  39.     case raw_rpar: @<Cases for |raw_rpar|@>; @+break;
  40.     case raw_unorbin: @<Cases for |raw_unorbin|@>; @+break;
  41.     case const_like: @<Cases for |const_like|@>; @+break;
  42.     case raw_int: @<Cases for |raw_int|@>; @+break;
  43.   }
  44.   pp++; /* if no match was found, we move to the right */
  45. }
  46. @ In CEE/, new specifier names can be defined via |typedef|, and we want
  47. to make the parser recognize future occurrences of the identifier thus
  48. defined as specifiers.  This is done by the procedure |make_reserved|,
  49. which changes the |ilk| of the relevant identifier.
  50. We first need a procedure to recursively seek the first
  51. identifier in a token list, because the identifier might
  52. be enclosed in parentheses, as when one defines a function
  53. returning a pointer.
  54. @d no_ident_found 0 /* distinct from any identifier token */
  55. @c
  56. token_pointer
  57. find_first_ident(p)
  58. text_pointer p;
  59. {
  60.   token_pointer q; /* token to be returned */
  61.   token_pointer j; /* token being looked at */
  62.   sixteen_bits r; /* remainder of token after the flag has been stripped off */
  63.   if (p>=text_ptr) confusion("find_first_ident");
  64.   for (j=*p; j<*(p+1); j++) {
  65.     r=*j%id_flag;
  66.     switch (*j/id_flag) {
  67.       case 1: case 2: return j;
  68.       case 4: case 5: /* |tok_flag| or |inner_tok_flag| */
  69.         if ((q=find_first_ident(tok_start+r))!=no_ident_found)
  70.           return q;
  71.       default: ; /* char, |section_flag|, fall thru: move on to next token */
  72.         if (*j==inserted) return no_ident_found; /* ignore inserts */
  73.     }
  74.   }
  75.   return no_ident_found;
  76. }
  77. @ The scraps currently being parsed must be inspected for any
  78. occurrence of the identifier that we're making reserved; hence
  79. the |for| loop below.
  80. @c
  81. void
  82. make_reserved(p) /* make the first identifier in |p->trans| like |int| */
  83. scrap_pointer p;
  84. {
  85.   sixteen_bits tok_value; /* the name of this identifier, plus its flag*/
  86.   token_pointer tok_loc; /* pointer to |tok_value| */
  87.   if ((tok_loc=find_first_ident(p->trans))==no_ident_found)
  88.     return; /* this should not happen */
  89.   tok_value=*tok_loc;
  90.   for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) {
  91.     if (p->cat==exp) {
  92.       if (**(p->trans)==tok_value) {
  93.         p->cat=raw_int;
  94.         **(p->trans)=tok_value%id_flag+res_flag;
  95.       }
  96.     }
  97.   }
  98.   (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=raw_int;
  99.   *tok_loc=tok_value%id_flag+res_flag;
  100. }
  101. @ In the following situations we want to mark the occurrence of
  102. an identifier as a definition: when |make_reserved| is just about to be
  103. used; after a specifier, as in |char **argv|;
  104. before a colon, as in \{found}:; and in the declaration of a function,
  105. as in \{main}()${ldots;}$.  This is accomplished by the invocation
  106. of |make_underlined| at appropriate times.  Notice that, in the declaration
  107. of a function, we only find out that the identifier is being defined after
  108. it has been swallowed up by an |exp|.
  109. @c
  110. void
  111. make_underlined(p)
  112. /* underline the entry for the first identifier in |p->trans| */
  113. scrap_pointer p;
  114. {
  115.   token_pointer tok_loc; /* where the first identifier appears */
  116.   if ((tok_loc=find_first_ident(p->trans))==no_ident_found)
  117.     return; /* this happens after parsing the |()| in |double f();| */
  118.   xref_switch=def_flag;
  119.   underline_xref(*tok_loc%id_flag+name_dir);
  120. }
  121. @ We cannot use |new_xref| to underline a cross-reference at this point
  122. because this would just make a new cross-reference at the end of the list.
  123. We actually have to search through the list for the existing
  124. cross-reference.
  125. @<Predecl...@>=
  126. void  underline_xref();
  127. @ @c
  128. void
  129. underline_xref(p)
  130. name_pointer p;
  131. {
  132.   xref_pointer q=(xref_pointer)p->xref; /* pointer to cross-reference being examined */
  133.   xref_pointer r; /* temporary pointer for permuting cross-references */
  134.   sixteen_bits m; /* cross-reference value to be installed */
  135.   sixteen_bits n; /* cross-reference value being examined */
  136.   if (no_xref) return;
  137.   m=section_count+xref_switch;
  138.   while (q != xmem) {
  139.     n=q->num;
  140.     if (n==m) return;
  141.     else if (m==n+def_flag) {
  142.         q->num=m; return;
  143.     }
  144.     else if (n>=def_flag && n<m) break;
  145.     q=q->xlink;
  146.   }
  147.   @<Insert new cross-reference at |q|, not at beginning of list@>;
  148. }
  149. @ We get to this section only when the identifier is one letter long,
  150. so it didn't get a non-underlined entry during phase one.  But it may
  151. have got some explicitly underlined entries in later sections, so in order
  152. to preserve the numerical order of the entries in the index, we have
  153. to insert the new cross-reference not at the beginning of the list
  154. (namely, at |p->xref|), but rather right before |q|.
  155. @<Insert new cross-reference at |q|...@>=
  156.   append_xref(0); /* this number doesn't matter */
  157.   xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr;
  158.   p->xref=(char*)xref_ptr;
  159.   while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;}
  160.   r->num=m; /* everything from |q| on is left undisturbed */
  161. @ Now comes the code that tries to match each production starting
  162. with a particular type of scrap. Whenever a match is discovered,
  163. the |squash| or |reduce| macro will cause the appropriate action
  164. to be performed, followed by |goto found|.
  165. @<Cases for |exp|@>=
  166. if (cat1==lbrace || cat1==int_like || cat1==decl) {
  167.   make_underlined(pp); big_app1(pp); big_app(indent); app(indent);
  168.   reduce(pp,1,fn_decl,0,1);
  169. }
  170. else if (cat1==unop) squash(pp,2,exp,-2,2);
  171. else if ((cat1==binop || cat1==unorbinop) && cat2==exp)
  172.         squash(pp,3,exp,-2,3);
  173. else if (cat1==comma && cat2==exp) {
  174.   big_app2(pp);
  175.   app(opt); app('9'); big_app1(pp+2); reduce(pp,3,exp,-2,4);
  176. }
  177. else if (cat1==exp || cat1==cast) squash(pp,2,exp,-2,5);
  178. else if (cat1==semi) squash(pp,2,stmt,-1,6);
  179. else if (cat1==colon) {
  180.   make_underlined (pp);  squash(pp,2,tag,0,7);
  181. }
  182. else if (cat1==base) {
  183.   if (cat2==int_like && cat3==comma) {
  184.     big_app1(pp+1); big_app(' '); big_app2(pp+2);
  185.     app(opt); app('9'); reduce(pp+1,3,base,0,8);
  186.   }
  187.   else if (cat2==int_like && cat3==lbrace) {
  188.     big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); big_app1(pp+2);
  189.     reduce(pp,3,exp,-1,9);
  190.   }
  191. }
  192. else if (cat1==rbrace) squash(pp,1,stmt,-1,10);
  193. @ @<Cases for |lpar|@>=
  194. if ((cat1==exp||cat1==unorbinop) && cat2==rpar) squash(pp,3,exp,-2,11);
  195. else if (cat1==rpar) {
  196.   big_app1(pp); app('\'); app(','); big_app1(pp+1);
  197. @.\,@>
  198.   reduce(pp,2,exp,-2,12);
  199. }
  200. else if (cat1==decl_head || cat1==int_like || cat1==exp) {
  201.   if (cat2==rpar) squash(pp,3,cast,-2,13);
  202.   else if (cat2==comma) {
  203.     big_app3(pp); app(opt); app('9'); reduce(pp,3,lpar,0,14);
  204.   }
  205. }
  206. else if (cat1==stmt || cat1==decl) {
  207.   big_app2(pp); big_app(' '); reduce(pp,2,lpar,0,15);
  208. }
  209. @ @<Cases for |question|@>=
  210. if (cat1==exp && cat2==colon) squash(pp,3,binop,-2,16);
  211. @ @<Cases for |unop|@>=
  212. if (cat1==exp || cat1==int_like) squash(pp,2,cat1,-2,17);
  213. @ @<Cases for |unorbinop|@>=
  214. if (cat1==exp || cat1==int_like) {
  215.   big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1);
  216.   reduce(pp,2,cat1,-2,18);
  217. }
  218. else if (cat1==binop) {
  219.   big_app(math_rel); big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
  220.   big_app('}'); reduce(pp,2,binop,-1,19);
  221. }
  222. @ @<Cases for |binop|@>=
  223. if (cat1==binop) {
  224.   big_app(math_rel); big_app('{'); big_app1(pp); big_app('}');
  225.   big_app('{'); big_app1(pp+1); big_app('}');
  226.   big_app('}'); reduce(pp,2,binop,-1,20);
  227. }
  228. @ @<Cases for |cast|@>=
  229. if (cat1==exp) {
  230.   big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,21);
  231. }
  232. else if (cat1==semi) squash(pp,1,exp,-2,22);
  233. @ @<Cases for |sizeof_like|@>=
  234. if (cat1==cast) squash(pp,2,exp,-2,23);
  235. else if (cat1==exp) {
  236.   big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,24);
  237. }
  238. @ @<Cases for |int_like|@>=
  239. if (cat1==int_like|| cat1==struct_like) {
  240.   big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,25);
  241. }
  242. else if (cat1==exp && (cat2==raw_int||cat2==struct_like))
  243.   squash(pp,2,int_like,-2,26);
  244. else if (cat1==exp || cat1==unorbinop || cat1==semi) {
  245.   big_app1(pp);
  246.   if (cat1!=semi) big_app(' ');
  247.   reduce(pp,1,decl_head,-1,27);
  248. }
  249. else if (cat1==colon) {
  250.   big_app1(pp); big_app(' '); reduce(pp,1,decl_head,0,28);
  251. }
  252. else if (cat1==prelangle) squash(pp+1,1,langle,1,29);
  253. else if (cat1==colcol && (cat2==exp||cat2==int_like)) squash(pp,3,cat2,-2,30);
  254. else if (cat1==cast) {
  255.   if (cat2==lbrace) {
  256.   big_app2(pp); big_app(indent); big_app(indent);
  257.   reduce(pp,2,fn_decl,1,31);
  258.   }
  259.   else squash(pp,2,int_like,-2,32);
  260. }
  261. @ @<Cases for |decl_head|@>=
  262. if (cat1==comma) {
  263.   big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33);
  264. }
  265. else if (cat1==unorbinop) {
  266.   big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
  267.   reduce(pp,2,decl_head,-1,34);
  268. }
  269. else if (cat1==exp && cat2!=lpar && cat2!=exp) {
  270.   make_underlined(pp+1); squash(pp,2,decl_head,-1,35);
  271. }
  272. else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma ||
  273.     cat3==semi || cat3==rpar))
  274.   squash(pp,3,decl_head,-1,36);
  275. else if (cat1==cast) squash(pp,2,decl_head,-1,37);
  276. else if (cat1==lbrace || (cat1==int_like&&cat2!=colcol) || cat1==decl) {
  277.   big_app1(pp); big_app(indent); app(indent); reduce(pp,1,fn_decl,0,38);
  278. }
  279. else if (cat1==semi) squash(pp,2,decl,-1,39);
  280. @ @<Cases for |decl|@>=
  281. if (cat1==decl) {
  282.   big_app1(pp); big_app(force); big_app1(pp+1);
  283.   reduce(pp,2,decl,-1,40);
  284. }
  285. else if (cat1==stmt || cat1==function) {
  286.   big_app1(pp); big_app(big_force);
  287.   big_app1(pp+1); reduce(pp,2,cat1,-1,41);
  288. }
  289. @ @<Cases for |typedef_like|@>=
  290. if (cat1==decl_head)
  291.   if ((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like) {
  292.     make_underlined(pp+2); make_reserved(pp+2);
  293.     big_app2(pp+1); reduce(pp+1,2,decl_head,0,42);
  294.   }
  295.   else if (cat2==semi) {
  296.     big_app1(pp); big_app(' '); big_app2(pp+1); reduce(pp,3,decl,-1,43);
  297.   }
  298. @ @<Cases for |struct_like|@>=
  299. if (cat1==lbrace) {
  300.   big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44);
  301. }
  302. else if (cat1==exp||cat1==int_like) {
  303.   if (cat2==lbrace || cat2==semi) {
  304.     make_underlined(pp+1); make_reserved(pp+1);
  305.     big_app1(pp); big_app(' '); big_app1(pp+1);
  306.     if (cat2==semi) reduce(pp,2,decl_head,0,45);
  307.     else {
  308.       big_app(' '); big_app1(pp+2);reduce(pp,3,struct_head,0,46);
  309.     }
  310.   }
  311.   else if (cat2==colon) squash(pp+2,1,base,-1,47);
  312.   else if (cat2!=base) {
  313.     big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48);
  314.   }
  315. }
  316. @ @<Cases for |struct_head|@>=
  317. if ((cat1==decl || cat1==stmt || cat1==function) && cat2==rbrace) {
  318.   big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1);
  319.   big_app(outdent); big_app(force);  big_app1(pp+2);
  320.   reduce(pp,3,int_like,-2,49);
  321. }
  322. else if (cat1==rbrace) {
  323.   big_app1(pp); app_str("\,"); big_app1(pp+1);
  324. @.\,@>
  325.   reduce(pp,2,int_like,-2,50);
  326. }
  327. @ @<Cases for |fn_decl|@>=
  328. if (cat1==decl) {
  329.   big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,fn_decl,0,51);
  330. }
  331. else if (cat1==stmt) {
  332.   big_app1(pp); app(outdent); app(outdent); big_app(force);
  333.   big_app1(pp+1); reduce(pp,2,function,-1,52);
  334. }
  335. @ @<Cases for |function|@>=
  336. if (cat1==function || cat1==decl || cat1==stmt) {
  337.   big_app1(pp); big_app(big_force); big_app1(pp+1); reduce(pp,2,cat1,-1,53);
  338. }
  339. @ @<Cases for |lbrace|@>=
  340. if (cat1==rbrace) {
  341.   big_app1(pp); app('\'); app(','); big_app1(pp+1);
  342. @.\,@>
  343.   reduce(pp,2,stmt,-1,54);
  344. }
  345. else if ((cat1==stmt||cat1==decl||cat1==function) && cat2==rbrace) {
  346.   big_app(force); big_app1(pp);  big_app(indent); big_app(force);
  347.   big_app1(pp+1); big_app(force); big_app(backup);  big_app1(pp+2);
  348.   big_app(outdent); big_app(force); reduce(pp,3,stmt,-1,55);
  349. }
  350. else if (cat1==exp) {
  351.   if (cat2==rbrace) squash(pp,3,exp,-2,56);
  352.   else if (cat2==comma && cat3==rbrace) squash(pp,4,exp,-2,56);
  353. }
  354. @ @<Cases for |if_like|@>=
  355. if (cat1==exp) {
  356.   big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,if_clause,0,57);
  357. }
  358. @ @<Cases for |for_like|@>=
  359. if (cat1==exp) {
  360.   big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,58);
  361. }
  362. @ @<Cases for |else_like|@>=
  363. if (cat1==lbrace) squash(pp,1,else_head,0,59);
  364. else if (cat1==stmt) {
  365.   big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
  366.   big_app1(pp+1); big_app(outdent); big_app(force);
  367.   reduce(pp,2,stmt,-1,60);
  368. }
  369. @ @<Cases for |else_head|@>=
  370. if (cat1==stmt || cat1==exp) {
  371.   big_app(force); big_app1(pp); big_app(break_space); app(noop);
  372.   big_app(cancel); big_app1(pp+1); big_app(force);
  373.   reduce(pp,2,stmt,-1,61);
  374. }
  375. @ @<Cases for |if_clause|@>=
  376. if (cat1==lbrace) squash(pp,1,if_head,0,62);
  377. else if (cat1==stmt) {
  378.   if (cat2==else_like) {
  379.     big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
  380.     big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2);
  381.     if (cat3==if_like) {
  382.       big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63);
  383.     }@+else reduce(pp,3,else_like,0,64);
  384.   }
  385.   else squash(pp,1,else_like,0,65);
  386. }
  387. @ @<Cases for |if_head|@>=
  388. if (cat1==stmt || cat1==exp) {
  389.   if (cat2==else_like) {
  390.     big_app(force); big_app1(pp); big_app(break_space); app(noop);
  391.     big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2);
  392.     if (cat3==if_like) {
  393.       big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66);
  394.     }@+else reduce(pp,3,else_like,0,67);
  395.   }
  396.   else squash(pp,1,else_head,0,68);
  397. }
  398. @ @<Cases for |do_like|@>=
  399. if (cat1==stmt && cat2==else_like && cat3==semi) {
  400.   big_app1(pp); big_app(break_space); app(noop); big_app(cancel);
  401.   big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space);
  402.   big_app2(pp+2); reduce(pp,4,stmt,-1,69);
  403. }
  404. @ @<Cases for |case_like|@>=
  405. if (cat1==semi) squash(pp,2,stmt,-1,70);
  406. else if (cat1==colon) squash(pp,2,tag,-1,71);
  407. else if (cat1==exp) {
  408.   if (cat2==semi) {
  409.     big_app1(pp); big_app(' ');  big_app1(pp+1);  big_app1(pp+2);
  410.     reduce(pp,3,stmt,-1,72);
  411.   }
  412.   else if (cat2==colon) {
  413.     big_app1(pp); big_app(' ');  big_app1(pp+1);  big_app1(pp+2);
  414.     reduce(pp,3,tag,-1,73);
  415.   }
  416. }
  417. @ @<Cases for |tag|@>=
  418. if (cat1==tag) {
  419.   big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74);
  420. }
  421. else if (cat1==stmt||cat1==decl||cat1==function) {
  422.   big_app(force); big_app(backup); big_app1(pp); big_app(break_space);
  423.   big_app1(pp+1); reduce(pp,2,cat1,-1,75);
  424. }
  425. @ The user can decide at run-time whether short statements should be
  426. grouped together on the same line.
  427. @d force_lines flags['f'] /* should each statement be on its own line? */
  428. @<Cases for |stmt|@>=
  429. if (cat1==stmt||cat1==decl||cat1==function) {
  430.   big_app1(pp);
  431.   if (cat1==function) big_app(big_force);
  432.   else if (cat1==decl) big_app(big_force);
  433.   else if (force_lines) big_app(force);
  434.   else big_app(break_space);
  435.   big_app1(pp+1); reduce(pp,2,cat1,-1,76);
  436. }
  437. @ @<Cases for |semi|@>=
  438. big_app(' '); big_app1(pp); reduce(pp,1,stmt,-1,77);
  439. @ @<Cases for |lproc|@>=
  440. if (cat1==define_like) make_underlined(pp+2);
  441. if (cat1==else_like || cat1==if_like ||cat1==define_like)
  442.   squash(pp,2,lproc,0,78);
  443. else if (cat1==rproc) {
  444.   app(inserted); big_app2(pp); reduce(pp,2,insert,-1,79);
  445. } else if (cat1==exp || cat1==function) {
  446.   if (cat2==rproc) {
  447.     app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1);
  448.     reduce(pp,3,insert,-1,80);
  449.   }
  450.   else if (cat2==exp && cat3==rproc && cat1==exp) {
  451.     app(inserted); big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \5");
  452. @.\5@>
  453.     big_app2(pp+2); reduce(pp,4,insert,-1,80);
  454.   }
  455. }
  456. @ @<Cases for |section_scrap|@>=
  457. if (cat1==semi) {
  458.   big_app2(pp); big_app(force); reduce(pp,2,stmt,-2,81);
  459. }
  460. else squash(pp,1,exp,-2,82);
  461. @ @<Cases for |insert|@>=
  462. if (cat1)
  463.   squash(pp,2,cat1,0,83);
  464. @ @<Cases for |prelangle|@>=
  465. init_mathness=cur_mathness=yes_math;
  466. app('<'); reduce(pp,1,binop,-2,84);
  467. @ @<Cases for |prerangle|@>=
  468. init_mathness=cur_mathness=yes_math;
  469. app('>'); reduce(pp,1,binop,-2,85);
  470. @ @<Cases for |langle|@>=
  471. if (cat1==exp && cat2==prerangle) squash(pp,3,cast,-1,86);
  472. else if (cat1==prerangle) {
  473.   big_app1(pp); app('\'); app(','); big_app1(pp+1);
  474. @.\,@>
  475.   reduce(pp,2,cast,-1,87);
  476. }
  477. else if (cat1==decl_head || cat1==int_like) {
  478.   if (cat2==prerangle) squash(pp,3,cast,-1,88);
  479.   else if (cat2==comma) {
  480.     big_app3(pp); app(opt); app('9'); reduce(pp,3,langle,0,89);
  481.   }
  482. }
  483. @ @<Cases for |public_like|@>=
  484. if (cat1==colon) squash(pp,2,tag,-1,90);
  485. else squash(pp,1,int_like,-2,91);
  486. @ @<Cases for |colcol|@>=
  487. if (cat1==exp||cat1==int_like) squash(pp,2,cat1,-2,92);
  488. @ @<Cases for |new_like|@>=
  489. if (cat1==exp || (cat1==raw_int&&cat2!=prelangle&&cat2!=langle)) {
  490.   big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,new_like,0,93);
  491. }
  492. else if (cat1==raw_unorbin || cat1==colcol)
  493.   squash(pp,2,new_like,0,94);
  494. else if (cat1==cast) squash(pp,2,exp,-2,95);
  495. else if (cat1!=lpar && cat1!=raw_int && cat1!=struct_like)
  496.   squash(pp,1,exp,-2,96);
  497. @ @<Cases for |operator_like|@>=
  498. if (cat1==binop || cat1==unop || cat1==unorbinop) {
  499.   if (cat2==binop) break;
  500.   big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
  501.   reduce(pp,2,exp,-2,97);
  502. }
  503. else if (cat1==new_like || cat1==sizeof_like) {
  504.   big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,98);
  505. }
  506. else squash(pp,1,new_like,0,99);
  507. @ @<Cases for |catch_like|@>=
  508. if (cat1==cast || cat1==exp) {
  509.   big_app2(pp); big_app(indent); big_app(indent);
  510.   reduce(pp,2,fn_decl,0,100);
  511. }
  512. @ @<Cases for |base|@>=
  513. if (cat1==public_like && cat2==exp) {
  514.   if (cat3==comma) {
  515.     big_app2(pp); big_app(' '); big_app2(pp+2);
  516.     reduce(pp,4,base,0,101);
  517.   } else {
  518.     big_app1(pp+1); big_app(' '); big_app1(pp+2);
  519.     reduce(pp+1,2,int_like,-1,102);
  520.   }
  521. }
  522. @ @<Cases for |raw_rpar|@>=
  523. if (cat1==const_like && @|
  524.     (cat2==semi || cat2==lbrace || cat2==comma || cat2==binop
  525.       || cat2==const_like)) {
  526.   big_app1(pp); big_app(' ');
  527.   big_app1(pp+1); reduce(pp,2,raw_rpar,0,103);
  528. } else squash(pp,1,rpar,-3,104);
  529. @ @<Cases for |raw_unorbin|@>=
  530. if (cat1==const_like) {
  531.   big_app2(pp); app_str("\ "); reduce(pp,2,raw_unorbin,0,105);
  532. @.\ @>
  533. } else squash(pp,1,unorbinop,-2,106);
  534. @ @<Cases for |const_like|@>=
  535. squash(pp,1,int_like,-2,107);
  536. @ @<Cases for |raw_int|@>=
  537. if (cat1==lpar) squash(pp,1,exp,-2,108);
  538. else squash(pp,1,int_like,-3,109);
  539. @ The `|freeze_text|' macro is used to give official status to a token list.
  540. Before saying |freeze_text|, items are appended to the current token list,
  541. and we know that the eventual number of this token list will be the current
  542. value of |text_ptr|. But no list of that number really exists as yet,
  543. because no ending point for the current list has been
  544. stored in the |tok_start| array. After saying |freeze_text|, the
  545. old current token list becomes legitimate, and its number is the current
  546. value of |text_ptr-1| since |text_ptr| has been increased. The new
  547. current token list is empty and ready to be appended to.
  548. Note that |freeze_text| does not check to see that |text_ptr| hasn't gotten
  549. too large, since it is assumed that this test was done beforehand.
  550. @d freeze_text *(++text_ptr)=tok_ptr
  551. @ Here's the |reduce| procedure used in our code for productions:
  552. @c
  553. void
  554. reduce(j,k,c,d,n)
  555. scrap_pointer j;
  556. eight_bits c;
  557. short k, d, n;
  558. {
  559.   scrap_pointer i, i1; /* pointers into scrap memory */
  560.   j->cat=c; j->trans=text_ptr;
  561.   j->mathness=4*cur_mathness+init_mathness;
  562.   freeze_text;
  563.   if (k>1) {
  564.     for (i=j+k, i1=j+1; i<=lo_ptr; i++, i1++) {
  565.       i1->cat=i->cat; i1->trans=i->trans;
  566.       i1->mathness=i->mathness;
  567.     }
  568.     lo_ptr=lo_ptr-k+1;
  569.   }
  570.   @<Change |pp| to $max(|scrap_base|,|pp|+d)$@>;
  571.   @<Print a snapshot of the scrap list if debugging @>;
  572.   pp--; /* we next say |pp++| */
  573. }
  574. @ @<Change |pp| to $max...@>=
  575. if (pp+d>=scrap_base) pp=pp+d;
  576. else pp=scrap_base;
  577. @ Here's the |squash| procedure, which
  578. takes advantage of the simplification that occurs when |k==1|.
  579. @c
  580. void
  581. squash(j,k,c,d,n)
  582. scrap_pointer j;
  583. eight_bits c;
  584. short k, d, n;
  585. {
  586.   scrap_pointer i; /* pointers into scrap memory */
  587.   if (k==1) {
  588.     j->cat=c; @<Change |pp|...@>;
  589.     @<Print a snapshot...@>;
  590.     pp--; /* we next say |pp++| */
  591.     return;
  592.   }
  593.   for (i=j; i<j+k; i++) big_app1(i);
  594.   reduce(j,k,c,d,n);
  595. }
  596. @ Here now is the code that applies productions as long as possible.
  597. Before applying the production mechanism, we must make sure
  598. it has good input (at least four scraps, the length of the lhs of the
  599. longest rules), and that there is enough room in the memory arrays
  600. to hold the appended tokens and texts.  Here we use a very
  601. conservative test: it's more important to make sure the program
  602. will still work if we change the production rules (within reason)
  603. than to squeeze the last bit of space from the memory arrays.
  604. @d safe_tok_incr 20
  605. @d safe_text_incr 10
  606. @d safe_scrap_incr 10
  607. @<Reduce the scraps using the productions until no more rules apply@>=
  608. while (1) {
  609.   @<Make sure the entries |pp| through |pp+3| of |cat| are defined@>;
  610.   if (tok_ptr+safe_tok_incr>tok_mem_end) {
  611.     if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
  612.     overflow("token");
  613.   }
  614.   if (text_ptr+safe_text_incr>tok_start_end) {
  615.     if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
  616.     overflow("text");
  617.   }
  618.   if (pp>lo_ptr) break;
  619.   init_mathness=cur_mathness=maybe_math;
  620.   @<Match a production...@>;
  621. }
  622. @ If we get to the end of the scrap list, category codes equal to zero are
  623. stored, since zero does not match anything in a production.
  624. @<Make sure the entries...@>=
  625. if (lo_ptr<pp+3) {
  626.   while (hi_ptr<=scrap_ptr && lo_ptr!=pp+3) {
  627.     (++lo_ptr)->cat=hi_ptr->cat; lo_ptr->mathness=(hi_ptr)->mathness;
  628.     lo_ptr->trans=(hi_ptr++)->trans;
  629.   }
  630.   for (i=lo_ptr+1;i<=pp+3;i++) i->cat=0;
  631. }
  632. @ If .{CWEAVE} is being run in debugging mode, the production numbers and
  633. current stack categories will be printed out when |tracing| is set to 2;
  634. a sequence of two or more irreducible scraps will be printed out when
  635. |tracing| is set to 1.
  636. @<Global...@>=
  637. int tracing; /* can be used to show parsing details */
  638. @ @<Print a snapsh...@>=
  639. { scrap_pointer k; /* pointer into |scrap_info| */
  640.   if (tracing==2) {
  641.     printf("n%d:",n);
  642.     for (k=scrap_base; k<=lo_ptr; k++) {
  643.       if (k==pp) putxchar('*'); else putxchar(' ');
  644.       if (k->mathness %4 ==  yes_math) putchar('+');
  645.       else if (k->mathness %4 ==  no_math) putchar('-');
  646.       print_cat(k->cat);
  647.       if (k->mathness /4 ==  yes_math) putchar('+');
  648.       else if (k->mathness /4 ==  no_math) putchar('-');
  649.     }
  650.     if (hi_ptr<=scrap_ptr) printf("..."); /* indicate that more is coming */
  651.   }
  652. }
  653. @ The |translate| function assumes that scraps have been stored in
  654. positions |scrap_base| through |scrap_ptr| of |cat| and |trans|. It
  655. applies productions as much as
  656. possible. The result is a token list containing the translation of
  657. the given sequence of scraps.
  658. After calling |translate|, we will have |text_ptr+3<=max_texts| and
  659. |tok_ptr+6<=max_toks|, so it will be possible to create up to three token
  660. lists with up to six tokens without checking for overflow. Before calling
  661. |translate|, we should have |text_ptr<max_texts| and |scrap_ptr<max_scraps|,
  662. since |translate| might add a new text and a new scrap before it checks
  663. for overflow.
  664. @c
  665. text_pointer
  666. translate() /* converts a sequence of scraps */
  667. {
  668.   scrap_pointer i, /* index into |cat| */
  669.   j; /* runs through final scraps */
  670.   pp=scrap_base; lo_ptr=pp-1; hi_ptr=pp;
  671.   @<If tracing, print an indication of where we are@>;
  672.   @<Reduce the scraps...@>;
  673.   @<Combine the irreducible scraps that remain@>;
  674. }
  675. @ If the initial sequence of scraps does not reduce to a single scrap,
  676. we concatenate the translations of all remaining scraps, separated by
  677. blank spaces, with dollar signs surrounding the translations of scraps
  678. where appropriate.
  679. @<Combine the irreducible...@>= {
  680.   @<If semi-tracing, show the irreducible scraps@>;
  681.   for (j=scrap_base; j<=lo_ptr; j++) {
  682.     if (j!=scrap_base) app(' ');
  683.     if (j->mathness % 4 == yes_math) app('$');
  684.     app1(j);
  685.     if (j->mathness / 4 == yes_math) app('$');
  686.     if (tok_ptr+6>tok_mem_end) overflow("token");
  687.   }
  688.   freeze_text; return(text_ptr-1);
  689. }
  690. @ @<If semi-tracing, show the irreducible scraps@>=
  691. if (lo_ptr>scrap_base && tracing==1) {
  692.   printf("nIrreducible scrap sequence in section %d:",section_count);
  693. @.Irreducible scrap sequence...@>
  694.   mark_harmless;
  695.   for (j=scrap_base; j<=lo_ptr; j++) {
  696.     printf(" "); print_cat(j->cat);
  697.   }
  698. }
  699. @ @<If tracing,...@>=
  700. if (tracing==2) {
  701.   printf("nTracing after l. %d:n",cur_line); mark_harmless;
  702. @.Tracing after...@>
  703.   if (loc>buffer+50) {
  704.     printf("...");
  705.     term_write(loc-51,51);
  706.   }
  707.   else term_write(buffer,loc-buffer);
  708. }
  709. @* Initializing the scraps.
  710. If we are going to use the powerful production mechanism just developed, we
  711. must get the scraps set up in the first place, given a CEE/ text. A table
  712. of the initial scraps corresponding to CEE/ tokens appeared above in the
  713. section on parsing; our goal now is to implement that table. We shall do this
  714. by implementing a subroutine called |C_parse| that is analogous to the
  715. |C_xref| routine used during phase one.
  716. Like |C_xref|, the |C_parse| procedure starts with the current
  717. value of |next_control| and it uses the operation |next_control=get_next()|
  718. repeatedly to read CEE/ text until encountering the next `.{v}' or
  719. `.{/*}', or until |next_control>=format_code|. The scraps corresponding to
  720. what it reads are appended into the |cat| and |trans| arrays, and |scrap_ptr|
  721. is advanced.
  722. @c
  723. void
  724. C_parse(spec_ctrl) /* creates scraps from CEE/ tokens */
  725.   eight_bits spec_ctrl;
  726. {
  727.   int count; /* characters remaining before string break */
  728.   while (next_control<format_code || next_control==spec_ctrl) {
  729.     @<Append the scrap appropriate to |next_control|@>;
  730.     next_control=get_next();
  731.     if (next_control=='|' || next_control==begin_comment ||
  732.         next_control==begin_short_comment) return;
  733.   }
  734. }
  735. @ The following macro is used to append a scrap whose tokens have just
  736. been appended:
  737. @d app_scrap(c,b) {
  738.   (++scrap_ptr)->cat=(c); scrap_ptr->trans=text_ptr;
  739.   scrap_ptr->mathness=5*(b); /* no no, yes yes, or maybe maybe */
  740.   freeze_text;
  741. }
  742. @ @<Append the scr...@>=
  743. @<Make sure that there is room for the new scraps, tokens, and texts@>;
  744. switch (next_control) {
  745.   case section_name:
  746.     app(section_flag+(int)(cur_section-name_dir));
  747.     app_scrap(section_scrap,maybe_math);
  748.     app_scrap(exp,yes_math);@+break;
  749.   case string: case constant: case verbatim: @<Append a string or constant@>;
  750.    @+break;
  751.   case identifier: app_cur_id(1);@+break;
  752.   case TeX_string: @<Append a TEX/ string, without forming a scrap@>;@+break;
  753.   case '/': case '.':
  754.     app(next_control); app_scrap(binop,yes_math);@+break;
  755.   case '<': app_str("\langle");@+app_scrap(prelangle,yes_math);@+break;
  756. @.\langle@>
  757.   case '>': app_str("\rangle");@+app_scrap(prerangle,yes_math);@+break;
  758. @.\rangle@>
  759.   case '=': app_str("\K"); app_scrap(binop,yes_math);@+break;
  760. @.\K@>
  761.   case '|': app_str("\OR"); app_scrap(binop,yes_math);@+break;
  762. @.\OR@>
  763.   case '^': app_str("\XOR"); app_scrap(binop,yes_math);@+break;
  764. @.\XOR@>
  765.   case '%': app_str("\MOD"); app_scrap(binop,yes_math);@+break;
  766. @.\MOD@>
  767.   case '!': app_str("\R"); app_scrap(unop,yes_math);@+break;
  768. @.\R@>
  769.   case '~': app_str("\CM"); app_scrap(unop,yes_math);@+break;
  770. @.\CM@>
  771.   case '+': case '-': app(next_control); app_scrap(unorbinop,yes_math);@+break;
  772.   case '*': app(next_control); app_scrap(raw_unorbin,yes_math);@+break;
  773.   case '&': app_str("\AND"); app_scrap(raw_unorbin,yes_math);@+break;
  774. @.\AND@>
  775.   case '?': app_str("\?"); app_scrap(question,yes_math);@+break;
  776. @.\?@>
  777.   case '#': app_str("\#"); app_scrap(unorbinop,yes_math);@+break;
  778. @.\#@>
  779.   case ignore: case xref_roman: case xref_wildcard:
  780.   case xref_typewriter: case noop:@+break;
  781.   case '(': case '[': app(next_control); app_scrap(lpar,maybe_math);@+break;
  782.   case ')': case ']': app(next_control); app_scrap(raw_rpar,maybe_math);@+break;
  783.   case '{': app_str("\{"@q}@>); app_scrap(lbrace,yes_math);@+break;
  784. @.\{@>@q}@>
  785.   case '}': app_str(@q{@>"\}"); app_scrap(rbrace,yes_math);@+break;
  786. @q{@>@.\}@>
  787.   case ',': app(','); app_scrap(comma,yes_math);@+break;
  788.   case ';': app(';'); app_scrap(semi,maybe_math);@+break;
  789.   case ':': app(':'); app_scrap(colon,maybe_math);@+break;@/
  790.   @t4@>  @<Cases involving nonstandard characters@>@;
  791.   case thin_space: app_str("\,"); app_scrap(insert,maybe_math);@+break;
  792. @.\,@>
  793.   case math_break: app(opt); app_str("0");
  794.     app_scrap(insert,maybe_math);@+break;
  795.   case line_break: app(force); app_scrap(insert,no_math);@+break;
  796.   case left_preproc: app(force); app(preproc_line);
  797.     app_str("\#"); app_scrap(lproc,no_math);@+break;
  798. @.\#@>
  799.   case right_preproc: app(force); app_scrap(rproc,no_math);@+break;
  800.   case big_line_break: app(big_force); app_scrap(insert,no_math);@+break;
  801.   case no_line_break: app(big_cancel); app(noop); app(break_space);
  802.     app(noop); app(big_cancel);
  803.     app_scrap(insert,no_math);@+break;
  804.   case pseudo_semi: app_scrap(semi,maybe_math);@+break;
  805.   case macro_arg_open: app_scrap(begin_arg,maybe_math);@+break;
  806.   case macro_arg_close: app_scrap(end_arg,maybe_math);@+break;
  807.   case join: app_str("\J"); app_scrap(insert,no_math);@+break;
  808. @.\J@>
  809.   case output_defs_code: app(force); app_str("\ATH"); app(force);
  810.     app_scrap(insert,no_math);@+break;
  811. @.\ATH@>
  812.   default: app(inserted); app(next_control);
  813.     app_scrap(insert,maybe_math);@+break;
  814. }
  815. @ @<Make sure that there is room for the new...@>=
  816. if (scrap_ptr+safe_scrap_incr>scrap_info_end ||
  817.   tok_ptr+safe_tok_incr>tok_mem_end @| ||
  818.   text_ptr+safe_text_incr>tok_start_end) {
  819.   if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
  820.   if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
  821.   if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
  822.   overflow("scrap/token/text");
  823. }
  824. @ Some nonstandard characters may have entered .{CWEAVE} by means of
  825. standard ones. They are converted to TEX/ control sequences so that it is
  826. possible to keep .{CWEAVE} from outputting unusual |char| codes.
  827. @<Cases involving nonstandard...@>=
  828. case not_eq: app_str("\I");@+app_scrap(binop,yes_math);@+break;
  829. @.\I@>
  830. case lt_eq: app_str("\Z");@+app_scrap(binop,yes_math);@+break;
  831. @.\Z@>
  832. case gt_eq: app_str("\G");@+app_scrap(binop,yes_math);@+break;
  833. @.\G@>
  834. case eq_eq: app_str("\E");@+app_scrap(binop,yes_math);@+break;
  835. @.\E@>
  836. case and_and: app_str("\W");@+app_scrap(binop,yes_math);@+break;
  837. @.\W@>
  838. case or_or: app_str("\V");@+app_scrap(binop,yes_math);@+break;
  839. @.\V@>
  840. case plus_plus: app_str("\PP");@+app_scrap(unop,yes_math);@+break;
  841. @.\PP@>
  842. case minus_minus: app_str("\MM");@+app_scrap(unop,yes_math);@+break;
  843. @.\MM@>
  844. case minus_gt: app_str("\MG");@+app_scrap(binop,yes_math);@+break;
  845. @.\MG@>
  846. case gt_gt: app_str("\GG");@+app_scrap(binop,yes_math);@+break;
  847. @.\GG@>
  848. case lt_lt: app_str("\LL");@+app_scrap(binop,yes_math);@+break;
  849. @.\LL@>
  850. case dot_dot_dot: app_str("\,\ldots\,");@+app_scrap(exp,yes_math);@+break;
  851. @.\,@>
  852. @.\ldots@>
  853. case colon_colon: app_str("\DC");@+app_scrap(colcol,maybe_math);@+break;
  854. @.\DC@>
  855. case period_ast: app_str("\PA");@+app_scrap(binop,yes_math);@+break;
  856. @.\PA@>
  857. case minus_gt_ast: app_str("\MGA");@+app_scrap(binop,yes_math);@+break;
  858. @.\MGA@>
  859. @ The following code must use |app_tok| instead of |app| in order to
  860. protect against overflow. Note that |tok_ptr+1<=max_toks| after |app_tok|
  861. has been used, so another |app| is legitimate before testing again.
  862. Many of the special characters in a string must be prefixed by `.\' so that
  863. TEX/ will print them properly.
  864. @^special string characters@>
  865. @<Append a string or...@>=
  866. count= -1;
  867. if (next_control==constant) app_str("\T{"@q}@>);
  868. @.\T@>
  869. else if (next_control==string) {
  870.   count=20; app_str("\.{"@q}@>);
  871. }
  872. @.\.@>
  873. else app_str("\vb{"@q}@>);
  874. @.\vb@>
  875. while (id_first<id_loc) {
  876.   if (count==0) { /* insert a discretionary break in a long string */
  877.      app_str(@q(@>@q{@>"}\)\.{"@q}@>); count=20;
  878. @q(@>@.\)@>
  879.   }
  880. @^high-bit character handling@>
  881.   if((eight_bits)(*id_first)>0177) {
  882.     app_tok(quoted_char);
  883.     app_tok((eight_bits)(*id_first++));
  884.   }
  885.   else {
  886.     switch (*id_first) {
  887.       case  ' ':case '\':case '#':case '%':case '$':case '^':
  888.       case '{': case '}': case '~': case '&': case '_': app('\'); break;
  889. @.\ @>
  890. @.\\@>
  891. @.\#@>
  892. @.\%@>
  893. @.\$@>
  894. @.\^@>
  895. @.\{@>@q}@>
  896. @q{@>@.\}@>
  897. @.\~@>
  898. @.\&@>
  899. @.\_@>  @q CWEAVE does quote an underscore! @>
  900.       case '@@': if (*(id_first+1)=='@@') id_first++;
  901.         else err_print("! Double @@ should be used in strings");
  902. @.Double @@ should be used...@>
  903.     }
  904.     app_tok(*id_first++);
  905.   }
  906.   count--;
  907. }
  908. app(@q{@>'}');
  909. app_scrap(exp,maybe_math);
  910. @ We do not make the TEX/ string into a scrap, because there is no
  911. telling what the user will be putting into it; instead we leave it
  912. open, to be picked up by the next scrap. If it comes at the end of a
  913. section, it will be made into a scrap when |finish_C| is called.
  914. There's a known bug here, in cases where an adjacent scrap is
  915. |prelangle| or |prerangle|. Then the TEX/ string can disappear
  916. when the .{\langle} or .{\rangle} becomes .{<} or .{>}.
  917. For example, if the user writes .{v x<@@ty@@>v}, the TEX/ string
  918. .{\hbox{y}} eventually becomes part of an |insert| scrap, which is combined
  919. with a |prelangle| scrap and eventually lost. The best way to work around
  920. this bug is probably to enclose the .{@@t...@@>} in .{@@[...@@]} so that
  921. the TEX/ string is treated as an expression.
  922. @^bug, known@>
  923. @<Append a TEX/ string, without forming a scrap@>=
  924. app_str("\hbox{"@q}@>);
  925. @^high-bit character handling@>
  926. while (id_first<id_loc)
  927.   if((eight_bits)(*id_first)>0177) {
  928.     app_tok(quoted_char);
  929.     app_tok((eight_bits)(*id_first++));
  930.   }
  931.   else {
  932.     if (*id_first=='@@') id_first++;
  933.     app_tok(*id_first++);
  934.   }
  935. app(@q{@>'}');
  936. @ The function |app_cur_id| appends the current identifier to the
  937. token list; it also builds a new scrap if |scrapping==1|.
  938. @<Predec...@>=
  939. void app_cur_id();
  940. @ @c
  941. void
  942. app_cur_id(scrapping)
  943. boolean scrapping; /* are we making this into a scrap? */
  944. {
  945.   name_pointer p=id_lookup(id_first,id_loc,normal);
  946.   if (p->ilk<=quoted) { /* not a reserved word */
  947.     app(id_flag+(int)(p-name_dir));
  948.     if (scrapping) app_scrap(exp,p->ilk>=custom? yes_math: maybe_math);
  949. @.\NULL@>
  950.   } else {
  951.     app(res_flag+(int)(p-name_dir));
  952.     if (scrapping) app_scrap(p->ilk,maybe_math);
  953.   }
  954. }
  955. @ When the `.{v}' that introduces CEE/ text is sensed, a call on
  956. |C_translate| will return a pointer to the TEX/ translation of
  957. that text. If scraps exist in |scrap_info|, they are
  958. unaffected by this translation process.
  959. @c
  960. text_pointer
  961. C_translate()
  962. {
  963.   text_pointer p; /* points to the translation */
  964.   scrap_pointer save_base; /* holds original value of |scrap_base| */
  965.   save_base=scrap_base; scrap_base=scrap_ptr+1;
  966.   C_parse(section_name); /* get the scraps together */
  967.   if (next_control!='|') err_print("! Missing '|' after C text");
  968. @.Missing '|'...@>
  969.   app_tok(cancel); app_scrap(insert,maybe_math);
  970.         /* place a |cancel| token as a final ``comment'' */
  971.   p=translate(); /* make the translation */
  972.   if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
  973.   scrap_ptr=scrap_base-1; scrap_base=save_base; /* scrap the scraps */
  974.   return(p);
  975. }
  976. @ The |outer_parse| routine is to |C_parse| as |outer_xref|
  977. is to |C_xref|: it constructs a sequence of scraps for CEE/ text
  978. until |next_control>=format_code|. Thus, it takes care of embedded comments.
  979. @c
  980. void
  981. outer_parse() /* makes scraps from CEE/ tokens and comments */
  982. {
  983.   int bal; /* brace level in comment */
  984.   text_pointer p, q; /* partial comments */
  985.   while (next_control<format_code)
  986.     if (next_control!=begin_comment && next_control!=begin_short_comment)
  987.       C_parse(ignore);
  988.     else {
  989.       boolean is_long_comment=(next_control==begin_comment);
  990.       @<Make sure that there is room for the new...@>;
  991.       app(cancel); app(inserted);
  992.       if (is_long_comment) app_str("\C{"@q}@>);
  993. @.\C@>
  994.       else app_str("\SHC{"@q}@>);
  995. @.\SHC@>
  996.       bal=copy_comment(is_long_comment,1); next_control=ignore;
  997.       while (bal>0) {
  998.         p=text_ptr; freeze_text; q=C_translate();
  999.          /* at this point we have |tok_ptr+6<=max_toks| */
  1000.         app(tok_flag+(int)(p-tok_start));
  1001.         app_str("\PB{"); app(inner_tok_flag+(int)(q-tok_start)); app_tok('}');
  1002. @.\PB@>
  1003.         if (next_control=='|') {
  1004.           bal=copy_comment(is_long_comment,bal);
  1005.           next_control=ignore;
  1006.         }
  1007.         else bal=0; /* an error has been reported */
  1008.       }
  1009.       app(force); app_scrap(insert,no_math);
  1010.         /* the full comment becomes a scrap */
  1011.     }
  1012. }
  1013. @* Output of tokens.
  1014. So far our programs have only built up multi-layered token lists in
  1015. .{CWEAVE}'s internal memory; we have to figure out how to get them into
  1016. the desired final form. The job of converting token lists to characters in
  1017. the TEX/ output file is not difficult, although it is an implicitly
  1018. recursive process. Four main considerations had to be kept in mind when
  1019. this part of .{CWEAVE} was designed.  (a) There are two modes of output:
  1020. |outer| mode, which translates tokens like |force| into line-breaking
  1021. control sequences, and |inner| mode, which ignores them except that blank
  1022. spaces take the place of line breaks. (b) The |cancel| instruction applies
  1023. to adjacent token or tokens that are output, and this cuts across levels
  1024. of recursion since `|cancel|' occurs at the beginning or end of a token
  1025. list on one level. (c) The TEX/ output file will be semi-readable if line
  1026. breaks are inserted after the result of tokens like |break_space| and
  1027. |force|.  (d) The final line break should be suppressed, and there should
  1028. be no |force| token output immediately after `.{\Y\B}'.
  1029. @ The output process uses a stack to keep track of what is going on at
  1030. different ``levels'' as the token lists are being written out. Entries on
  1031. this stack have three parts:
  1032. yskiphang |end_field| is the |tok_mem| location where the token list of a
  1033. particular level will end;
  1034. yskiphang |tok_field| is the |tok_mem| location from which the next token
  1035. on a particular level will be read;
  1036. yskiphang |mode_field| is the current mode, either |inner| or |outer|.
  1037. yskipnoindent The current values of these quantities are referred to
  1038. quite frequently, so they are stored in a separate place instead of in the
  1039. |stack| array. We call the current values |cur_end|, |cur_tok|, and
  1040. |cur_mode|.
  1041. The global variable |stack_ptr| tells how many levels of output are
  1042. currently in progress. The end of output occurs when an |end_translation|
  1043. token is found, so the stack is never empty except when we first begin the
  1044. output process.
  1045. @d inner 0 /* value of |mode| for CEE/ texts within TEX/ texts */
  1046. @d outer 1 /* value of |mode| for CEE/ texts in sections */
  1047. @<Typed...@>= typedef int mode;
  1048. typedef struct {
  1049.   token_pointer end_field; /* ending location of token list */
  1050.   token_pointer tok_field; /* present location within token list */
  1051.   boolean mode_field; /* interpretation of control tokens */
  1052. } output_state;
  1053. typedef output_state *stack_pointer;
  1054. @ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */
  1055. @d cur_tok cur_state.tok_field /* location of next output token in |tok_mem| */
  1056. @d cur_mode cur_state.mode_field /* current mode of interpretation */
  1057. @d init_stack stack_ptr=stack;cur_mode=outer /* initialize the stack */
  1058. @<Global...@>=
  1059. output_state cur_state; /* |cur_end|, |cur_tok|, |cur_mode| */
  1060. output_state stack[stack_size]; /* info for non-current levels */
  1061. stack_pointer stack_ptr; /* first unused location in the output state stack */
  1062. stack_pointer stack_end=stack+stack_size-1; /* end of |stack| */
  1063. stack_pointer max_stack_ptr; /* largest value assumed by |stack_ptr| */
  1064. @ @<Set init...@>=
  1065. max_stack_ptr=stack;
  1066. @ To insert token-list |p| into the output, the |push_level| subroutine
  1067. is called; it saves the old level of output and gets a new one going.
  1068. The value of |cur_mode| is not changed.
  1069. @c
  1070. void
  1071. push_level(p) /* suspends the current level */
  1072. text_pointer p;
  1073. {
  1074.   if (stack_ptr==stack_end) overflow("stack");
  1075.   if (stack_ptr>stack) { /* save current state */
  1076.     stack_ptr->end_field=cur_end;
  1077.     stack_ptr->tok_field=cur_tok;
  1078.     stack_ptr->mode_field=cur_mode;
  1079.   }
  1080.   stack_ptr++;
  1081.   if (stack_ptr>max_stack_ptr) max_stack_ptr=stack_ptr;
  1082.   cur_tok=*p; cur_end=*(p+1);
  1083. }
  1084. @ Conversely, the |pop_level| routine restores the conditions that were in
  1085. force when the current level was begun. This subroutine will never be
  1086. called when |stack_ptr==1|.
  1087. @c
  1088. void
  1089. pop_level()
  1090. {
  1091.   cur_end=(--stack_ptr)->end_field;
  1092.   cur_tok=stack_ptr->tok_field; cur_mode=stack_ptr->mode_field;
  1093. }
  1094. @ The |get_output| function returns the next byte of output that is not a
  1095. reference to a token list. It returns the values |identifier| or |res_word|
  1096. or |section_code| if the next token is to be an identifier (typeset in
  1097. italics), a reserved word (typeset in boldface) or a section name (typeset
  1098. by a complex routine that might generate additional levels of output).
  1099. In these cases |cur_name| points to the identifier or section name in
  1100. question.
  1101. @<Global...@>=
  1102. name_pointer cur_name;
  1103. @ @d res_word 0201 /* returned by |get_output| for reserved words */
  1104. @d section_code 0200 /* returned by |get_output| for section names */
  1105. @c
  1106. eight_bits
  1107. get_output() /* returns the next token of output */
  1108. {
  1109.   sixteen_bits a; /* current item read from |tok_mem| */
  1110.   restart: while (cur_tok==cur_end) pop_level();
  1111.   a=*(cur_tok++);
  1112.   if (a>=0400) {
  1113.     cur_name=a % id_flag + name_dir;
  1114.     switch (a / id_flag) {
  1115.       case 2: return(res_word); /* |a==res_flag+cur_name| */
  1116.       case 3: return(section_code); /* |a==section_flag+cur_name| */
  1117.       case 4: push_level(a % id_flag + tok_start); goto restart;
  1118.         /* |a==tok_flag+cur_name| */
  1119.       case 5: push_level(a % id_flag + tok_start); cur_mode=inner; goto restart;
  1120.         /* |a==inner_tok_flag+cur_name| */
  1121.       default: return(identifier); /* |a==id_flag+cur_name| */
  1122.     }
  1123.   }
  1124.   return(a);
  1125. }
  1126. @ The real work associated with token output is done by |make_output|.
  1127. This procedure appends an |end_translation| token to the current token list,
  1128. and then it repeatedly calls |get_output| and feeds characters to the output
  1129. buffer until reaching the |end_translation| sentinel. It is possible for
  1130. |make_output| to be called recursively, since a section name may include
  1131. embedded CEE/ text; however, the depth of recursion never exceeds one
  1132. level, since section names cannot be inside of section names.
  1133. A procedure called |output_C| does the scanning, translation, and
  1134. output of CEE/ text within `pb' brackets, and this procedure uses
  1135. |make_output| to output the current token list. Thus, the recursive call
  1136. of |make_output| actually occurs when |make_output| calls |output_C|
  1137. while outputting the name of a section.
  1138. @^recursion@>
  1139. The token list created from within `pb' brackets is output as an argument
  1140. to .{\PB}. Although .{cwebmac} ignores .{\PB}, other macro packages
  1141. might use it to localize the special meaning of the macros that mark up
  1142. program text.
  1143. @c
  1144. void
  1145. output_C() /* outputs the current token list */
  1146. {
  1147.   token_pointer save_tok_ptr;
  1148.   text_pointer save_text_ptr;
  1149.   sixteen_bits save_next_control; /* values to be restored */
  1150.   text_pointer p; /* translation of the CEE/ text */
  1151.   save_tok_ptr=tok_ptr; save_text_ptr=text_ptr;
  1152.   save_next_control=next_control; next_control=ignore; p=C_translate();
  1153.   app(inner_tok_flag+(int)(p-tok_start));
  1154.   out_str("\PB{"); make_output(); out('}'); /* output the list */
  1155. @.\PB@>
  1156.   if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
  1157.   if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
  1158.   text_ptr=save_text_ptr; tok_ptr=save_tok_ptr; /* forget the tokens */
  1159.   next_control=save_next_control; /* restore |next_control| to original state */
  1160. }
  1161. @ Here is .{CWEAVE}'s major output handler.
  1162. @<Predecl...@>=
  1163. void make_output();
  1164. @ @c
  1165. void
  1166. make_output() /* outputs the equivalents of tokens */
  1167. {
  1168.   eight_bits a, /* current output byte */
  1169.   b; /* next output byte */
  1170.   int c; /* count of |indent| and |outdent| tokens */
  1171.   char scratch[longest_name]; /* scratch area for section names */
  1172.   char *k, *k_limit; /* indices into |scratch| */
  1173.   char *j; /* index into |buffer| */
  1174.   char *p; /* index into |byte_mem| */
  1175.   char delim; /* first and last character of string being copied */
  1176.   char *save_loc, *save_limit; /* |loc| and |limit| to be restored */
  1177.   name_pointer cur_section_name; /* name of section being output */
  1178.   boolean save_mode; /* value of |cur_mode| before a sequence of breaks */
  1179.   app(end_translation); /* append a sentinel */
  1180.   freeze_text; push_level(text_ptr-1);
  1181.   while (1) {
  1182.     a=get_output();
  1183.     reswitch: switch(a) {
  1184.       case end_translation: return;
  1185.       case identifier: case res_word: @<Output an identifier@>; break;
  1186.       case section_code: @<Output a section name@>; break;
  1187.       case math_rel: out_str("\MRL{"@q}@>);
  1188. @.\MRL@>
  1189.       case noop: case inserted: break;
  1190.       case cancel: case big_cancel: c=0; b=a;
  1191.         while (1) {
  1192.           a=get_output();
  1193.           if (a==inserted) continue;
  1194.           if ((a<indent && !(b==big_cancel&&a==' ')) || a>big_force) break;
  1195.           if (a==indent) c++; else if (a==outdent) c--;
  1196.           else if (a==opt) a=get_output();
  1197.         }
  1198.         @<Output saved |indent| or |outdent| tokens@>;
  1199.         goto reswitch;
  1200.       case indent: case outdent: case opt: case backup: case break_space:
  1201.       case force: case big_force: case preproc_line: @<Output a control,
  1202.         look ahead in case of line breaks, possibly |goto reswitch|@>; break;
  1203.       case quoted_char: out(*(cur_tok++)); break;
  1204.       default: out(a); /* otherwise |a| is an ordinary character */
  1205.     }
  1206.   }
  1207. }
  1208. @ An identifier of length one does not have to be enclosed in braces, and it
  1209. looks slightly better if set in a math-italic font instead of a (slightly
  1210. narrower) text-italic font. Thus we output `.{\v}.{a}' but
  1211. `.{\\{aa}}'.
  1212. @<Output an identifier@>=
  1213. out('\');
  1214. if (a==identifier) {
  1215.   if (cur_name->ilk>=custom && cur_name->ilk<=quoted && !doing_format) {
  1216.     for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
  1217.       out(isxalpha(*p)? 'x':*p);
  1218.     break;
  1219.   } else if (is_tiny(cur_name)) out('|')
  1220. @.\|@>
  1221.   else { delim='.';
  1222.     for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
  1223.       if (xislower(*p)) { /* not entirely uppercase */
  1224.          delim='\'; break;
  1225.       }
  1226.   out(delim);
  1227.   }
  1228. @.\\@>
  1229. @.\.@>
  1230. }
  1231. else out('&') /* |a==res_word| */
  1232. @.\&@>
  1233. if (is_tiny(cur_name)) {
  1234.   if (isxalpha((cur_name->byte_start)[0]))
  1235.     out('\');
  1236.   out((cur_name->byte_start)[0]);
  1237. }
  1238. else out_name(cur_name);
  1239. @ The current mode does not affect the behavior of .{CWEAVE}'s output routine
  1240. except when we are outputting control tokens.
  1241. @<Output a control...@>=
  1242. if (a<break_space || a==preproc_line) {
  1243.   if (cur_mode==outer) {
  1244.     out('\'); out(a-cancel+'0');
  1245. @.\1@>
  1246. @.\2@>
  1247. @.\3@>
  1248. @.\4@>
  1249. @.\8@>
  1250.     if (a==opt) {
  1251.       b=get_output(); /* |opt| is followed by a digit */
  1252.       if (b!='0' || force_lines==0) out(b)@;
  1253.       else out_str("{-1}"); /* |force_lines| encourages more .{@@v} breaks */
  1254.     }
  1255.   } else if (a==opt) b=get_output(); /* ignore digit following |opt| */
  1256.   }
  1257. else @<Look ahead for strongest line break, |goto reswitch|@>
  1258. @ If several of the tokens |break_space|, |force|, |big_force| occur in a
  1259. row, possibly mixed with blank spaces (which are ignored),
  1260. the largest one is used. A line break also occurs in the output file,
  1261. except at the very end of the translation. The very first line break
  1262. is suppressed (i.e., a line break that follows `.{\Y\B}').
  1263. @<Look ahead for st...@>= {
  1264.   b=a; save_mode=cur_mode; c=0;
  1265.   while (1) {
  1266.     a=get_output();
  1267.     if (a==inserted) continue;
  1268.     if (a==cancel || a==big_cancel) {
  1269.       @<Output saved |indent| or |outdent| tokens@>;
  1270.       goto reswitch; /* |cancel| overrides everything */
  1271.     }
  1272.     if ((a!=' ' && a<indent) || a==backup || a>big_force) {
  1273.       if (save_mode==outer) {
  1274.         if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\Y\B",4)==0)
  1275.           goto reswitch;
  1276.         @<Output saved |indent| or |outdent| tokens@>;
  1277.         out('\'); out(b-cancel+'0');
  1278. @.\5@>
  1279. @.\6@>
  1280. @.\7@>
  1281.         if (a!=end_translation) finish_line();
  1282.       }
  1283.       else if (a!=end_translation && cur_mode==inner) out(' ');
  1284.       goto reswitch;
  1285.     }
  1286.     if (a==indent) c++;
  1287.     else if (a==outdent) c--;
  1288.     else if (a==opt) a=get_output();
  1289.     else if (a>b) b=a; /* if |a==' '| we have |a<b| */
  1290.   }
  1291. }
  1292. @ @<Output saved...@>=
  1293.   for (;c>0;c--) out_str("\1");
  1294. @.\1@>
  1295.   for (;c<0;c++) out_str("\2");
  1296. @.\2@>
  1297. @ The remaining part of |make_output| is somewhat more complicated. When we
  1298. output a section name, we may need to enter the parsing and translation
  1299. routines, since the name may contain CEE/ code embedded in
  1300. pb constructions. This CEE/ code is placed at the end of the active
  1301. input buffer and the translation process uses the end of the active
  1302. |tok_mem| area.
  1303. @<Output a section name@>= {
  1304.   out_str("\X");
  1305. @.\X@>
  1306.   cur_xref=(xref_pointer)cur_name->xref;
  1307.   if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;}
  1308.   else an_output=0;
  1309.   if (cur_xref->num>=def_flag) {
  1310.     out_section(cur_xref->num-def_flag);
  1311.     if (phase==3) {
  1312.       cur_xref=cur_xref->xlink;
  1313.       while (cur_xref->num>=def_flag) {
  1314.         out_str(", ");
  1315.         out_section(cur_xref->num-def_flag);
  1316.       cur_xref=cur_xref->xlink;
  1317.       }
  1318.     }
  1319.   }
  1320.   else out('0'); /* output the section number, or zero if it was undefined */
  1321.   out(':');
  1322.   if (an_output) out_str("\.{"@q}@>);
  1323. @.\.@>
  1324.   @<Output the text of the section name@>;
  1325.   if (an_output) out_str(@q{@>" }");
  1326.   out_str("\X");
  1327. }
  1328. @ @<Output the text...@>=
  1329. sprint_section_name(scratch,cur_name);
  1330. k=scratch;
  1331. k_limit=scratch+strlen(scratch);
  1332. cur_section_name=cur_name;
  1333. while (k<k_limit) {
  1334.   b=*(k++);
  1335.   if (b=='@@') @<Skip next character, give error if not `.{@@}'@>;
  1336.   if (an_output)
  1337.     switch (b) {
  1338.  case  ' ':case '\':case '#':case '%':case '$':case '^':
  1339.  case '{': case '}': case '~': case '&': case '_':
  1340.     out('\'); /* falls through */
  1341. @.\ @>
  1342. @.\\@>
  1343. @.\#@>
  1344. @.\%@>
  1345. @.\$@>
  1346. @.\^@>
  1347. @.\{@>@q}@>
  1348. @q{@>@.\}@>
  1349. @.\~@>
  1350. @.\&@>
  1351. @.\_@>  @q CWEAVE does quote an underscore! @>
  1352.  default: out(b);
  1353.     }
  1354.   else if (b!='|') out(b)
  1355.   else {
  1356.     @<Copy the CEE/ text into the |buffer| array@>;
  1357.     save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1;
  1358.     *limit='|'; output_C();
  1359.     loc=save_loc; limit=save_limit;
  1360.   }
  1361. }
  1362. @ @<Skip next char...@>=
  1363. if (*k++!='@@') {
  1364.   printf("n! Illegal control code in section name: <");
  1365. @.Illegal control code...@>
  1366.   print_section_name(cur_section_name); printf("> "); mark_error;
  1367. }
  1368. @ The CEE/ text enclosed in pb should not contain `.{v}' characters,
  1369. except within strings. We put a `.{v}' at the front of the buffer, so that an
  1370. error message that displays the whole buffer will look a little bit sensible.
  1371. The variable |delim| is zero outside of strings, otherwise it
  1372. equals the delimiter that began the string being copied.
  1373. @<Copy the CEE/ text into...@>=
  1374. j=limit+1; *j='|'; delim=0;
  1375. while (1) {
  1376.   if (k>=k_limit) {
  1377.     printf("n! C text in section name didn't end: <");
  1378. @.C text...didn't end@>
  1379.     print_section_name(cur_section_name); printf("> "); mark_error; break;
  1380.   }
  1381.   b=*(k++);
  1382.   if (b=='@@' || (b=='\' && delim!=0))
  1383.      @<Copy a quoted character into the buffer@>
  1384.   else {
  1385.     if (b==''' || b=='"')
  1386.       if (delim==0) delim=b;
  1387.       else if (delim==b) delim=0;
  1388.     if (b!='|' || delim!=0) {
  1389.       if (j>buffer+long_buf_size-3) overflow("buffer");
  1390.       *(++j)=b;
  1391.     }
  1392.     else break;
  1393.   }
  1394. }
  1395. @ @<Copy a quoted char...@>= {
  1396.   if (j>buffer+long_buf_size-4) overflow("buffer");
  1397.   *(++j)=b; *(++j)=*(k++);
  1398. }
  1399. @** Phase two processing.
  1400. We have assembled enough pieces of the puzzle in order to be ready to specify
  1401. the processing in .{CWEAVE}'s main pass over the source file. Phase two
  1402. is analogous to phase one, except that more work is involved because we must
  1403. actually output the TEX/ material instead of merely looking at the
  1404. .{CWEB} specifications.
  1405. @<Predecl...@>=
  1406. void phase_two();
  1407. @ @c
  1408. void
  1409. phase_two() {
  1410. reset_input(); if (show_progress) printf("nWriting the output file...");
  1411. @.Writing the output file...@>
  1412. section_count=0; format_visible=1; copy_limbo();
  1413. finish_line(); flush_buffer(out_buf,0,0); /* insert a blank line, it looks nice */
  1414. while (!input_has_ended) @<Translate the current section@>;
  1415. }
  1416. @ The output file will contain the control sequence .{\Y} between non-null
  1417. sections of a section, e.g., between the TEX/ and definition parts if both
  1418. are nonempty. This puts a little white space between the parts when they are
  1419. printed. However, we don't want .{\Y} to occur between two definitions
  1420. within a single section. The variables |out_line| or |out_ptr| will
  1421. change if a section is non-null, so the following macros `|save_position|'
  1422. and `|emit_space_if_needed|' are able to handle the situation:
  1423. @d save_position save_line=out_line; save_place=out_ptr
  1424. @d emit_space_if_needed if (save_line!=out_line || save_place!=out_ptr)
  1425.   out_str("\Y");
  1426.   space_checked=1
  1427. @.\Y@>
  1428. @<Global...@>=
  1429. int save_line; /* former value of |out_line| */
  1430. char *save_place; /* former value of |out_ptr| */
  1431. int sec_depth; /* the integer, if any, following .{@@*} */
  1432. boolean space_checked; /* have we done |emit_space_if_needed|? */
  1433. boolean format_visible; /* should the next format declaration be output? */
  1434. boolean doing_format=0; /* are we outputting a format declaration? */
  1435. boolean group_found=0; /* has a starred section occurred? */
  1436. @ @<Translate the current section@>= {
  1437.   section_count++;
  1438.   @<Output the code for the beginning of a new section@>;
  1439.   save_position;
  1440.   @<Translate the TEX/ part of the current section@>;
  1441.   @<Translate the definition part of the current section@>;
  1442.   @<Translate the CEE/ part of the current section@>;
  1443.   @<Show cross-references to this section@>;
  1444.   @<Output the code for the end of a section@>;
  1445. }
  1446. @ Sections beginning with the .{CWEB} control sequence `.{@@ }' start in the
  1447. output with the TEX/ control sequence `.{\M}', followed by the section
  1448. number. Similarly, `.{@@*}' sections lead to the control sequence `.{\N}'.
  1449. In this case there's an additional parameter, representing one plus the
  1450. specified depth, immediately after the .{\N}.
  1451. If the section has changed, we put .{\*} just after the section number.
  1452. @<Output the code for the beginning...@>=
  1453. if (*(loc-1)!='*') out_str("\M");
  1454. @.\M@>
  1455. else {
  1456.   while (*loc == ' ') loc++;
  1457.   if (*loc=='*') { /* ``top'' level */
  1458.     sec_depth = -1;
  1459.     loc++;
  1460.   }
  1461.   else {
  1462.     for (sec_depth=0; xisdigit(*loc);loc++)
  1463.       sec_depth = sec_depth*10 + (*loc) -'0';
  1464.   }
  1465.   while (*loc == ' ') loc++; /* remove spaces before group title */
  1466.   group_found=1;
  1467.   out_str("\N");
  1468. @.\N@>
  1469.   {@+ char s[32];@+sprintf(s,"{%d}",sec_depth+1);@+out_str(s);@+}
  1470.   if (show_progress)
  1471.   printf("*%d",section_count); update_terminal; /* print a progress report */
  1472. }
  1473. out_str("{");out_section(section_count); out_str("}");
  1474. @ In the TEX/ part of a section, we simply copy the source text, except that
  1475. index entries are not copied and CEE/ text within pb is translated.
  1476. @<Translate the T...@>= do {
  1477.   next_control=copy_TeX();
  1478.   switch (next_control) {
  1479.     case '|': init_stack; output_C(); break;
  1480.     case '@@': out('@@'); break;
  1481.     case TeX_string: case noop:
  1482.     case xref_roman: case xref_wildcard: case xref_typewriter:
  1483.     case section_name: loc-=2; next_control=get_next(); /* skip to .{@@>} */
  1484.       if (next_control==TeX_string)
  1485.         err_print("! TeX string should be in C text only"); break;
  1486. @.TeX string should be...@>
  1487.     case thin_space: case math_break: case ord:
  1488.     case line_break: case big_line_break: case no_line_break: case join:
  1489.     case pseudo_semi: case macro_arg_open: case macro_arg_close:
  1490.     case output_defs_code:
  1491.         err_print("! You can't do that in TeX text"); break;
  1492. @.You can't do that...@>
  1493.   }
  1494. } while (next_control<format_code);
  1495. @ When we get to the following code we have |next_control>=format_code|, and
  1496. the token memory is in its initial empty state.
  1497. @<Translate the d...@>=
  1498. space_checked=0;
  1499. while (next_control<=definition) { /* |format_code| or |definition| */
  1500.   init_stack;
  1501.   if (next_control==definition) @<Start a macro definition@>@;
  1502.   else @<Start a format definition@>;
  1503.   outer_parse(); finish_C(format_visible); format_visible=1;
  1504.   doing_format=0;
  1505. }
  1506. @ The |finish_C| procedure outputs the translation of the current
  1507. scraps, preceded by the control sequence `.{\B}' and followed by the
  1508. control sequence `.{\par}'. It also restores the token and scrap
  1509. memories to their initial empty state.
  1510. A |force| token is appended to the current scraps before translation
  1511. takes place, so that the translation will normally end with .{\6} or
  1512. .{\7} (the TEX/ macros for |force| and |big_force|). This .{\6} or
  1513. .{\7} is replaced by the concluding .{\par} or by .{\Y\par}.
  1514. @<Predecl...@>=
  1515. void finish_C();
  1516. @ @c
  1517. void
  1518. finish_C(visible) /* finishes a definition or a CEE/ part */
  1519.   boolean visible; /* nonzero if we should produce TEX/ output */
  1520. {
  1521.   text_pointer p; /* translation of the scraps */
  1522.   if (visible) {
  1523.     out_str("\B"); app_tok(force); app_scrap(insert,no_math);
  1524.     p=translate();
  1525. @.\B@>
  1526.     app(tok_flag+(int)(p-tok_start)); make_output(); /* output the list */
  1527.     if (out_ptr>out_buf+1)
  1528.       if (*(out_ptr-1)=='\')
  1529. @.\6@>
  1530. @.\7@>
  1531. @.\Y@>
  1532.         if (*out_ptr=='6') out_ptr-=2;
  1533.         else if (*out_ptr=='7') *out_ptr='Y';
  1534.     out_str("\par"); finish_line();
  1535.   }
  1536.   if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
  1537.   if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
  1538.   if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
  1539.   tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info;
  1540.     /* forget the tokens and the scraps */
  1541. }
  1542. @ Keeping in line with the conventions of the CEE/ preprocessor (and
  1543. otherwise contrary to the rules of .{CWEB}) we distinguish here
  1544. between the case that `.(' immediately follows an identifier and the
  1545. case that the two are separated by a space.  In the latter case, and
  1546. if the identifier is not followed by `.(' at all, the replacement
  1547. text starts immediately after the identifier.  In the former case,
  1548. it starts after we scan the matching `.)'.
  1549. @<Start a macro...@>= {
  1550.   if (save_line!=out_line || save_place!=out_ptr || space_checked) app(backup);
  1551.   if(!space_checked){emit_space_if_needed;save_position;}
  1552.   app_str("\D"); /* this will produce `&{define }' */
  1553. @.\D@>
  1554.   if ((next_control=get_next())!=identifier)
  1555.     err_print("! Improper macro definition");
  1556. @.Improper macro definition@>
  1557.   else {
  1558.     app('$'); app_cur_id(0);
  1559.     if (*loc=='(')
  1560.   reswitch: switch (next_control=get_next()) {
  1561.       case '(': case ',': app(next_control); goto reswitch;
  1562.       case identifier: app_cur_id(0); goto reswitch;
  1563.       case ')': app(next_control); next_control=get_next(); break;
  1564.       default: err_print("! Improper macro definition"); break;
  1565.     }
  1566.     else next_control=get_next();
  1567.     app_str("$ "); app(break_space);
  1568.     app_scrap(dead,no_math); /* scrap won't take part in the parsing */
  1569.   }
  1570. }
  1571. @ @<Start a format...@>= {
  1572.   doing_format=1;
  1573.   if(*(loc-1)=='s' || *(loc-1)=='S') format_visible=0;
  1574.   if(!space_checked){emit_space_if_needed;save_position;}
  1575.   app_str("\F"); /* this will produce `&{format }' */
  1576. @.\F@>
  1577.   next_control=get_next();
  1578.   if (next_control==identifier) {
  1579.     app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir));
  1580.     app(' ');
  1581.     app(break_space); /* this is syntactically separate from what follows */
  1582.     next_control=get_next();
  1583.     if (next_control==identifier) {
  1584.       app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir));
  1585.       app_scrap(exp,maybe_math); app_scrap(semi,maybe_math);
  1586.       next_control=get_next();
  1587.     }
  1588.   }
  1589.   if (scrap_ptr!=scrap_info+2) err_print("! Improper format definition");
  1590. @.Improper format definition@>
  1591. }
  1592. @ Finally, when the TEX/ and definition parts have been treated, we have
  1593. |next_control>=begin_C|. We will make the global variable |this_section|
  1594. point to the current section name, if it has a name.
  1595. @<Global...@>=
  1596. name_pointer this_section; /* the current section name, or zero */
  1597. @ @<Translate the CEE/...@>=
  1598. this_section=name_dir;
  1599. if (next_control<=section_name) {
  1600.   emit_space_if_needed; init_stack;
  1601.   if (next_control==begin_C) next_control=get_next();
  1602.   else {
  1603.     this_section=cur_section;
  1604.     @<Check that '=' or '==' follows this section name, and
  1605.       emit the scraps to start the section definition@>;
  1606.   }
  1607.   while  (next_control<=section_name) {
  1608.     outer_parse();
  1609.     @<Emit the scrap for a section name if present@>;
  1610.   }
  1611.   finish_C(1);
  1612. }
  1613. @ The title of the section and an $E$ or $mathrel+E$ are made
  1614. into a scrap that should not take part in the parsing.
  1615. @<Check that '='...@>=
  1616. do next_control=get_next();
  1617.   while (next_control=='+'); /* allow optional `.{+=}' */
  1618. if (next_control!='=' && next_control!=eq_eq)
  1619.   err_print("! You need an = sign after the section name");
  1620. @.You need an = sign...@>
  1621.   else next_control=get_next();
  1622. if (out_ptr>out_buf+1 && *out_ptr=='Y' && *(out_ptr-1)=='\') app(backup);
  1623.     /* the section name will be flush left */
  1624. @.\Y@>
  1625. app(section_flag+(int)(this_section-name_dir));
  1626. cur_xref=(xref_pointer)this_section->xref;
  1627. if(cur_xref->num==file_flag) cur_xref=cur_xref->xlink;
  1628. app_str("${}");
  1629. if (cur_xref->num!=section_count+def_flag) {
  1630.   app_str("\mathrel+"); /*section name is multiply defined*/
  1631.   this_section=name_dir; /*so we won't give cross-reference info here*/
  1632. }
  1633. app_str("\E"); /* output an equivalence sign */
  1634. @.\E@>
  1635. app_str("{}$");
  1636. app(force); app_scrap(dead,no_math);
  1637.         /* this forces a line break unless `.{@@+}' follows */
  1638. @ @<Emit the scrap...@>=
  1639. if (next_control<section_name) {
  1640.   err_print("! You can't do that in C text");
  1641. @.You can't do that...@>
  1642.   next_control=get_next();
  1643. }
  1644. else if (next_control==section_name) {
  1645.   app(section_flag+(int)(cur_section-name_dir));
  1646.   app_scrap(section_scrap,maybe_math);
  1647.   next_control=get_next();
  1648. }
  1649. @ Cross references relating to a named section are given
  1650. after the section ends.
  1651. @<Show cross...@>=
  1652. if (this_section>name_dir) {
  1653.   cur_xref=(xref_pointer)this_section->xref;
  1654.   if (cur_xref->num==file_flag){an_output=1;cur_xref=cur_xref->xlink;}
  1655.   else an_output=0;
  1656.   if (cur_xref->num>def_flag)
  1657.     cur_xref=cur_xref->xlink; /* bypass current section number */
  1658.   footnote(def_flag); footnote(cite_flag); footnote(0);
  1659. }
  1660. @ The |footnote| procedure gives cross-reference information about
  1661. multiply defined section names (if the |flag| parameter is
  1662. |def_flag|), or about references to a section name
  1663. (if |flag==cite_flag|), or to its uses (if |flag==0|). It assumes that
  1664. |cur_xref| points to the first cross-reference entry of interest, and it
  1665. leaves |cur_xref| pointing to the first element not printed.  Typical outputs:
  1666. `.{\A101.}'; `.{\Us 370\ET1009.}';
  1667. `.{\As 8, 27\*\ETs64.}'.
  1668. Note that the output of .{CWEAVE} is not English-specific; users may
  1669. supply new definitions for the macros .{\A}, .{\As}, etc.
  1670. @<Predecl...@>=
  1671. void footnote();
  1672. @ @c
  1673. void
  1674. footnote(flag) /* outputs section cross-references */
  1675. sixteen_bits flag;
  1676. {
  1677.   xref_pointer q; /* cross-reference pointer variable */
  1678.   if (cur_xref->num<=flag) return;
  1679.   finish_line(); out('\');
  1680. @.\A@>
  1681. @.\Q@>
  1682. @.\U@>
  1683.   out(flag==0? 'U': flag==cite_flag? 'Q': 'A');
  1684.   @<Output all the section numbers on the reference list |cur_xref|@>;
  1685.   out('.');
  1686. }
  1687. @ The following code distinguishes three cases, according as the number
  1688. of cross-references is one, two, or more than two. Variable |q| points
  1689. to the first cross-reference, and the last link is a zero.
  1690. @<Output all the section numbers...@>=
  1691. q=cur_xref; if (q->xlink->num>flag) out('s'); /* plural */
  1692. while (1) {
  1693.   out_section(cur_xref->num-flag);
  1694.   cur_xref=cur_xref->xlink; /* point to the next cross-reference to output */
  1695.   if (cur_xref->num<=flag) break;
  1696.   if (cur_xref->xlink->num>flag) out_str(", "); /* not the last */
  1697.   else {out_str("\ET"); /* the last */
  1698. @.\ET@>
  1699.   if (cur_xref != q->xlink) out('s'); /* the last of more than two */
  1700.   }
  1701. }
  1702. @ @<Output the code for the end of a section@>=
  1703. out_str("\fi"); finish_line();
  1704. @.\fi@>
  1705. flush_buffer(out_buf,0,0); /* insert a blank line, it looks nice */
  1706. @** Phase three processing.
  1707. We are nearly finished! .{CWEAVE}'s only remaining task is to write out the
  1708. index, after sorting the identifiers and index entries.
  1709. If the user has set the |no_xref| flag (the .{-x} option on the command line),
  1710. just finish off the page, omitting the index, section name list, and table of
  1711. contents.
  1712. @<Predecl...@>=
  1713. void phase_three();
  1714. @ @c
  1715. void
  1716. phase_three() {
  1717. if (no_xref) {
  1718.   finish_line();
  1719.   out_str("\end");
  1720. @.\end@>
  1721.   finish_line();
  1722. }
  1723. else {
  1724.   phase=3; if (show_progress) printf("nWriting the index...");
  1725. @.Writing the index...@>
  1726.   finish_line();
  1727.   if ((idx_file=fopen(idx_file_name,"w"))==NULL)
  1728.     fatal("! Cannot open index file ",idx_file_name);
  1729. @.Cannot open index file@>
  1730.   if (change_exists) {
  1731.     @<Tell about changed sections@>; finish_line(); finish_line();
  1732.   }
  1733.   out_str("\inx"); finish_line();
  1734. @.\inx@>
  1735.   active_file=idx_file; /* change active file to the index file */
  1736.   @<Do the first pass of sorting@>;
  1737.   @<Sort and output the index@>;
  1738.   finish_line(); fclose(active_file); /* finished with |idx_file| */
  1739.   active_file=tex_file; /* switch back to |tex_file| for a tic */
  1740.   out_str("\fin"); finish_line();
  1741. @.\fin@>
  1742.   if ((scn_file=fopen(scn_file_name,"w"))==NULL)
  1743.     fatal("! Cannot open section file ",scn_file_name);
  1744. @.Cannot open section file@>
  1745.   active_file=scn_file; /* change active file to section listing file */
  1746.   @<Output all the section names@>;
  1747.   finish_line(); fclose(active_file); /* finished with |scn_file| */
  1748.   active_file=tex_file;
  1749.   if (group_found) out_str("\con");@+else out_str("\end");
  1750. @.\con@>
  1751. @.\end@>
  1752.   finish_line();
  1753.   fclose(active_file);
  1754. }
  1755. if (show_happiness) printf("nDone.");
  1756. check_complete(); /* was all of the change file used? */
  1757. }
  1758. @ Just before the index comes a list of all the changed sections, including
  1759. the index section itself.
  1760. @<Global...@>=
  1761. sixteen_bits k_section; /* runs through the sections */
  1762. @ @<Tell about changed sections@>= {
  1763.   /* remember that the index is already marked as changed */
  1764.   k_section=0;
  1765.   while (!changed_section[++k_section]);
  1766.   out_str("\ch ");
  1767. @.\ch@>
  1768.   out_section(k_section);
  1769.   while (k_section<section_count) {
  1770.     while (!changed_section[++k_section]);
  1771.     out_str(", "); out_section(k_section);
  1772.   }
  1773.   out('.');
  1774. }
  1775. @ A left-to-right radix sorting method is used, since this makes it easy to
  1776. adjust the collating sequence and since the running time will be at worst
  1777. proportional to the total length of all entries in the index. We put the
  1778. identifiers into 102 different lists based on their first characters.
  1779. (Uppercase letters are put into the same list as the corresponding lowercase
  1780. letters, since we want to have `$t<\{TeX}<&{to}$'.) The
  1781. list for character |c| begins at location |bucket[c]| and continues through
  1782. the |blink| array.
  1783. @<Global...@>=
  1784. name_pointer bucket[256];
  1785. name_pointer next_name; /* successor of |cur_name| when sorting */
  1786. name_pointer blink[max_names]; /* links in the buckets */
  1787. @ To begin the sorting, we go through all the hash lists and put each entry
  1788. having a nonempty cross-reference list into the proper bucket.
  1789. @<Do the first pass...@>= {
  1790. int c;
  1791. for (c=0; c<=255; c++) bucket[c]=NULL;
  1792. for (h=hash; h<=hash_end; h++) {
  1793.   next_name=*h;
  1794.   while (next_name) {
  1795.     cur_name=next_name; next_name=cur_name->link;
  1796.     if (cur_name->xref!=(char*)xmem) {
  1797.       c=(eight_bits)((cur_name->byte_start)[0]);
  1798.       if (xisupper(c)) c=tolower(c);
  1799.       blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name;
  1800.     }
  1801.   }
  1802. }
  1803. }
  1804. @ During the sorting phase we shall use the |cat| and |trans| arrays from
  1805. .{CWEAVE}'s parsing algorithm and rename them |depth| and |head|. They now
  1806. represent a stack of identifier lists for all the index entries that have
  1807. not yet been output. The variable |sort_ptr| tells how many such lists are
  1808. present; the lists are output in reverse order (first |sort_ptr|, then
  1809. |sort_ptr-1|, etc.). The |j|th list starts at |head[j]|, and if the first
  1810. |k| characters of all entries on this list are known to be equal we have
  1811. |depth[j]==k|.
  1812. @ @<Rest of |trans_plus| union@>=
  1813. name_pointer Head;
  1814. @ @d depth cat /* reclaims memory that is no longer needed for parsing */
  1815. @d head trans_plus.Head /* ditto */
  1816. @f sort_pointer int
  1817. @d sort_pointer scrap_pointer /* ditto */
  1818. @d sort_ptr scrap_ptr /* ditto */
  1819. @d max_sorts max_scraps /* ditto */
  1820. @<Global...@>=
  1821. eight_bits cur_depth; /* depth of current buckets */
  1822. char *cur_byte; /* index into |byte_mem| */
  1823. sixteen_bits cur_val; /* current cross-reference number */
  1824. sort_pointer max_sort_ptr; /* largest value of |sort_ptr| */
  1825. @ @<Set init...@>=
  1826. max_sort_ptr=scrap_info;
  1827. @ The desired alphabetic order is specified by the |collate| array; namely,
  1828. $|collate|[0]<|collate|[1]<cdots<|collate|[100]$.
  1829. @<Global...@>=
  1830. eight_bits collate[102+128]; /* collation order */
  1831. @^high-bit character handling@>
  1832. @ We use the order $hbox{null}<. <hbox{other characters}<{}$._${}<
  1833. .A=.a<cdots<.Z=.z<.0<cdots<.9.$ Warning: The collation mapping
  1834. needs to be changed if ASCII code is not being used.
  1835. @^ASCII code dependencies@>
  1836. @^high-bit character handling@>
  1837. We initialize |collate| by copying a few characters at a time, because
  1838. some CEE/ compilers choke on long strings.
  1839. @<Set init...@>=
  1840. collate[0]=0;
  1841. strcpy(collate+1," 12345671011121314151617");
  1842. /* 16 characters + 1 = 17 */
  1843. strcpy(collate+17,"20212223242526273031323334353637");
  1844. /* 16 characters + 17 = 33 */
  1845. strcpy(collate+33,"!42#$%&'()*+,-./:;<=>?@@[\]^`{|}~_");
  1846. /* 32 characters + 33 = 65 */
  1847. strcpy(collate+65,"abcdefghijklmnopqrstuvwxyz0123456789");
  1848. /* (26 + 10) characters + 65 = 101 */
  1849. strcpy(collate+101,"200201202203204205206207210211212213214215216217");
  1850. /* 16 characters + 101 = 117 */
  1851. strcpy(collate+117,"220221222223224225226227230231232233234235236237");
  1852. /* 16 characters + 117 = 133 */
  1853. strcpy(collate+133,"240241242243244245246247250251252253254255256257");
  1854. /* 16 characters + 133 = 149 */
  1855. strcpy(collate+149,"260261262263264265266267270271272273274275276277");
  1856. /* 16 characters + 149 = 165 */
  1857. strcpy(collate+165,"300301302303304305306307310311312313314315316317");
  1858. /* 16 characters + 165 = 181 */
  1859. strcpy(collate+181,"320321322323324325326327330331332333334335336337");
  1860. /* 16 characters + 181 = 197 */
  1861. strcpy(collate+197,"340341342343344345346347350351352353354355356357");
  1862. /* 16 characters + 197 = 213 */
  1863. strcpy(collate+213,"360361362363364365366367370371372373374375376377");
  1864. /* 16 characters + 213 = 229 */
  1865. @ Procedure |unbucket| goes through the buckets and adds nonempty lists
  1866. to the stack, using the collating sequence specified in the |collate| array.
  1867. The parameter to |unbucket| tells the current depth in the buckets.
  1868. Any two sequences that agree in their first 255 character positions are
  1869. regarded as identical.
  1870. @d infinity 255 /* $infty$ (approximately) */
  1871. @<Predecl...@>=
  1872. void  unbucket();
  1873. @ @c
  1874. void
  1875. unbucket(d) /* empties buckets having depth |d| */
  1876. eight_bits d;
  1877. {
  1878.   int c;  /* index into |bucket|; cannot be a simple |char| because of sign
  1879.     comparison below*/
  1880.   for (c=100+128; c>= 0; c--) if (bucket[collate[c]]) {
  1881. @^high-bit character handling@>
  1882.     if (sort_ptr>=scrap_info_end) overflow("sorting");
  1883.     sort_ptr++;
  1884.     if (sort_ptr>max_sort_ptr) max_sort_ptr=sort_ptr;
  1885.     if (c==0) sort_ptr->depth=infinity;
  1886.     else sort_ptr->depth=d;
  1887.     sort_ptr->head=bucket[collate[c]]; bucket[collate[c]]=NULL;
  1888.   }
  1889. }
  1890. @ @<Sort and output...@>=
  1891. sort_ptr=scrap_info; unbucket(1);
  1892. while (sort_ptr>scrap_info) {
  1893.   cur_depth=sort_ptr->depth;
  1894.   if (blink[sort_ptr->head-name_dir]==0 || cur_depth==infinity)
  1895.     @<Output index entries for the list at |sort_ptr|@>@;
  1896.   else @<Split the list at |sort_ptr| into further lists@>;
  1897. }
  1898. @ @<Split the list...@>= {
  1899.   eight_bits c;
  1900.   next_name=sort_ptr->head;
  1901.   do {
  1902.     cur_name=next_name; next_name=blink[cur_name-name_dir];
  1903.     cur_byte=cur_name->byte_start+cur_depth;
  1904.     if (cur_byte==(cur_name+1)->byte_start) c=0; /* hit end of the name */
  1905.     else {
  1906.       c=(eight_bits) *cur_byte;
  1907.       if (xisupper(c)) c=tolower(c);
  1908.     }
  1909.   blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name;
  1910.   } while (next_name);
  1911.   --sort_ptr; unbucket(cur_depth+1);
  1912. }
  1913. @ @<Output index...@>= {
  1914.   cur_name=sort_ptr->head;
  1915.   do {
  1916.     out_str("\I");
  1917. @.\I@>
  1918.     @<Output the name at |cur_name|@>;
  1919.     @<Output the cross-references at |cur_name|@>;
  1920.     cur_name=blink[cur_name-name_dir];
  1921.   } while (cur_name);
  1922.   --sort_ptr;
  1923. }
  1924. @ @<Output the name...@>=
  1925. switch (cur_name->ilk) {
  1926.   case normal: if (is_tiny(cur_name)) out_str("\|");
  1927.     else {char *j;
  1928.       for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
  1929.         if (xislower(*j)) goto lowcase;
  1930.       out_str("\."); break;
  1931. lowcase: out_str("\\");
  1932.     }
  1933.   break;
  1934. @.\|@>
  1935. @.\.@>
  1936. @.\\@>
  1937.   case roman: break;
  1938.   case wildcard: out_str("\9"); break;
  1939. @.\9@>
  1940.   case typewriter: out_str("\."); break;
  1941. @.\.@>
  1942.   case custom: case quoted: {char *j; out_str("$\");
  1943.     for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
  1944.       out(isxalpha(*j)? 'x' : *j);
  1945.     out('$');
  1946.     goto name_done;
  1947.     }
  1948.   default: out_str("\&");
  1949. @.\&@>
  1950. }
  1951. out_name(cur_name);
  1952. name_done:
  1953. @ Section numbers that are to be underlined are enclosed in
  1954. `.{\[}$,ldots,$.]'.
  1955. @<Output the cross-references...@>=
  1956. @<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>;
  1957. do {
  1958.   out_str(", "); cur_val=cur_xref->num;
  1959.   if (cur_val<def_flag) out_section(cur_val);
  1960.   else {out_str("\["); out_section(cur_val-def_flag); out(']');}
  1961. @.\[@>
  1962.   cur_xref=cur_xref->xlink;
  1963. } while (cur_xref!=xmem);
  1964. out('.'); finish_line();
  1965. @ List inversion is best thought of as popping elements off one stack and
  1966. pushing them onto another. In this case |cur_xref| will be the head of
  1967. the stack that we push things onto.
  1968. @<Global...@>=
  1969. xref_pointer next_xref, this_xref;
  1970.   /* pointer variables for rearranging a list */
  1971. @ @<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>=
  1972. this_xref=(xref_pointer)cur_name->xref; cur_xref=xmem;
  1973. do {
  1974.   next_xref=this_xref->xlink; this_xref->xlink=cur_xref;
  1975.   cur_xref=this_xref; this_xref=next_xref;
  1976. } while (this_xref!=xmem);
  1977. @ The following recursive procedure walks through the tree of section names and
  1978. prints them.
  1979. @^recursion@>
  1980. @<Predecl...@>=
  1981. void section_print();
  1982. @ @c
  1983. void
  1984. section_print(p) /* print all section names in subtree |p| */
  1985. name_pointer p;
  1986. {
  1987.   if (p) {
  1988.     section_print(p->llink); out_str("\I");
  1989. @.\I@>
  1990.     tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info; init_stack;
  1991.     app(p-name_dir+section_flag); make_output();
  1992.     footnote(cite_flag);
  1993.     footnote(0); /* |cur_xref| was set by |make_output| */
  1994.     finish_line();@/
  1995.     section_print(p->rlink);
  1996.   }
  1997. }
  1998. @ @<Output all the section names@>=section_print(root)
  1999. @ Because on some systems the difference between two pointers is a |long|
  2000. rather than an |int|, we use .{%ld} to print these quantities.
  2001. @c
  2002. void
  2003. print_stats() {
  2004.   printf("nMemory usage statistics:n");
  2005. @.Memory usage statistics:@>
  2006.   printf("%ld names (out of %ld)n",
  2007.             (long)(name_ptr-name_dir),(long)max_names);
  2008.   printf("%ld cross-references (out of %ld)n",
  2009.             (long)(xref_ptr-xmem),(long)max_refs);
  2010.   printf("%ld bytes (out of %ld)n",
  2011.             (long)(byte_ptr-byte_mem),(long)max_bytes);
  2012.   printf("Parsing:n");
  2013.   printf("%ld scraps (out of %ld)n",
  2014.             (long)(max_scr_ptr-scrap_info),(long)max_scraps);
  2015.   printf("%ld texts (out of %ld)n",
  2016.             (long)(max_text_ptr-tok_start),(long)max_texts);
  2017.   printf("%ld tokens (out of %ld)n",
  2018.             (long)(max_tok_ptr-tok_mem),(long)max_toks);
  2019.   printf("%ld levels (out of %ld)n",
  2020.             (long)(max_stack_ptr-stack),(long)stack_size);
  2021.   printf("Sorting:n");
  2022.   printf("%ld levels (out of %ld)n",
  2023.             (long)(max_sort_ptr-scrap_info),(long)max_scraps);
  2024. }
  2025. @** Index.
  2026. If you have read and understood the code for Phase III above, you know what
  2027. is in this index and how it got here. All sections in which an identifier is
  2028. used are listed with that identifier, except that reserved words are
  2029. indexed only when they appear in format definitions, and the appearances
  2030. of identifiers in section names are not indexed. Underlined entries
  2031. correspond to where the identifier was declared. Error messages, control
  2032. sequences put into the output, and a few
  2033. other things like ``recursion'' are indexed here too.