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

通讯编程

开发平台:

Visual C++

  1. % This file is part of CWEB.
  2. % This program by Silvio Levy and Donald E. Knuth
  3. % is based on a program by Knuth.
  4. % It is distributed WITHOUT ANY WARRANTY, express or implied.
  5. % Version 3.4 --- April 1995
  6. % Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth
  7. % Permission is granted to make and distribute verbatim copies of this
  8. % document provided that the copyright notice and this permission notice
  9. % are preserved on all copies.
  10. % Permission is granted to copy and distribute modified versions of this
  11. % document under the conditions for verbatim copying, provided that the
  12. % entire resulting derived work is given a different name and distributed
  13. % under the terms of a permission notice identical to this one.
  14. % Here is TeX material that gets inserted after input cwebmac
  15. defhang{hangindent 3emindentignorespaces}
  16. defpb{$.|ldots.|$} % C brackets (|...|)
  17. defv{char'174} % vertical (|) in typewriter font
  18. defdleft{[![} defdright{]!]} % double brackets
  19. mathchardefRA="3221 % right arrow
  20. mathchardefBA="3224 % double arrow
  21. def({} % ) kludge for alphabetizing certain section names
  22. defTeXxstring{\{TEX/_string}}
  23. defskipxTeX{\{skip_TEX/}}
  24. defcopyxTeX{\{copy_TEX/}}
  25. deftitle{CWEAVE (Version 3.4)}
  26. deftopofcontents{nullvfill
  27.   centerline{titlefont The {ttitlefont CWEAVE} processor}
  28.   vskip 15pt
  29.   centerline{(Version 3.4)}
  30.   vfill}
  31. defbotofcontents{vfill
  32. noindent
  33. Copyright copyright 1987, 1990, 1993 Silvio Levy and Donald E. Knuth
  34. bigskipnoindent
  35. Permission is granted to make and distribute verbatim copies of this
  36. document provided that the copyright notice and this permission notice
  37. are preserved on all copies.
  38. smallskipnoindent
  39. Permission is granted to copy and distribute modified versions of this
  40. document under the conditions for verbatim copying, provided that the
  41. entire resulting derived work is given a different name and distributed
  42. under the terms of a permission notice identical to this one.
  43. }
  44. pageno=contentspagenumber advancepageno by 1
  45. letmaybe=iftrue
  46. @** Introduction.
  47. This is the .{CWEAVE} program by Silvio Levy and Donald E. Knuth,
  48. based on .{WEAVE} by Knuth.
  49. We are thankful to Steve Avery,
  50. Nelson Beebe, Hans-Hermann Bode (to whom the CPLUSPLUS/ adaptation is due),
  51. Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter,
  52. Joachim Schrod, Lee Wittenberg, and others who have contributed improvements.
  53. The ``banner line'' defined here should be changed whenever .{CWEAVE}
  54. is modified.
  55. @d banner "This is CWEAVE (Version 3.4)n"
  56. @c @<Include files@>@/
  57. @h
  58. @<Common code for .{CWEAVE} and .{CTANGLE}@>@/
  59. @<Typedef declarations@>@/
  60. @<Global variables@>@/
  61. @<Predeclaration of procedures@>
  62. @ We predeclare several standard system functions here instead of including
  63. their system header files, because the names of the header files are not as
  64. standard as the names of the functions. (For example, some CEE/ environments
  65. have .{<string.h>} where others have .{<strings.h>}.)
  66. @<Predecl...@>=
  67. extern int strlen(); /* length of string */
  68. extern int strcmp(); /* compare strings lexicographically */
  69. extern char* strcpy(); /* copy one string to another */
  70. extern int strncmp(); /* compare up to $n$ string characters */
  71. extern char* strncpy(); /* copy up to $n$ string characters */
  72. @ .{CWEAVE} has a fairly straightforward outline.  It operates in
  73. three phases: First it inputs the source file and stores cross-reference
  74. data, then it inputs the source once again and produces the TEX/ output
  75. file, finally it sorts and outputs the index.
  76. Please read the documentation for .{common}, the set of routines common
  77. to .{CTANGLE} and .{CWEAVE}, before proceeding further.
  78. @c
  79. int main (ac, av)
  80. int ac; /* argument count */
  81. char **av; /* argument values */
  82. {
  83.   argc=ac; argv=av;
  84.   program=cweave;
  85.   make_xrefs=force_lines=1; /* controlled by command-line options */
  86.   common_init();
  87.   @<Set initial values@>;
  88.   if (show_banner) printf(banner); /* print a ``banner line'' */
  89.   @<Store all the reserved words@>;
  90.   phase_one(); /* read all the user's text and store the cross-references */
  91.   phase_two(); /* read all the text again and translate it to TEX/ form */
  92.   phase_three(); /* output the cross-reference index */
  93.   return wrap_up(); /* and exit gracefully */
  94. }
  95. @ The following parameters were sufficient in the original .{WEAVE} to
  96. handle TEX/, so they should be sufficient for most applications of .{CWEAVE}.
  97. If you change |max_bytes|, |max_names|, |hash_size| or |buf_size|
  98. you have to change them also in the file |"common.w"|.
  99. @d max_bytes 90000 /* the number of bytes in identifiers,
  100.   index entries, and section names */
  101. @d max_names 4000 /* number of identifiers, strings, section names;
  102.   must be less than 10240; used in |"common.w"| */
  103. @d max_sections 2000 /* greater than the total number of sections */
  104. @d hash_size 353 /* should be prime */
  105. @d buf_size 100 /* maximum length of input line, plus one */
  106. @d longest_name 1000 /* section names and strings shouldn't be longer than this */
  107. @d long_buf_size (buf_size+longest_name)
  108. @d line_length 80 /* lines of TEX/ output have at most this many characters;
  109.   should be less than 256 */
  110. @d max_refs 20000 /* number of cross-references; must be less than 65536 */
  111. @d max_toks 20000 /* number of symbols in CEE/ texts being parsed;
  112.   must be less than 65536 */
  113. @d max_texts 4000 /* number of phrases in CEE/ texts being parsed;
  114.   must be less than 10240 */
  115. @d max_scraps 2000 /* number of tokens in CEE/ texts being parsed */
  116. @d stack_size 400 /* number of simultaneous output levels */
  117. @ The next few sections contain stuff from the file |"common.w"| that must
  118. be included in both |"ctangle.w"| and |"cweave.w"|. It appears in
  119. file |"common.h"|, which needs to be updated when |"common.w"| changes.
  120. @i common.h
  121. @* Data structures exclusive to {tt CWEAVE}.
  122. As explained in .{common.w}, the field of a |name_info| structure
  123. that contains the |rlink| of a section name is used for a completely
  124. different purpose in the case of identifiers.  It is then called the
  125. |ilk| of the identifier, and it is used to
  126. distinguish between various types of identifiers, as follows:
  127. yskiphang |normal| identifiers are part of the CEE/ program and
  128. will appear in italic type.
  129. yskiphang |roman| identifiers are index entries that appear after
  130. .{@@^} in the .{CWEB} file.
  131. yskiphang |wildcard| identifiers are index entries that appear after
  132. .{@@:} in the .{CWEB} file.
  133. yskiphang |typewriter| identifiers are index entries that appear after
  134. .{@@.} in the .{CWEB} file.
  135. yskiphang |else_like|, dots, |typedef_like|
  136. identifiers are CEE/ reserved words whose |ilk| explains how they are
  137. to be treated when CEE/ code is being formatted.
  138. @d ilk dummy.Ilk
  139. @d normal 0 /* ordinary identifiers have |normal| ilk */
  140. @d roman 1 /* normal index entries have |roman| ilk */
  141. @d wildcard 2 /* user-formatted index entries have |wildcard| ilk */
  142. @d typewriter 3 /* `typewriter type' entries have |typewriter| ilk */
  143. @d abnormal(a) (a->ilk>typewriter) /* tells if a name is special */
  144. @d custom 4 /* identifiers with user-given control sequence */
  145. @d unindexed(a) (a->ilk>custom) /* tells if uses of a name are to be indexed */
  146. @d quoted 5 /* .{NULL} */
  147. @d else_like 26 /* &{else} */
  148. @d public_like 40 /* &{public}, &{private}, &{protected} */
  149. @d operator_like 41 /* &{operator} */
  150. @d new_like 42 /* &{new} */
  151. @d catch_like 43 /* &{catch} */
  152. @d for_like 45 /* .{for}, &{switch}, &{while} */
  153. @d do_like 46 /* &{do} */
  154. @d if_like 47 /* &{if}, &{ifdef}, &{endif}, &{pragma}, dots */
  155. @d raw_rpar 48 /* `.)' or `.]' when looking for &{const} following */
  156. @d raw_unorbin 49 /* `.&' or `.*' when looking for &{const} following */
  157. @d const_like 50 /* &{const}, &{volatile} */
  158. @d raw_int 51 /* &{int}, &{char}, &{extern}, dots  */
  159. @d int_like 52 /* same, when not followed by left parenthesis */
  160. @d case_like 53 /* &{case}, &{return}, &{goto}, &{break}, &{continue} */
  161. @d sizeof_like 54 /* &{sizeof} */
  162. @d struct_like 55 /* &{struct}, &{union}, &{enum}, &{class} */
  163. @d typedef_like 56 /* &{typedef} */
  164. @d define_like 57 /* &{define} */
  165. @ We keep track of the current section number in |section_count|, which
  166. is the total number of sections that have started.  Sections which have
  167. been altered by a change file entry have their |changed_section| flag
  168. turned on during the first phase.
  169. @<Global...@>=
  170. boolean change_exists; /* has any section changed? */
  171. @ The other large memory area in .{CWEAVE} keeps the cross-reference data.
  172. All uses of the name |p| are recorded in a linked list beginning at
  173. |p->xref|, which points into the |xmem| array. The elements of |xmem|
  174. are structures consisting of an integer, |num|, and a pointer |xlink|
  175. to another element of |xmem|.  If |x=p->xref| is a pointer into |xmem|,
  176. the value of |x->num| is either a section number where |p| is used,
  177. or |cite_flag| plus a section number where |p| is mentioned,
  178. or |def_flag| plus a section number where |p| is defined;
  179. and |x->xlink| points to the next such cross-reference for |p|,
  180. if any. This list of cross-references is in decreasing order by
  181. section number. The next unused slot in |xmem| is |xref_ptr|.
  182. The linked list ends at |&xmem[0]|.
  183. The global variable |xref_switch| is set either to |def_flag| or to zero,
  184. depending on whether the next cross-reference to an identifier is to be
  185. underlined or not in the index. This switch is set to |def_flag| when
  186. .{@@!} or .{@@d} is scanned, and it is cleared to zero when
  187. the next identifier or index entry cross-reference has been made.
  188. Similarly, the global variable |section_xref_switch| is either
  189. |def_flag| or |cite_flag| or zero, depending
  190. on whether a section name is being defined, cited or used in CEE/ text.
  191. @<Type...@>=
  192. typedef struct xref_info {
  193.   sixteen_bits num; /* section number plus zero or |def_flag| */
  194.   struct xref_info *xlink; /* pointer to the previous cross-reference */
  195. } xref_info;
  196. typedef xref_info *xref_pointer;
  197. @ @<Global...@>=
  198. xref_info xmem[max_refs]; /* contains cross-reference information */
  199. xref_pointer xmem_end = xmem+max_refs-1;
  200. xref_pointer xref_ptr; /* the largest occupied position in |xmem| */
  201. sixteen_bits xref_switch,section_xref_switch; /* either zero or |def_flag| */
  202. @ A section that is used for multi-file output (with the .{@@(} feature)
  203. has a special first cross-reference whose |num| field is |file_flag|.
  204. @d file_flag (3*cite_flag)
  205. @d def_flag (2*cite_flag)
  206. @d cite_flag 10240 /* must be strictly larger than |max_sections| */
  207. @d xref equiv_or_xref
  208. @<Set init...@>=
  209. xref_ptr=xmem; name_dir->xref=(char*)xmem; xref_switch=0; section_xref_switch=0;
  210. xmem->num=0; /* sentinel value */
  211. @ A new cross-reference for an identifier is formed by calling |new_xref|,
  212. which discards duplicate entries and ignores non-underlined references
  213. to one-letter identifiers or CEE/'s reserved words.
  214. If the user has sent the |no_xref| flag (the .{-x} option of the command line),
  215. it is unnecessary to keep track of cross-references for identifiers.
  216. If one were careful, one could probably make more changes around section
  217. 100 to avoid a lot of identifier looking up.
  218. @d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference");
  219.   else (++xref_ptr)->num=c;
  220. @d no_xref (flags['x']==0)
  221. @d make_xrefs flags['x'] /* should cross references be output? */
  222. @d is_tiny(p) ((p+1)->byte_start==(p)->byte_start+1)
  223. @c
  224. void
  225. new_xref(p)
  226. name_pointer p;
  227. {
  228.   xref_pointer q; /* pointer to previous cross-reference */
  229.   sixteen_bits m, n; /* new and previous cross-reference value */
  230.   if (no_xref) return;
  231.   if ((unindexed(p) || is_tiny(p)) && xref_switch==0) return;
  232.   m=section_count+xref_switch; xref_switch=0; q=(xref_pointer)p->xref;
  233.   if (q != xmem) {
  234.     n=q->num;
  235.     if (n==m || n==m+def_flag) return;
  236.     else if (m==n+def_flag) {
  237.         q->num=m; return;
  238.     }
  239.   }
  240.   append_xref(m); xref_ptr->xlink=q; p->xref=(char*)xref_ptr;
  241. }
  242. @ The cross-reference lists for section names are slightly different.
  243. Suppose that a section name is defined in sections $m_1$, dots,
  244. $m_k$, cited in sections $n_1$, dots, $n_l$, and used in sections
  245. $p_1$, dots, $p_j$.  Then its list will contain $m_1+|def_flag|$,
  246. dots, $m_k+|def_flag|$, $n_1+|cite_flag|$, dots,
  247. $n_l+|cite_flag|$, $p_1$, dots, $p_j$, in this order.
  248. Although this method of storage take quadratic time on the length of
  249. the list, under foreseeable uses of .{CWEAVE} this inefficiency is
  250. insignificant.
  251. @c
  252. void
  253. new_section_xref(p)
  254. name_pointer p;
  255. {
  256.   xref_pointer q,r; /* pointers to previous cross-references */
  257.   q=(xref_pointer)p->xref; r=xmem;
  258.   if (q>xmem)
  259.         while (q->num>section_xref_switch) {r=q; q=q->xlink;}
  260.   if (r->num==section_count+section_xref_switch)
  261.         return; /* don't duplicate entries */
  262.   append_xref(section_count+section_xref_switch);
  263.   xref_ptr->xlink=q; section_xref_switch=0;
  264.   if (r==xmem) p->xref=(char*)xref_ptr;
  265.   else r->xlink=xref_ptr;
  266. }
  267. @ The cross-reference list for a section name may also begin with
  268. |file_flag|. Here's how that flag gets put~in.
  269. @c
  270. void
  271. set_file_flag(p)
  272. name_pointer p;
  273. {
  274.   xref_pointer q;
  275.   q=(xref_pointer)p->xref;
  276.   if (q->num==file_flag) return;
  277.   append_xref(file_flag);
  278.   xref_ptr->xlink = q;
  279.   p->xref = (char *)xref_ptr;
  280. }
  281. @ A third large area of memory is used for sixteen-bit `tokens', which appear
  282. in short lists similar to the strings of characters in |byte_mem|. Token lists
  283. are used to contain the result of CEE/ code translated into TEX/ form;
  284. further details about them will be explained later. A |text_pointer| variable
  285. is an index into |tok_start|.
  286. @<Typed...@>=
  287. typedef sixteen_bits token;
  288. typedef token *token_pointer;
  289. typedef token_pointer *text_pointer;
  290. @ The first position of |tok_mem|
  291. that is unoccupied by replacement text is called |tok_ptr|, and the first
  292. unused location of |tok_start| is called |text_ptr|.
  293. Thus, we usually have |*text_ptr==tok_ptr|.
  294. @<Global...@>=
  295. token tok_mem[max_toks]; /* tokens */
  296. token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */
  297. token_pointer tok_start[max_texts]; /* directory into |tok_mem| */
  298. token_pointer tok_ptr; /* first unused position in |tok_mem| */
  299. text_pointer text_ptr; /* first unused position in |tok_start| */
  300. text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */
  301. token_pointer max_tok_ptr; /* largest value of |tok_ptr| */
  302. text_pointer max_text_ptr; /* largest value of |text_ptr| */
  303. @ @<Set init...@>=
  304. tok_ptr=tok_mem+1; text_ptr=tok_start+1; tok_start[0]=tok_mem+1;
  305. tok_start[1]=tok_mem+1;
  306. max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1;
  307. @ Here are the three procedures needed to complete |id_lookup|:
  308. @c
  309. int names_match(p,first,l,t)
  310. name_pointer p; /* points to the proposed match */
  311. char *first; /* position of first character of string */
  312. int l; /* length of identifier */
  313. eight_bits t; /* desired ilk */
  314. {
  315.   if (length(p)!=l) return 0;
  316.   if (p->ilk!=t && !(t==normal && abnormal(p))) return 0;
  317.   return !strncmp(first,p->byte_start,l);
  318. }
  319. void
  320. init_p(p,t)
  321. name_pointer p;
  322. eight_bits t;
  323. {
  324.   p->ilk=t; p->xref=(char*)xmem;
  325. }
  326. void
  327. init_node(p)
  328. name_pointer p;
  329. {
  330.   p->xref=(char*)xmem;
  331. }
  332. @ We have to get CEE/'s
  333. reserved words into the hash table, and the simplest way to do this is
  334. to insert them every time .{CWEAVE} is run.  Fortunately there are relatively
  335. few reserved words. (Some of these are not strictly ``reserved,'' but
  336. are defined in header files of the ISO Standard CEE/ Library.)
  337. @^reserved words@>
  338. @<Store all the reserved words@>=
  339. id_lookup("asm",NULL,sizeof_like);
  340. id_lookup("auto",NULL,int_like);
  341. id_lookup("break",NULL,case_like);
  342. id_lookup("case",NULL,case_like);
  343. id_lookup("catch",NULL,catch_like);
  344. id_lookup("char",NULL,raw_int);
  345. id_lookup("class",NULL,struct_like);
  346. id_lookup("clock_t",NULL,raw_int);
  347. id_lookup("const",NULL,const_like);
  348. id_lookup("continue",NULL,case_like);
  349. id_lookup("default",NULL,case_like);
  350. id_lookup("define",NULL,define_like);
  351. id_lookup("defined",NULL,sizeof_like);
  352. id_lookup("delete",NULL,sizeof_like);
  353. id_lookup("div_t",NULL,raw_int);
  354. id_lookup("do",NULL,do_like);
  355. id_lookup("double",NULL,raw_int);
  356. id_lookup("elif",NULL,if_like);
  357. id_lookup("else",NULL,else_like);
  358. id_lookup("endif",NULL,if_like);
  359. id_lookup("enum",NULL,struct_like);
  360. id_lookup("error",NULL,if_like);
  361. id_lookup("extern",NULL,int_like);
  362. id_lookup("FILE",NULL,raw_int);
  363. id_lookup("float",NULL,raw_int);
  364. id_lookup("for",NULL,for_like);
  365. id_lookup("fpos_t",NULL,raw_int);
  366. id_lookup("friend",NULL,int_like);
  367. id_lookup("goto",NULL,case_like);
  368. id_lookup("if",NULL,if_like);
  369. id_lookup("ifdef",NULL,if_like);
  370. id_lookup("ifndef",NULL,if_like);
  371. id_lookup("include",NULL,if_like);
  372. id_lookup("inline",NULL,int_like);
  373. id_lookup("int",NULL,raw_int);
  374. id_lookup("jmp_buf",NULL,raw_int);
  375. id_lookup("ldiv_t",NULL,raw_int);
  376. id_lookup("line",NULL,if_like);
  377. id_lookup("long",NULL,raw_int);
  378. id_lookup("new",NULL,new_like);
  379. id_lookup("NULL",NULL,quoted);
  380. id_lookup("offsetof",NULL,sizeof_like);
  381. id_lookup("operator",NULL,operator_like);
  382. id_lookup("pragma",NULL,if_like);
  383. id_lookup("private",NULL,public_like);
  384. id_lookup("protected",NULL,public_like);
  385. id_lookup("ptrdiff_t",NULL,raw_int);
  386. id_lookup("public",NULL,public_like);
  387. id_lookup("register",NULL,int_like);
  388. id_lookup("return",NULL,case_like);
  389. id_lookup("short",NULL,raw_int);
  390. id_lookup("sig_atomic_t",NULL,raw_int);
  391. id_lookup("signed",NULL,raw_int);
  392. id_lookup("size_t",NULL,raw_int);
  393. id_lookup("sizeof",NULL,sizeof_like);
  394. id_lookup("static",NULL,int_like);
  395. id_lookup("struct",NULL,struct_like);
  396. id_lookup("switch",NULL,for_like);
  397. id_lookup("template",NULL,int_like);
  398. id_lookup("TeX",NULL,custom);
  399. id_lookup("this",NULL,quoted);
  400. id_lookup("throw",NULL,case_like);
  401. id_lookup("time_t",NULL,raw_int);
  402. id_lookup("try",NULL,else_like);
  403. id_lookup("typedef",NULL,typedef_like);
  404. id_lookup("undef",NULL,if_like);
  405. id_lookup("union",NULL,struct_like);
  406. id_lookup("unsigned",NULL,raw_int);
  407. id_lookup("va_dcl",NULL,decl); /* Berkeley's variable-arg-list convention */
  408. id_lookup("va_list",NULL,raw_int); /* ditto */
  409. id_lookup("virtual",NULL,int_like);
  410. id_lookup("void",NULL,raw_int);
  411. id_lookup("volatile",NULL,const_like);
  412. id_lookup("wchar_t",NULL,raw_int);
  413. id_lookup("while",NULL,for_like);
  414. @* Lexical scanning.
  415. Let us now consider the subroutines that read the .{CWEB} source file
  416. and break it into meaningful units. There are four such procedures:
  417. One simply skips to the next `.{@@ }' or `.{@@*}' that begins a
  418. section; another passes over the TEX/ text at the beginning of a
  419. section; the third passes over the TEX/ text in a CEE/ comment;
  420. and the last, which is the most interesting, gets the next token of
  421. a CEE/ text.  They all use the pointers |limit| and |loc| into
  422. the line of input currently being studied.
  423. @ Control codes in .{CWEB}, which begin with `.{@@}', are converted
  424. into a numeric code designed to simplify .{CWEAVE}'s logic; for example,
  425. larger numbers are given to the control codes that denote more significant
  426. milestones, and the code of |new_section| should be the largest of
  427. all. Some of these numeric control codes take the place of |char|
  428. control codes that will not otherwise appear in the output of the
  429. scanning routines.
  430. @^ASCII code dependencies@>
  431. @d ignore 00 /* control code of no interest to .{CWEAVE} */
  432. @d verbatim 02 /* takes the place of extended ASCII .{char2} */
  433. @d begin_short_comment 03 /* CPLUSPLUS/ short comment */
  434. @d begin_comment 't' /* tab marks will not appear */
  435. @d underline 'n' /* this code will be intercepted without confusion */
  436. @d noop 0177 /* takes the place of ASCII delete */
  437. @d xref_roman 0203 /* control code for `.{@@^}' */
  438. @d xref_wildcard 0204 /* control code for `.{@@:}' */
  439. @d xref_typewriter 0205 /* control code for `.{@@.}' */
  440. @d TeX_string 0206 /* control code for `.{@@t}' */
  441. @f TeX_string TeX
  442. @d ord 0207 /* control code for `.{@@'}' */
  443. @d join 0210 /* control code for `.{@@&}' */
  444. @d thin_space 0211 /* control code for `.{@@,}' */
  445. @d math_break 0212 /* control code for `.{@@v}' */
  446. @d line_break 0213 /* control code for `.{@@/}' */
  447. @d big_line_break 0214 /* control code for `.{@@#}' */
  448. @d no_line_break 0215 /* control code for `.{@@+}' */
  449. @d pseudo_semi 0216 /* control code for `.{@@;}' */
  450. @d macro_arg_open 0220 /* control code for `.{@@[}' */
  451. @d macro_arg_close 0221 /* control code for `.{@@]}' */
  452. @d trace 0222 /* control code for `.{@@0}', `.{@@1}' and `.{@@2}' */
  453. @d translit_code 0223 /* control code for `.{@@l}' */
  454. @d output_defs_code 0224 /* control code for `.{@@h}' */
  455. @d format_code 0225 /* control code for `.{@@f}' and `.{@@s}' */
  456. @d definition 0226 /* control code for `.{@@d}' */
  457. @d begin_C 0227 /* control code for `.{@@c}' */
  458. @d section_name 0230 /* control code for `.{@@<}' */
  459. @d new_section 0231 /* control code for `.{@@ }' and `.{@@*}' */
  460. @ Control codes are converted to .{CWEAVE}'s internal
  461. representation by means of the table |ccode|.
  462. @<Global...@>=
  463. eight_bits ccode[256]; /* meaning of a char following .{@@} */
  464. @ @<Set ini...@>=
  465. {int c; for (c=0; c<256; c++) ccode[c]=0;}
  466. ccode[' ']=ccode['t']=ccode['n']=ccode['v']=ccode['r']=ccode['f']
  467.    =ccode['*']=new_section;
  468. ccode['@@']='@@'; /* `quoted' at sign */
  469. ccode['=']=verbatim;
  470. ccode['d']=ccode['D']=definition;
  471. ccode['f']=ccode['F']=ccode['s']=ccode['S']=format_code;
  472. ccode['c']=ccode['C']=ccode['p']=ccode['P']=begin_C;
  473. ccode['t']=ccode['T']=TeX_string;
  474. ccode['l']=ccode['L']=translit_code;
  475. ccode['q']=ccode['Q']=noop;
  476. ccode['h']=ccode['H']=output_defs_code;
  477. ccode['&']=join; ccode['<']=ccode['(']=section_name;
  478. ccode['!']=underline; ccode['^']=xref_roman;
  479. ccode[':']=xref_wildcard; ccode['.']=xref_typewriter; ccode[',']=thin_space;
  480. ccode['|']=math_break; ccode['/']=line_break; ccode['#']=big_line_break;
  481. ccode['+']=no_line_break; ccode[';']=pseudo_semi;
  482. ccode['[']=macro_arg_open; ccode[']']=macro_arg_close;
  483. ccode[''']=ord;
  484. @<Special control codes for debugging@>@;
  485. @ Users can write
  486. .{@@2}, .{@@1}, and .{@@0} to turn tracing fully on, partly on,
  487. and off, respectively.
  488. @<Special control codes...@>=
  489. ccode['0']=ccode['1']=ccode['2']=trace;
  490. @ The |skip_limbo| routine is used on the first pass to skip through
  491. portions of the input that are not in any sections, i.e., that precede
  492. the first section. After this procedure has been called, the value of
  493. |input_has_ended| will tell whether or not a section has actually been found.
  494. There's a complication that we will postpone until later: If the .{@@s}
  495. operation appears in limbo, we want to use it to adjust the default
  496. interpretation of identifiers.
  497. @<Predec...@>=
  498. void   skip_limbo();
  499. @ @c
  500. void
  501. skip_limbo() {
  502.   while(1) {
  503.     if (loc>limit && get_line()==0) return;
  504.     *(limit+1)='@@';
  505.     while (*loc!='@@') loc++; /* look for '@@', then skip two chars */
  506.     if (loc++ <=limit) { int c=ccode[(eight_bits)*loc++];
  507.       if (c==new_section) return;
  508.       if (c==noop) skip_restricted();
  509.       else if (c==format_code) @<Process simple format in limbo@>;
  510.     }
  511.   }
  512. }
  513. @ The |skip_TeX| routine is used on the first pass to skip through
  514. the TEX/ code at the beginning of a section. It returns the next
  515. control code or `.{v}' found in the input. A |new_section| is
  516. assumed to exist at the very end of the file.
  517. @f skip_TeX TeX
  518. @c
  519. unsigned
  520. skip_TeX() /* skip past pure TEX/ code */
  521. {
  522.   while (1) {
  523.     if (loc>limit && get_line()==0) return(new_section);
  524.     *(limit+1)='@@';
  525.     while (*loc!='@@' && *loc!='|') loc++;
  526.     if (*loc++ =='|') return('|');
  527.     if (loc<=limit) return(ccode[(eight_bits)*(loc++)]);
  528.   }
  529. }
  530. @*1 Inputting the next token.
  531. As stated above, .{CWEAVE}'s most interesting lexical scanning routine is the
  532. |get_next| function that inputs the next token of CEE/ input. However,
  533. |get_next| is not especially complicated.
  534. The result of |get_next| is either a |char| code for some special character,
  535. or it is a special code representing a pair of characters (e.g., `.{!=}'),
  536. or it is the numeric value computed by the |ccode|
  537. table, or it is one of the following special codes:
  538. yskiphang |identifier|: In this case the global variables |id_first| and
  539. |id_loc| will have been set to the beginning and ending-plus-one locations
  540. in the buffer, as required by the |id_lookup| routine.
  541. yskiphang |string|: The string will have been copied into the array
  542. |section_text|; |id_first| and |id_loc| are set as above (now they are
  543. pointers into |section_text|).
  544. yskiphang |constant|: The constant is copied into |section_text|, with
  545. slight modifications; |id_first| and |id_loc| are set.
  546. yskipnoindent Furthermore, some of the control codes cause
  547. |get_next| to take additional actions:
  548. yskiphang |xref_roman|, |xref_wildcard|, |xref_typewriter|, |TeX_string|,
  549. |verbatim|: The values of |id_first| and |id_loc| will have been set to
  550. the beginning and ending-plus-one locations in the buffer.
  551. yskiphang |section_name|: In this case the global variable |cur_section| will
  552. point to the |byte_start| entry for the section name that has just been scanned.
  553. The value of |cur_section_char| will be |'('| if the section name was
  554. preceded by .{@@(} instead of .{@@<}.
  555. yskipnoindent If |get_next| sees `.{@@!}'
  556. it sets |xref_switch| to |def_flag| and goes on to the next token.
  557. @d constant 0200 /* CEE/ constant */
  558. @d string 0201 /* CEE/ string */
  559. @d identifier 0202 /* CEE/ identifier or reserved word */
  560. @<Global...@>=
  561. name_pointer cur_section; /* name of section just scanned */
  562. char cur_section_char; /* the character just before that name */
  563. @ @<Include...@>=
  564. #include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
  565. #include <stdlib.h> /* definition of |exit| */
  566. @ As one might expect, |get_next| consists mostly of a big switch
  567. that branches to the various special cases that can arise.
  568. @d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */
  569. @d ishigh(c) ((eight_bits)(c)>0177)
  570. @^high-bit character handling@>
  571. @<Predecl...@>=
  572. eight_bits get_next();
  573. @ @c
  574. eight_bits
  575. get_next() /* produces the next input token */
  576. {@+eight_bits c; /* the current character */
  577.   while (1) {
  578.     @<Check if we're at the end of a preprocessor command@>;
  579.     if (loc>limit && get_line()==0) return(new_section);
  580.     c=*(loc++);
  581.     if (xisdigit(c) || c=='\' || c=='.') @<Get a constant@>@;
  582.     else if (c==''' || c=='"' || (c=='L'&&(*loc==''' || *loc=='"'))@|
  583.            || (c=='<' && sharp_include_line==1))
  584.         @<Get a string@>@;
  585.     else if (xisalpha(c) || isxalpha(c) || ishigh(c))
  586.       @<Get an identifier@>@;
  587.     else if (c=='@@') @<Get control code and possible section name@>@;
  588.     else if (xisspace(c)) continue; /* ignore spaces and tabs */
  589.     if (c=='#' && loc==buffer+1) @<Raise preprocessor flag@>;
  590.     mistake: @<Compress two-symbol operator@>@;
  591.     return(c);
  592.   }
  593. }
  594. @ Because preprocessor commands do not fit in with the rest of the syntax
  595. of CEE/,
  596. we have to deal with them separately.  One solution is to enclose such
  597. commands between special markers.  Thus, when a .# is seen as the
  598. first character of a line, |get_next| returns a special code
  599. |left_preproc| and raises a flag |preprocessing|.
  600. We can use the same internal code number for |left_preproc| as we do
  601. for |ord|, since |get_next| changes |ord| into a string.
  602. @d left_preproc ord /* begins a preprocessor command */
  603. @d right_preproc 0217 /* ends a preprocessor command */
  604. @<Glob...@>=
  605. boolean preprocessing=0; /* are we scanning a preprocessor command? */
  606. @ @<Raise prep...@>= {
  607.   preprocessing=1;
  608.   @<Check if next token is |include|@>;
  609.   return (left_preproc);
  610. }
  611. @ An additional complication is the freakish use of .< and .> to delimit
  612. a file name in lines that start with .{#include}.  We must treat this file
  613. name as a string.
  614. @<Glob...@>=
  615. boolean sharp_include_line=0; /* are we scanning a |#include| line? */
  616. @ @<Check if next token is |include|@>=
  617. while (loc<=buffer_end-7 && xisspace(*loc)) loc++;
  618. if (loc<=buffer_end-6 && strncmp(loc,"include",7)==0) sharp_include_line=1;
  619. @ When we get to the end of a preprocessor line,
  620. we lower the flag and send a code |right_preproc|, unless
  621. the last character was a .\.
  622. @<Check if we're at...@>=
  623.   while (loc==limit-1 && preprocessing && *loc=='\')
  624.     if (get_line()==0) return(new_section); /* still in preprocessor mode */
  625.   if (loc>=limit && preprocessing) {
  626.     preprocessing=sharp_include_line=0;
  627.     return(right_preproc);
  628.   }
  629. @ The following code assigns values to the combinations .{++},
  630. .{--}, .{->}, .{>=}, .{<=}, .{==}, .{<<}, .{>>}, .{!=}, .{vv}, and
  631. .{&&}, and to the CPLUSPLUS/
  632. combinations .{...}, .{::}, .{.*} and .{->*}.
  633. The compound assignment operators (e.g., .{+=}) are
  634. treated as separate tokens.
  635. @d compress(c) if (loc++<=limit) return(c)
  636. @<Compress tw...@>=
  637. switch(c) {
  638.   case '/': if (*loc=='*') {compress(begin_comment);}
  639.     else if (*loc=='/') compress(begin_short_comment); break;
  640.   case '+': if (*loc=='+') compress(plus_plus); break;
  641.   case '-': if (*loc=='-') {compress(minus_minus);}
  642.     else if (*loc=='>') if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);}
  643.                         else compress(minus_gt); break;
  644.   case '.': if (*loc=='*') {compress(period_ast);}
  645.             else if (*loc=='.' && *(loc+1)=='.') {
  646.               loc++; compress(dot_dot_dot);
  647.             }
  648.             break;
  649.   case ':': if (*loc==':') compress(colon_colon); break;
  650.   case '=': if (*loc=='=') compress(eq_eq); break;
  651.   case '>': if (*loc=='=') {compress(gt_eq);}
  652.     else if (*loc=='>') compress(gt_gt); break;
  653.   case '<': if (*loc=='=') {compress(lt_eq);}
  654.     else if (*loc=='<') compress(lt_lt); break;
  655.   case '&': if (*loc=='&') compress(and_and); break;
  656.   case '|': if (*loc=='|') compress(or_or); break;
  657.   case '!': if (*loc=='=') compress(not_eq); break;
  658. }
  659. @ @<Get an identifier@>= {
  660.   id_first=--loc;
  661.   while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc));
  662.   id_loc=loc; return(identifier);
  663. }
  664. @ Different conventions are followed by TEX/ and CEE/ to express octal
  665. and hexadecimal numbers; it is reasonable to stick to each convention
  666. within its realm.  Thus the CEE/ part of a .{CWEB} file has octals
  667. introduced by .0 and hexadecimals by .{0x}, but .{CWEAVE} will print
  668. in italics or typewriter font, respectively, and introduced by single
  669. or double quotes.  In order to simplify the TEX/ macro used to print
  670. such constants, we replace some of the characters.
  671. Notice that in this section and the next, |id_first| and |id_loc|
  672. are pointers into the array |section_text|, not into |buffer|.
  673. @<Get a constant@>= {
  674.   id_first=id_loc=section_text+1;
  675.   if (*(loc-1)=='\') {*id_loc++='~';
  676.   while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */
  677.   else if (*(loc-1)=='0') {
  678.     if (*loc=='x' || *loc=='X') {*id_loc++='^'; loc++;
  679.       while (xisxdigit(*loc)) *id_loc++=*loc++;} /* hex constant */
  680.     else if (xisdigit(*loc)) {*id_loc++='~';
  681.       while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */
  682.     else goto dec; /* decimal constant */
  683.   }
  684.   else { /* decimal constant */
  685.     if (*(loc-1)=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */
  686.     dec: *id_loc++=*(loc-1);
  687.     while (xisdigit(*loc) || *loc=='.') *id_loc++=*loc++;
  688.     if (*loc=='e' || *loc=='E') { /* float constant */
  689.       *id_loc++='_'; loc++;
  690.       if (*loc=='+' || *loc=='-') *id_loc++=*loc++;
  691.       while (xisdigit(*loc)) *id_loc++=*loc++;
  692.     }
  693.   }
  694.   while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
  695.          || *loc=='f' || *loc=='F') {
  696.     *id_loc++='$'; *id_loc++=toupper(*loc); loc++;
  697.   }
  698.   return(constant);
  699. }
  700. @ CEE/ strings and character constants, delimited by double and single
  701. quotes, respectively, can contain newlines or instances of their own
  702. delimiters if they are protected by a backslash.  We follow this
  703. convention, but do not allow the string to be longer than |longest_name|.
  704. @<Get a string@>= {
  705.   char delim = c; /* what started the string */
  706.   id_first = section_text+1;
  707.   id_loc = section_text;
  708.   if (delim==''' && *(loc-2)=='@@') {*++id_loc='@@'; *++id_loc='@@';}
  709.   *++id_loc=delim;
  710.   if (delim=='L') { /* wide character constant */
  711.     delim=*loc++; *++id_loc=delim;
  712.   }
  713.   if (delim=='<') delim='>'; /* for file names in |#include| lines */
  714.   while (1) {
  715.     if (loc>=limit) {
  716.       if(*(limit-1)!='\') {
  717.         err_print("! String didn't end"); loc=limit; break;
  718. @.String didn't end@>
  719.       }
  720.       if(get_line()==0) {
  721.         err_print("! Input ended in middle of string"); loc=buffer; break;
  722. @.Input ended in middle of string@>
  723.       }
  724.     }
  725.     if ((c=*loc++)==delim) {
  726.       if (++id_loc<=section_text_end) *id_loc=c;
  727.       break;
  728.     }
  729.     if (c=='\') if (loc>=limit) continue;
  730.       else if (++id_loc<=section_text_end) {
  731.         *id_loc = '\'; c=*loc++;
  732.       }
  733.     if (++id_loc<=section_text_end) *id_loc=c;
  734.   }
  735.   if (id_loc>=section_text_end) {
  736.     printf("n! String too long: ");
  737. @.String too long@>
  738.     term_write(section_text+1,25);
  739.     printf("..."); mark_error;
  740.   }
  741.   id_loc++;
  742.   return(string);
  743. }
  744. @ After an .{@@} sign has been scanned, the next character tells us
  745. whether there is more work to do.
  746. @<Get control code and possible section name@>= {
  747.   c=*loc++;
  748.   switch(ccode[(eight_bits)c]) {
  749.     case translit_code: err_print("! Use @@l in limbo only"); continue;
  750. @.Use @@l in limbo...@>
  751.     case underline: xref_switch=def_flag; continue;
  752.     case trace: tracing=c-'0'; continue;
  753.     case xref_roman: case xref_wildcard: case xref_typewriter:
  754.     case noop: case TeX_string: c=ccode[c]; skip_restricted(); return(c);
  755.     case section_name:
  756.       @<Scan the section name and make |cur_section| point to it@>;
  757.     case verbatim: @<Scan a verbatim string@>;
  758.     case ord: @<Get a string@>;
  759.     default: return(ccode[(eight_bits)c]);
  760.   }
  761. }
  762. @ The occurrence of a section name sets |xref_switch| to zero,
  763. because the section name might (for example) follow &{int}.
  764. @<Scan the section name...@>= {
  765.   char *k; /* pointer into |section_text| */
  766.   cur_section_char=*(loc-1);
  767.   @<Put section name into |section_text|@>;
  768.   if (k-section_text>3 && strncmp(k-2,"...",3)==0)
  769.         cur_section=section_lookup(section_text+1,k-3,1); /* 1 indicates a prefix */
  770.   else cur_section=section_lookup(section_text+1,k,0);
  771.   xref_switch=0; return(section_name);
  772. }
  773. @ Section names are placed into the |section_text| array with consecutive spaces,
  774. tabs, and carriage-returns replaced by single spaces. There will be no
  775. spaces at the beginning or the end. (We set |section_text[0]=' '| to facilitate
  776. this, since the |section_lookup| routine uses |section_text[1]| as the first
  777. character of the name.)
  778. @<Set init...@>=section_text[0]=' ';
  779. @ @<Put section name...@>=
  780. k=section_text;
  781. while (1) {
  782.   if (loc>limit && get_line()==0) {
  783.     err_print("! Input ended in section name");
  784. @.Input ended in section name@>
  785.     loc=buffer+1; break;
  786.   }
  787.   c=*loc;
  788.   @<If end of name or erroneous control code, |break|@>;
  789.   loc++; if (k<section_text_end) k++;
  790.   if (xisspace(c)) {
  791.     c=' '; if (*(k-1)==' ') k--;
  792.   }
  793. *k=c;
  794. }
  795. if (k>=section_text_end) {
  796.   printf("n! Section name too long: ");
  797. @.Section name too long@>
  798.   term_write(section_text+1,25);
  799.   printf("..."); mark_harmless;
  800. }
  801. if (*k==' ' && k>section_text) k--;
  802. @ @<If end of name...@>=
  803. if (c=='@@') {
  804.   c=*(loc+1);
  805.   if (c=='>') {
  806.     loc+=2; break;
  807.   }
  808.   if (ccode[(eight_bits)c]==new_section) {
  809.     err_print("! Section name didn't end"); break;
  810. @.Section name didn't end@>
  811.   }
  812.   if (c!='@@') {
  813.     err_print("! Control codes are forbidden in section name"); break;
  814. @.Control codes are forbidden...@>
  815.   }
  816.   *(++k)='@@'; loc++; /* now |c==*loc| again */
  817. }
  818. @ This function skips over a restricted context at relatively high speed.
  819. @<Predecl...@>=
  820. void skip_restricted();
  821. @ @c
  822. void
  823. skip_restricted()
  824. {
  825.   id_first=loc; *(limit+1)='@@';
  826. false_alarm:
  827.   while (*loc!='@@') loc++;
  828.   id_loc=loc;
  829.   if (loc++>limit) {
  830.     err_print("! Control text didn't end"); loc=limit;
  831. @.Control text didn't end@>
  832.   }
  833.   else {
  834.     if (*loc=='@@'&&loc<=limit) {loc++; goto false_alarm;}
  835.     if (*loc++!='>')
  836.       err_print("! Control codes are forbidden in control text");
  837. @.Control codes are forbidden...@>
  838.   }
  839. }
  840. @ At the present point in the program we
  841. have |*(loc-1)==verbatim|; we set |id_first| to the beginning
  842. of the string itself, and |id_loc| to its ending-plus-one location in the
  843. buffer.  We also set |loc| to the position just after the ending delimiter.
  844. @<Scan a verbatim string@>= {
  845.   id_first=loc++; *(limit+1)='@@'; *(limit+2)='>';
  846.   while (*loc!='@@' || *(loc+1)!='>') loc++;
  847.   if (loc>=limit) err_print("! Verbatim string didn't end");
  848. @.Verbatim string didn't end@>
  849.   id_loc=loc; loc+=2;
  850.   return (verbatim);
  851. }
  852. @** Phase one processing.
  853. We now have accumulated enough subroutines to make it possible to carry out
  854. .{CWEAVE}'s first pass over the source file. If everything works right,
  855. both phase one and phase two of .{CWEAVE} will assign the same numbers to
  856. sections, and these numbers will agree with what .{CTANGLE} does.
  857. The global variable |next_control| often contains the most recent output of
  858. |get_next|; in interesting cases, this will be the control code that
  859. ended a section or part of a section.
  860. @<Global...@>=
  861. eight_bits next_control; /* control code waiting to be acting upon */
  862. @ The overall processing strategy in phase one has the following
  863. straightforward outline.
  864. @<Predecl...@>=
  865. void phase_one();
  866. @ @c
  867. void
  868. phase_one() {
  869.   phase=1; reset_input(); section_count=0;
  870.   skip_limbo(); change_exists=0;
  871.   while (!input_has_ended)
  872.     @<Store cross-reference data for the current section@>;
  873.   changed_section[section_count]=change_exists;
  874.     /* the index changes if anything does */
  875.   phase=2; /* prepare for second phase */
  876.   @<Print error messages about unused or undefined section names@>;
  877. }
  878. @ @<Store cross-reference data...@>=
  879. {
  880.   if (++section_count==max_sections) overflow("section number");
  881.   changed_section[section_count]=changing;
  882.      /* it will become 1 if any line changes */
  883.   if (*(loc-1)=='*' && show_progress) {
  884.     printf("*%d",section_count);
  885.     update_terminal; /* print a progress report */
  886.   }
  887.   @<Store cross-references in the TEX/ part of a section@>;
  888.   @<Store cross-references in the definition part of a section@>;
  889.   @<Store cross-references in the CEE/ part of a section@>;
  890.   if (changed_section[section_count]) change_exists=1;
  891. }
  892. @ The |C_xref| subroutine stores references to identifiers in
  893. CEE/ text material beginning with the current value of |next_control|
  894. and continuing until |next_control| is `.{' or `.{v}', or until the next
  895. ``milestone'' is passed (i.e., |next_control>=format_code|). If
  896. |next_control>=format_code| when |C_xref| is called, nothing will happen;
  897. but if |next_control=='|'| upon entry, the procedure assumes that this is
  898. the `.{v}' preceding CEE/ text that is to be processed.
  899. The parameter |spec_ctrl| is used to change this behavior. In most cases
  900. |C_xref| is called with |spec_ctrl==ignore|, which triggers the default
  901. processing described above. If |spec_ctrl==section_name|, section names will
  902. be gobbled. This is used when CEE/ text in the TEX/ part or inside comments
  903. is parsed: It allows for section names to appear in pb, but these
  904. strings will not be entered into the cross reference lists since they are not
  905. definitions of section names.
  906. The program uses the fact that our internal code numbers satisfy
  907. the relations |xref_roman==identifier+roman| and |xref_wildcard==identifier
  908. +wildcard| and |xref_typewriter==identifier+typewriter|,
  909. as well as |normal==0|.
  910. @<Predecl...@>=
  911. void C_xref();
  912. @ @c
  913. void
  914. C_xref( spec_ctrl ) /* makes cross-references for CEE/ identifiers */
  915.   eight_bits spec_ctrl;
  916. {
  917.   name_pointer p; /* a referenced name */
  918.   while (next_control<format_code || next_control==spec_ctrl) {
  919.     if (next_control>=identifier && next_control<=xref_typewriter) {
  920.       if (next_control>identifier) @<Replace |"@@@@"| by |"@@"| @>@;
  921.       p=id_lookup(id_first, id_loc,next_control-identifier); new_xref(p);
  922.     }
  923.     if (next_control==section_name) {
  924.       section_xref_switch=cite_flag;
  925.       new_section_xref(cur_section);
  926.     }
  927.     next_control=get_next();
  928.     if (next_control=='|' || next_control==begin_comment ||
  929.         next_control==begin_short_comment) return;
  930.   }
  931. }
  932. @ The |outer_xref| subroutine is like |C_xref| except that it begins
  933. with |next_control!='|'| and ends with |next_control>=format_code|. Thus, it
  934. handles CEE/ text with embedded comments.
  935. @<Predecl...@>=
  936. void outer_xref();
  937. @ @c
  938. void
  939. outer_xref() /* extension of |C_xref| */
  940. {
  941.   int bal; /* brace level in comment */
  942.   while (next_control<format_code)
  943.     if (next_control!=begin_comment && next_control!=begin_short_comment)
  944.       C_xref(ignore);
  945.     else {
  946.       boolean is_long_comment=(next_control==begin_comment);
  947.       bal=copy_comment(is_long_comment,1); next_control='|';
  948.       while (bal>0) {
  949.         C_xref(section_name); /* do not reference section names in comments */
  950.         if (next_control=='|') bal=copy_comment(is_long_comment,bal);
  951.         else bal=0; /* an error message will occur in phase two */
  952.       }
  953.     }
  954. }
  955. @ In the TEX/ part of a section, cross-reference entries are made only for
  956. the identifiers in CEE/ texts enclosed in pb, or for control texts
  957. enclosed in .{@@^}$,ldots,$.{@@>} or .{@@.}$,ldots,$.{@@>}
  958. or .{@@:}$,ldots,$.{@@>}.
  959. @<Store cross-references in the T...@>=
  960. while (1) {
  961.   switch (next_control=skip_TeX()) {
  962.     case translit_code: err_print("! Use @@l in limbo only"); continue;
  963. @.Use @@l in limbo...@>
  964.     case underline: xref_switch=def_flag; continue;
  965.     case trace: tracing=*(loc-1)-'0'; continue;
  966.     case '|': C_xref(section_name); break;
  967.     case xref_roman: case xref_wildcard: case xref_typewriter:
  968.     case noop: case section_name:
  969.       loc-=2; next_control=get_next(); /* scan to .{@@>} */
  970.       if (next_control>=xref_roman && next_control<=xref_typewriter) {
  971.         @<Replace |"@@@@"| by |"@@"| @>@;
  972.         new_xref(id_lookup(id_first, id_loc,next_control-identifier));
  973.       }
  974.       break;
  975.   }
  976.   if (next_control>=format_code) break;
  977. }
  978. @ @<Replace |"@@@@"| by |"@@"| @>=
  979. {
  980.   char *src=id_first,*dst=id_first;
  981.   while(src<id_loc){
  982.     if(*src=='@@') src++;
  983.     *dst++=*src++;
  984.   }
  985.   id_loc=dst;
  986.   while (dst<src) *dst++=' '; /* clean up in case of error message display */
  987. }
  988. @ During the definition and CEE/ parts of a section, cross-references
  989. are made for all identifiers except reserved words. However, the right
  990. identifier in a format definition is not referenced, and the left
  991. identifier is referenced only if it has been explicitly
  992. underlined (preceded by .{@@!}).
  993. The TEX/ code in comments is, of course, ignored, except for
  994. CEE/ portions enclosed in pb; the text of a section name is skipped
  995. entirely, even if it contains pb constructions.
  996. The variables |lhs| and |rhs| point to the respective identifiers involved
  997. in a format definition.
  998. @<Global...@>=
  999. name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */
  1000. @ When we get to the following code we have |next_control>=format_code|.
  1001. @<Store cross-references in the d...@>=
  1002. while (next_control<=definition) { /* |format_code| or |definition| */
  1003.   if (next_control==definition) {
  1004.     xref_switch=def_flag; /* implied .{@@!} */
  1005.     next_control=get_next();
  1006.   } else @<Process a format definition@>;
  1007.   outer_xref();
  1008. }
  1009. @ Error messages for improper format definitions will be issued in phase
  1010. two. Our job in phase one is to define the |ilk| of a properly formatted
  1011. identifier, and to remove cross-references to identifiers that we now
  1012. discover should be unindexed.
  1013. @<Process a form...@>= {
  1014.   next_control=get_next();
  1015.   if (next_control==identifier) {
  1016.     lhs=id_lookup(id_first, id_loc,normal); lhs->ilk=normal;
  1017.     if (xref_switch) new_xref(lhs);
  1018.     next_control=get_next();
  1019.     if (next_control==identifier) {
  1020.       rhs=id_lookup(id_first, id_loc,normal);
  1021.       lhs->ilk=rhs->ilk;
  1022.       if (unindexed(lhs)) { /* retain only underlined entries */
  1023.         xref_pointer q,r=NULL;
  1024.         for (q=(xref_pointer)lhs->xref;q>xmem;q=q->xlink)
  1025.           if (q->num<def_flag)
  1026.             if (r) r->xlink=q->xlink;
  1027.             else lhs->xref=(char*)q->xlink;
  1028.           else r=q;
  1029.       }
  1030.       next_control=get_next();
  1031.     }
  1032.   }
  1033. }
  1034. @ A much simpler processing of format definitions occurs when the
  1035. definition is found in limbo.
  1036. @<Process simple format in limbo@>=
  1037. {
  1038.   if (get_next()!=identifier)
  1039.     err_print("! Missing left identifier of @@s");
  1040. @.Missing left identifier...@>
  1041.   else {
  1042.     lhs=id_lookup(id_first,id_loc,normal);
  1043.     if (get_next()!=identifier)
  1044.       err_print("! Missing right identifier of @@s");
  1045. @.Missing right identifier...@>
  1046.     else {
  1047.       rhs=id_lookup(id_first,id_loc,normal);
  1048.       lhs->ilk=rhs->ilk;
  1049.     }
  1050.   }
  1051. }
  1052. @ Finally, when the TEX/ and definition parts have been treated, we have
  1053. |next_control>=begin_C|.
  1054. @<Store cross-references in the CEE/...@>=
  1055. if (next_control<=section_name) {  /* |begin_C| or |section_name| */
  1056.   if (next_control==begin_C) section_xref_switch=0;
  1057.   else {
  1058.     section_xref_switch=def_flag;
  1059.     if(cur_section_char=='(' && cur_section!=name_dir)
  1060.       set_file_flag(cur_section);
  1061.   }
  1062.   do {
  1063.     if (next_control==section_name && cur_section!=name_dir)
  1064.       new_section_xref(cur_section);
  1065.     next_control=get_next(); outer_xref();
  1066.   } while ( next_control<=section_name);
  1067. }
  1068. @ After phase one has looked at everything, we want to check that each
  1069. section name was both defined and used.  The variable |cur_xref| will point
  1070. to cross-references for the current section name of interest.
  1071. @<Global...@>=
  1072. xref_pointer cur_xref; /* temporary cross-reference pointer */
  1073. boolean an_output; /* did |file_flag| precede |cur_xref|? */
  1074. @ The following recursive procedure
  1075. walks through the tree of section names and prints out anomalies.
  1076. @^recursion@>
  1077. @<Predecl...@>=
  1078. void section_check();
  1079. @ @c
  1080. void
  1081. section_check(p)
  1082. name_pointer p; /* print anomalies in subtree |p| */
  1083. {
  1084.   if (p) {
  1085.     section_check(p->llink);
  1086.     cur_xref=(xref_pointer)p->xref;
  1087.     if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;}
  1088.     else an_output=0;
  1089.     if (cur_xref->num <def_flag) {
  1090.       printf("n! Never defined: <"); print_section_name(p); putchar('>'); mark_harmless;
  1091. @.Never defined: <section name>@>
  1092.     }
  1093.     while (cur_xref->num >=cite_flag) cur_xref=cur_xref->xlink;
  1094.     if (cur_xref==xmem && !an_output) {
  1095.       printf("n! Never used: <"); print_section_name(p); putchar('>'); mark_harmless;
  1096. @.Never used: <section name>@>
  1097.     }
  1098.     section_check(p->rlink);
  1099.   }
  1100. }
  1101. @ @<Print error messages about un...@>=section_check(root)
  1102. @* Low-level output routines.
  1103. The TEX/ output is supposed to appear in lines at most |line_length|
  1104. characters long, so we place it into an output buffer. During the output
  1105. process, |out_line| will hold the current line number of the line about to
  1106. be output.
  1107. @<Global...@>=
  1108. char out_buf[line_length+1]; /* assembled characters */
  1109. char *out_ptr; /* just after last character in |out_buf| */
  1110. char *out_buf_end = out_buf+line_length; /* end of |out_buf| */
  1111. int out_line; /* number of next line to be output */
  1112. @ The |flush_buffer| routine empties the buffer up to a given breakpoint,
  1113. and moves any remaining characters to the beginning of the next line.
  1114. If the |per_cent| parameter is 1 a |'%'| is appended to the line
  1115. that is being output; in this case the breakpoint |b| should be strictly
  1116. less than |out_buf_end|. If the |per_cent| parameter is |0|,
  1117. trailing blanks are suppressed.
  1118. The characters emptied from the buffer form a new line of output;
  1119. if the |carryover| parameter is true, a |"%"| in that line will be
  1120. carried over to the next line (so that TEX/ will ignore the completion
  1121. of commented-out text).
  1122. @d c_line_write(c) fflush(active_file),fwrite(out_buf+1,sizeof(char),c,active_file)
  1123. @d tex_putc(c) putc(c,active_file)
  1124. @d tex_new_line putc('n',active_file)
  1125. @d tex_printf(c) fprintf(active_file,c)
  1126. @c
  1127. void
  1128. flush_buffer(b,per_cent,carryover)
  1129. char *b;  /* outputs from |out_buf+1| to |b|,where |b<=out_ptr| */
  1130. boolean per_cent,carryover;
  1131. {
  1132.   char *j; j=b; /* pointer into |out_buf| */
  1133.   if (! per_cent) /* remove trailing blanks */
  1134.     while (j>out_buf && *j==' ') j--;
  1135.   c_line_write(j-out_buf);
  1136.   if (per_cent) tex_putc('%');
  1137.   tex_new_line; out_line++;
  1138.   if (carryover)
  1139.     while (j>out_buf)
  1140.       if (*j--=='%' && (j==out_buf || *j!='\')) {
  1141.         *b--='%'; break;
  1142.       }
  1143.   if (b<out_ptr) strncpy(out_buf+1,b+1,out_ptr-b);
  1144.   out_ptr-=b-out_buf;
  1145. }
  1146. @ When we are copying TEX/ source material, we retain line breaks
  1147. that occur in the input, except that an empty line is not
  1148. output when the TEX/ source line was nonempty. For example, a line
  1149. of the TEX/ file that contains only an index cross-reference entry
  1150. will not be copied. The |finish_line| routine is called just before
  1151. |get_line| inputs a new line, and just after a line break token has
  1152. been emitted during the output of translated CEE/ text.
  1153. @c
  1154. void
  1155. finish_line() /* do this at the end of a line */
  1156. {
  1157.   char *k; /* pointer into |buffer| */
  1158.   if (out_ptr>out_buf) flush_buffer(out_ptr,0,0);
  1159.   else {
  1160.     for (k=buffer; k<=limit; k++)
  1161.       if (!(xisspace(*k))) return;
  1162.     flush_buffer(out_buf,0,0);
  1163.   }
  1164. }
  1165. @ In particular, the |finish_line| procedure is called near the very
  1166. beginning of phase two. We initialize the output variables in a slightly
  1167. tricky way so that the first line of the output file will be
  1168. `.{\input cwebmac}'.
  1169. @<Set init...@>=
  1170. out_ptr=out_buf+1; out_line=1; active_file=tex_file;
  1171. *out_ptr='c'; tex_printf("\input cwebma");
  1172. @ When we wish to append one character |c| to the output buffer, we write
  1173. `|out(c)|'; this will cause the buffer to be emptied if it was already
  1174. full.  If we want to append more than one character at once, we say
  1175. |out_str(s)|, where |s| is a string containing the characters.
  1176. A line break will occur at a space or after a single-nonletter
  1177. TEX/ control sequence.
  1178. @d out(c) {if (out_ptr>=out_buf_end) break_out(); *(++out_ptr)=c;}
  1179. @c
  1180. void
  1181. out_str(s) /* output characters from |s| to end of string */
  1182. char *s;
  1183. {
  1184.   while (*s) out(*s++);
  1185. }
  1186. @ The |break_out| routine is called just before the output buffer is about
  1187. to overflow. To make this routine a little faster, we initialize position
  1188. 0 of the output buffer to `.\'; this character isn't really output.
  1189. @<Set init...@>=
  1190. out_buf[0]='\';
  1191. @ A long line is broken at a blank space or just before a backslash that isn't
  1192. preceded by another backslash. In the latter case, a |'%'| is output at
  1193. the break.
  1194. @<Predecl...@>=
  1195. void break_out();
  1196. @ @c
  1197. void
  1198. break_out() /* finds a way to break the output line */
  1199. {
  1200.   char *k=out_ptr; /* pointer into |out_buf| */
  1201.   while (1) {
  1202.     if (k==out_buf) @<Print warning message, break the line, |return|@>;
  1203.     if (*k==' ') {
  1204.       flush_buffer(k,0,1); return;
  1205.     }
  1206.     if (*(k--)=='\' && *k!='\') { /* we've decreased |k| */
  1207.       flush_buffer(k,1,1); return;
  1208.     }
  1209.   }
  1210. }
  1211. @ We get to this section only in the unusual case that the entire output line
  1212. consists of a string of backslashes followed by a string of nonblank
  1213. non-backslashes. In such cases it is almost always safe to break the
  1214. line by putting a |'%'| just before the last character.
  1215. @<Print warning message...@>=
  1216. {
  1217.   printf("n! Line had to be broken (output l. %d):n",out_line);
  1218. @.Line had to be broken@>
  1219.   term_write(out_buf+1, out_ptr-out_buf-1);
  1220.   new_line; mark_harmless;
  1221.   flush_buffer(out_ptr-1,1,1); return;
  1222. }
  1223. @ Here is a macro that outputs a section number in decimal notation.
  1224. The number to be converted by |out_section| is known to be less than
  1225. |def_flag|, so it cannot have more than five decimal digits.  If
  1226. the section is changed, we output `.{\*}' just after the number.
  1227. @c
  1228. void
  1229. out_section(n)
  1230. sixteen_bits n;
  1231. {
  1232.   char s[6];
  1233.   sprintf(s,"%d",n); out_str(s);
  1234.   if(changed_section[n]) out_str ("\*");
  1235. @.\*@>
  1236. }
  1237. @ The |out_name| procedure is used to output an identifier or index
  1238. entry, enclosing it in braces.
  1239. @c
  1240. void
  1241. out_name(p)
  1242. name_pointer p;
  1243. {
  1244.   char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */
  1245.   out('{');
  1246.   for (k=p->byte_start; k<k_end; k++) {
  1247.     if (isxalpha(*k)) out('\');
  1248.     out(*k);
  1249.   }
  1250.   out('}');
  1251. }
  1252. @* Routines that copy TEX/ material.
  1253. During phase two, we use subroutines |copy_limbo|, |copy_TeX|, and
  1254. |copy_comment| in place of the analogous |skip_limbo|, |skip_TeX|, and
  1255. |skip_comment| that were used in phase one. (Well, |copy_comment|
  1256. was actually written in such a way that it functions as |skip_comment|
  1257. in phase one.)
  1258. The |copy_limbo| routine, for example, takes TEX/ material that is not
  1259. part of any section and transcribes it almost verbatim to the output file.
  1260. The use of `.{@@}' signs is severely restricted in such material:
  1261. `.{@@@@}' pairs are replaced by singletons; `.{@@l}' and `.{@@q}' and
  1262. `.{@@s}' are interpreted.
  1263. @c
  1264. void
  1265. copy_limbo()
  1266. {
  1267.   char c;
  1268.   while (1) {
  1269.     if (loc>limit && (finish_line(), get_line()==0)) return;
  1270.     *(limit+1)='@@';
  1271.     while (*loc!='@@') out(*(loc++));
  1272.     if (loc++<=limit) {
  1273.       c=*loc++;
  1274.       if (ccode[(eight_bits)c]==new_section) break;
  1275.       switch (ccode[(eight_bits)c]) {
  1276.         case translit_code: out_str("\ATL"); break;
  1277. @.\ATL@>
  1278.         case '@@': out('@@'); break;
  1279.         case noop: skip_restricted(); break;
  1280.         case format_code: if (get_next()==identifier) get_next();
  1281.           if (loc>=limit) get_line(); /* avoid blank lines in output */
  1282.           break; /* the operands of .{@@s} are ignored on this pass */
  1283.         default: err_print("! Double @@ should be used in limbo");
  1284. @.Double @@ should be used...@>
  1285.         out('@@');
  1286.       }
  1287.     }
  1288.   }
  1289. }
  1290. @ The |copy_TeX| routine processes the TEX/ code at the beginning of a
  1291. section; for example, the words you are now reading were copied in this
  1292. way. It returns the next control code or `.{v}' found in the input.
  1293. We don't copy spaces or tab marks into the beginning of a line. This
  1294. makes the test for empty lines in |finish_line| work.
  1295. @ @f copy_TeX TeX
  1296. @c
  1297. eight_bits
  1298. copy_TeX()
  1299. {
  1300.   char c; /* current character being copied */
  1301.   while (1) {
  1302.     if (loc>limit && (finish_line(), get_line()==0)) return(new_section);
  1303.     *(limit+1)='@@';
  1304.     while ((c=*(loc++))!='|' && c!='@@') {
  1305.       out(c);
  1306.       if (out_ptr==out_buf+1 && (xisspace(c))) out_ptr--;
  1307.     }
  1308.     if (c=='|') return('|');
  1309.     if (loc<=limit) return(ccode[(eight_bits)*(loc++)]);
  1310.   }
  1311. }
  1312. @ The |copy_comment| function issues a warning if more braces are opened than
  1313. closed, and in the case of a more serious error it supplies enough
  1314. braces to keep TEX/ from complaining about unbalanced braces.
  1315. Instead of copying the TEX/ material
  1316. into the output buffer, this function copies it into the token memory
  1317. (in phase two only).
  1318. The abbreviation |app_tok(t)| is used to append token |t| to the current
  1319. token list, and it also makes sure that it is possible to append at least
  1320. one further token without overflow.
  1321. @d app_tok(c) {if (tok_ptr+2>tok_mem_end) overflow("token"); *(tok_ptr++)=c;}
  1322. @<Predec...@>=
  1323. int copy_comment();
  1324. @ @c
  1325. int copy_comment(is_long_comment,bal) /* copies TEX/ code in comments */
  1326. boolean is_long_comment; /* is this a traditional CEE/ comment? */
  1327. int bal; /* brace balance */
  1328. {
  1329.   char c; /* current character being copied */
  1330.   while (1) {
  1331.     if (loc>limit) {
  1332.       if (is_long_comment) {
  1333.         if (get_line()==0) {
  1334.           err_print("! Input ended in mid-comment");
  1335. @.Input ended in mid-comment@>
  1336.           loc=buffer+1; goto done;
  1337.         }
  1338.       }
  1339.       else {
  1340.         if (bal>1) err_print("! Missing } in comment");
  1341. @.Missing } in comment@>
  1342.         goto done;
  1343.       }
  1344.     }
  1345.     c=*(loc++);
  1346.     if (c=='|') return(bal);
  1347.     if (is_long_comment) @<Check for end of comment@>;
  1348.     if (phase==2) {
  1349.       if (ishigh(c)) app_tok(quoted_char);
  1350.       app_tok(c);
  1351.     }
  1352.     @<Copy special things when |c=='@@', '\'|@>;
  1353.     if (c=='{') bal++;
  1354.     else if (c=='}') {
  1355.       if(bal>1) bal--;
  1356.       else {err_print("! Extra } in comment");
  1357. @.Extra } in comment@>
  1358.         if (phase==2) tok_ptr--;
  1359.       }
  1360.     }
  1361.   }
  1362. done:@<Clear |bal| and |return|@>;
  1363. }
  1364. @ @<Check for end of comment@>=
  1365. if (c=='*' && *loc=='/') {
  1366.   loc++;
  1367.   if (bal>1) err_print("! Missing } in comment");
  1368. @.Missing } in comment@>
  1369.   goto done;
  1370. }
  1371. @ @<Copy special things when |c=='@@'...@>=
  1372. if (c=='@@') {
  1373.   if (*(loc++)!='@@') {
  1374.     err_print("! Illegal use of @@ in comment");
  1375. @.Illegal use of @@...@>
  1376.     loc-=2; if (phase==2) *(tok_ptr-1)=' '; goto done;
  1377.   }
  1378. }
  1379. else if (c=='\' && *loc!='@@')
  1380.   if (phase==2) app_tok(*(loc++)) else loc++;
  1381. @ We output
  1382. enough right braces to keep TEX/ happy.
  1383. @<Clear |bal|...@>=
  1384. if (phase==2) while (bal-- >0) app_tok('}');
  1385. return(0);
  1386. @** Parsing.
  1387. The most intricate part of .{CWEAVE} is its mechanism for converting
  1388. CEE/-like code into TEX/ code, and we might as well plunge into this
  1389. aspect of the program now. A ``bottom up'' approach is used to parse the
  1390. CEE/-like material, since .{CWEAVE} must deal with fragmentary
  1391. constructions whose overall ``part of speech'' is not known.
  1392. At the lowest level, the input is represented as a sequence of entities
  1393. that we shall call {it scraps}, where each scrap of information consists
  1394. of two parts, its {it category} and its {it translation}. The category
  1395. is essentially a syntactic class, and the translation is a token list that
  1396. represents TEX/ code. Rules of syntax and semantics tell us how to
  1397. combine adjacent scraps into larger ones, and if we are lucky an entire
  1398. CEE/ text that starts out as hundreds of small scraps will join
  1399. together into one gigantic scrap whose translation is the desired TEX/
  1400. code. If we are unlucky, we will be left with several scraps that don't
  1401. combine; their translations will simply be output, one by one.
  1402. The combination rules are given as context-sensitive productions that are
  1403. applied from left to right. Suppose that we are currently working on the
  1404. sequence of scraps $s_1,s_2ldots s_n$. We try first to find the longest
  1405. production that applies to an initial substring $s_1,s_2ldots,$; but if
  1406. no such productions exist, we try to find the longest production
  1407. applicable to the next substring $s_2,s_3ldots,$; and if that fails, we
  1408. try to match $s_3,s_4ldots,$, etc.
  1409. A production applies if the category codes have a given pattern. For
  1410. example, one of the productions (see rule~3) is
  1411. $$hbox{|exp| }left{matrix{hbox{|binop|}crhbox{|unorbinop|}}right}
  1412. hbox{ |exp| }RAhbox{ |exp|}$$
  1413. and it means that three consecutive scraps whose respective categories are
  1414. |exp|, |binop| (or |unorbinop|),
  1415. and |exp| are converted to one scrap whose category
  1416. is |exp|.  The translations of the original
  1417. scraps are simply concatenated.  The case of
  1418. $$hbox{|exp| |comma| |exp| $RA$ |exp|} hskip4emE_1C,\{opt}9,E_2$$
  1419. (rule 4) is only slightly more complicated:
  1420. Here the resulting |exp| translation
  1421. consists not only of the three original translations, but also of the
  1422. tokens |opt| and 9 between the translations of the
  1423. |comma| and the following |exp|.
  1424. In the TEX/ file, this will specify an optional line break after the
  1425. comma, with penalty 90.
  1426. At each opportunity the longest possible production is applied.  For
  1427. example, if the current sequence of scraps is |int_like| |cast|
  1428. |lbrace|, rule 31 is applied; but if the sequence is |int_like| |cast|
  1429. followed by anything other than |lbrace|, rule 32 takes effect.
  1430. Translation rules such as `$E_1C,\{opt}9,E_2$' above use subscripts
  1431. to distinguish between translations of scraps whose categories have the
  1432. same initial letter; these subscripts are assigned from left to right.
  1433. @ Here is a list of the category codes that scraps can have.
  1434. (A few others, like |int_like|, have already been defined; the
  1435. |cat_name| array contains a complete list.)
  1436. @d exp 1 /* denotes an expression, including perhaps a single identifier */
  1437. @d unop 2 /* denotes a unary operator */
  1438. @d binop 3 /* denotes a binary operator */
  1439. @d unorbinop 4
  1440.   /* denotes an operator that can be unary or binary, depending on context */
  1441. @d cast 5 /* denotes a cast */
  1442. @d question 6 /* denotes a question mark and possibly the expressions flanking it */
  1443. @d lbrace 7 /* denotes a left brace */
  1444. @d rbrace 8 /* denotes a right brace */
  1445. @d decl_head 9 /* denotes an incomplete declaration */
  1446. @d comma 10 /* denotes a comma */
  1447. @d lpar 11 /* denotes a left parenthesis or left bracket */
  1448. @d rpar 12 /* denotes a right parenthesis or right bracket */
  1449. @d prelangle 13 /* denotes `$<$' before we know what it is */
  1450. @d prerangle 14 /* denotes `$>$' before we know what it is */
  1451. @d langle 15 /* denotes `$<$' when it's used as angle bracket in a template */
  1452. @d colcol 18 /* denotes `::' */
  1453. @d base 19 /* denotes a colon that introduces a base specifier */
  1454. @d decl 20 /* denotes a complete declaration */
  1455. @d struct_head 21 /* denotes the beginning of a structure specifier */
  1456. @d stmt 23 /* denotes a complete statement */
  1457. @d function 24 /* denotes a complete function */
  1458. @d fn_decl 25 /* denotes a function declarator */
  1459. @d semi 27 /* denotes a semicolon */
  1460. @d colon 28 /* denotes a colon */
  1461. @d tag 29 /* denotes a statement label */
  1462. @d if_head 30 /* denotes the beginning of a compound conditional */
  1463. @d else_head 31 /* denotes a prefix for a compound statement */
  1464. @d if_clause 32 /* pending .{if} together with a condition */
  1465. @d lproc 35 /* begins a preprocessor command */
  1466. @d rproc 36 /* ends a preprocessor command */
  1467. @d insert 37 /* a scrap that gets combined with its neighbor */
  1468. @d section_scrap 38 /* section name */
  1469. @d dead 39 /* scrap that won't combine */
  1470. @d begin_arg 58 /* .{@@[} */
  1471. @d end_arg 59 /* .{@@]} */
  1472. @<Glo...@>=
  1473. char cat_name[256][12];
  1474. eight_bits cat_index;
  1475. @ @<Set in...@>=
  1476.     for (cat_index=0;cat_index<255;cat_index++)
  1477.       strcpy(cat_name[cat_index],"UNKNOWN");
  1478.     strcpy(cat_name[exp],"exp");
  1479.     strcpy(cat_name[unop],"unop");
  1480.     strcpy(cat_name[binop],"binop");
  1481.     strcpy(cat_name[unorbinop],"unorbinop");
  1482.     strcpy(cat_name[cast],"cast");
  1483.     strcpy(cat_name[question],"?");
  1484.     strcpy(cat_name[lbrace],"{"@q}@>);
  1485.     strcpy(cat_name[rbrace],@q{@>"}");
  1486.     strcpy(cat_name[decl_head],"decl_head");
  1487.     strcpy(cat_name[comma],",");
  1488.     strcpy(cat_name[lpar],"(");
  1489.     strcpy(cat_name[rpar],")");
  1490.     strcpy(cat_name[prelangle],"<");
  1491.     strcpy(cat_name[prerangle],">");
  1492.     strcpy(cat_name[langle],"\<");
  1493.     strcpy(cat_name[colcol],"::");
  1494.     strcpy(cat_name[base],"\:");
  1495.     strcpy(cat_name[decl],"decl");
  1496.     strcpy(cat_name[struct_head],"struct_head");
  1497.     strcpy(cat_name[stmt],"stmt");
  1498.     strcpy(cat_name[function],"function");
  1499.     strcpy(cat_name[fn_decl],"fn_decl");
  1500.     strcpy(cat_name[else_like],"else_like");
  1501.     strcpy(cat_name[semi],";");
  1502.     strcpy(cat_name[colon],":");
  1503.     strcpy(cat_name[tag],"tag");
  1504.     strcpy(cat_name[if_head],"if_head");
  1505.     strcpy(cat_name[else_head],"else_head");
  1506.     strcpy(cat_name[if_clause],"if()");
  1507.     strcpy(cat_name[lproc],"#{"@q}@>);
  1508.     strcpy(cat_name[rproc],@q{@>"#}");
  1509.     strcpy(cat_name[insert],"insert");
  1510.     strcpy(cat_name[section_scrap],"section");
  1511.     strcpy(cat_name[dead],"@@d");
  1512.     strcpy(cat_name[public_like],"public");
  1513.     strcpy(cat_name[operator_like],"operator");
  1514.     strcpy(cat_name[new_like],"new");
  1515.     strcpy(cat_name[catch_like],"catch");
  1516.     strcpy(cat_name[for_like],"for");
  1517.     strcpy(cat_name[do_like],"do");
  1518.     strcpy(cat_name[if_like],"if");
  1519.     strcpy(cat_name[raw_rpar],")?");
  1520.     strcpy(cat_name[raw_unorbin],"unorbinop?");
  1521.     strcpy(cat_name[const_like],"const");
  1522.     strcpy(cat_name[raw_int],"raw");
  1523.     strcpy(cat_name[int_like],"int");
  1524.     strcpy(cat_name[case_like],"case");
  1525.     strcpy(cat_name[sizeof_like],"sizeof");
  1526.     strcpy(cat_name[struct_like],"struct");
  1527.     strcpy(cat_name[typedef_like],"typedef");
  1528.     strcpy(cat_name[define_like],"define");
  1529.     strcpy(cat_name[begin_arg],"@@["@q]@>);
  1530.     strcpy(cat_name[end_arg],@q[@>"@@]");
  1531.     strcpy(cat_name[0],"zero");
  1532. @ This code allows .{CWEAVE} to display its parsing steps.
  1533. @c
  1534. void
  1535. print_cat(c) /* symbolic printout of a category */
  1536. eight_bits c;
  1537. {
  1538.   printf(cat_name[c]);
  1539. }
  1540. @ The token lists for translated TEX/ output contain some special control
  1541. symbols as well as ordinary characters. These control symbols are
  1542. interpreted by .{CWEAVE} before they are written to the output file.
  1543. yskiphang |break_space| denotes an optional line break or an en space;
  1544. yskiphang |force| denotes a line break;
  1545. yskiphang |big_force| denotes a line break with additional vertical space;
  1546. yskiphang |preproc_line| denotes that the line will be printed flush left;
  1547. yskiphang |opt| denotes an optional line break (with the continuation
  1548. line indented two ems with respect to the normal starting position)---this
  1549. code is followed by an integer |n|, and the break will occur with penalty
  1550. $10n$;
  1551. yskiphang |backup| denotes a backspace of one em;
  1552. yskiphang |cancel| obliterates any |break_space|, |opt|, |force|, or
  1553. |big_force| tokens that immediately precede or follow it and also cancels any
  1554. |backup| tokens that follow it;
  1555. yskiphang |indent| causes future lines to be indented one more em;
  1556. yskiphang |outdent| causes future lines to be indented one less em.
  1557. yskipnoindent All of these tokens are removed from the TEX/ output that
  1558. comes from CEE/ text between pb signs; |break_space| and |force| and
  1559. |big_force| become single spaces in this mode. The translation of other
  1560. CEE/ texts results in TEX/ control sequences .{\1}, .{\2},
  1561. .{\3}, .{\4}, .{\5}, .{\6}, .{\7}, .{\8}
  1562. corresponding respectively to
  1563. |indent|, |outdent|, |opt|, |backup|, |break_space|, |force|,
  1564. |big_force| and |preproc_line|.
  1565. However, a sequence of consecutive `. ', |break_space|,
  1566. |force|, and/or |big_force| tokens is first replaced by a single token
  1567. (the maximum of the given ones).
  1568. The token |math_rel| will be translated into
  1569. .{\MRL{}, and it will get a matching .} later.
  1570. Other control sequences in the TEX/ output will be
  1571. `.{\\{}$,ldots,$.}'
  1572. surrounding identifiers, `.{\&{}$,ldots,$.}' surrounding
  1573. reserved words, `.{\.{}$,ldots,$.}' surrounding strings,
  1574. `.{\C{}$,ldots,$.}$,$|force|' surrounding comments, and
  1575. `.{\X$n$:}$,ldots,$.{\X}' surrounding section names, where
  1576. |n| is the section number.
  1577. @d math_rel 0206
  1578. @d big_cancel 0210 /* like |cancel|, also overrides spaces */
  1579. @d cancel 0211 /* overrides |backup|, |break_space|, |force|, |big_force| */
  1580. @d indent 0212 /* one more tab (.{\1}) */
  1581. @d outdent 0213 /* one less tab (.{\2}) */
  1582. @d opt 0214 /* optional break in mid-statement (.{\3}) */
  1583. @d backup 0215 /* stick out one unit to the left (.{\4}) */
  1584. @d break_space 0216 /* optional break between statements (.{\5}) */
  1585. @d force 0217 /* forced break between statements (.{\6}) */
  1586. @d big_force 0220 /* forced break with additional space (.{\7}) */
  1587. @d preproc_line 0221 /* begin line without indentation (.{\8}) */
  1588. @^high-bit character handling@>
  1589. @d quoted_char 0222
  1590.         /* introduces a character token in the range |0200|--|0377| */
  1591. @d end_translation 0223 /* special sentinel token at end of list */
  1592. @d inserted 0224 /* sentinel to mark translations of inserts */
  1593. @ The raw input is converted into scraps according to the following table,
  1594. which gives category codes followed by the translations.
  1595. defstars {.{**}}%
  1596. The symbol `stars' stands for `.{\&{{rm identifier}}}',
  1597. i.e., the identifier itself treated as a reserved word.
  1598. The right-hand column is the so-called |mathness|, which is explained
  1599. further below.
  1600. An identifier |c| of length 1 is translated as .{\v c} instead of
  1601. as .{\\{c}}. An identifier .{CAPS} in all caps is translated as
  1602. .{\.{CAPS}} instead of as .{\\{CAPS}}. An identifier that has
  1603. become a reserved word via |typedef| is translated with .{\&} replacing
  1604. .{\\} and |raw_int| replacing |exp|.
  1605. A string of length greater than 20 is broken into pieces of size at most~20
  1606. with discretionary breaks in between.
  1607. yskiphalign{quad#hfil&quad#hfil&quadhfil#hfilcr
  1608. .{!=}&|binop|: .{\I}&yescr
  1609. .{<=}&|binop|: .{\Z}&yescr
  1610. .{>=}&|binop|: .{\G}&yescr
  1611. .{==}&|binop|: .{\E}&yescr
  1612. .{&&}&|binop|: .{\W}&yescr
  1613. .{vv}&|binop|: .{\V}&yescr
  1614. .{++}&|binop|: .{\PP}&yescr
  1615. .{--}&|binop|: .{\MM}&yescr
  1616. .{->}&|binop|: .{\MG}&yescr
  1617. .{>>}&|binop|: .{\GG}&yescr
  1618. .{<<}&|binop|: .{\LL}&yescr
  1619. .{::}&|colcol|: .{\DC}&maybecr
  1620. .{.*}&|binop|: .{\PA}&yescr
  1621. .{->*}&|binop|: .{\MGA}&yescr
  1622. .{...}&|exp|: .{\,\ldots\,}&yescr
  1623. ."string."&|exp|: .{\.{}string with special characters quoted.}&maybecr
  1624. .{@@=}string.{@@>}&|exp|: .{\vb{}string with special characters
  1625.   quoted.}&maybecr
  1626. .{@@'7'}&|exp|: .{\.{@@'7'}}&maybecr
  1627. .{077} or .{\77}&|exp|: .{\T{\~77}}&maybecr
  1628. .{0x7f}&|exp|: .{\T{\^7f}}&maybecr
  1629. .{77}&|exp|: .{\T{77}}&maybecr
  1630. .{77L}&|exp|: .{\T{77\$L}}&maybecr
  1631. .{0.1E5}&|exp|: .{\T{0.1\_5}}&maybecr
  1632. .+&|unorbinop|: .+&yescr
  1633. .-&|unorbinop|: .-&yescr
  1634. .*&|raw_unorbin|: .*&yescr
  1635. ./&|binop|: ./&yescr
  1636. .<&|prelangle|: .{\langle}&yescr
  1637. .=&|binop|: .{\K}&yescr
  1638. .>&|prerangle|: .{\rangle}&yescr
  1639. ..&|binop|: ..&yescr
  1640. .{v}&|binop|: .{\OR}&yescr
  1641. .^&|binop|: .{\XOR}&yescr
  1642. .%&|binop|: .{\MOD}&yescr
  1643. .?&|question|: .{\?}&yescr
  1644. .!&|unop|: .{\R}&yescr
  1645. .~&|unop|: .{\CM}&yescr
  1646. .&&|raw_unorbin|: .{\AND}&yescr
  1647. .(&|lpar|: .(&maybecr
  1648. .[&|lpar|: .[&maybecr
  1649. .)&|raw_rpar|: .)&maybecr
  1650. .]&|raw_rpar|: .]&maybecr
  1651. .{&|lbrace|: .{&yescr
  1652. .}&|lbrace|: .}&yescr
  1653. .,&|comma|: .,&yescr
  1654. .;&|semi|: .;&maybecr
  1655. .:&|colon|: .:&maybecr
  1656. .# (within line)&|unorbinop|: .{\#}&yescr
  1657. .# (at beginning)&|lproc|:  |force| |preproc_line| .{\#}&nocr
  1658. end of .# line&|rproc|:  |force|&nocr
  1659. identifier&|exp|: .{\\{}identifier with underlines quoted.}&maybecr
  1660. .{asm}&|sizeof_like|: stars&maybecr
  1661. .{auto}&|int_like|: stars&maybecr
  1662. .{break}&|case_like|: stars&maybecr
  1663. .{case}&|case_like|: stars&maybecr
  1664. .{catch}&|catch_like|: stars&maybecr
  1665. .{char}&|raw_int|: stars&maybecr
  1666. .{class}&|struct_like|: stars&maybecr
  1667. .{clock_t}&|raw_int|: stars&maybecr
  1668. .{const}&|const_like|: stars&maybecr
  1669. .{continue}&|case_like|: stars&maybecr
  1670. .{default}&|case_like|: stars&maybecr
  1671. .{define}&|define_like|: stars&maybecr
  1672. .{defined}&|sizeof_like|: stars&maybecr
  1673. .{delete}&|sizeof_like|: stars&maybecr
  1674. .{div_t}&|raw_int|: stars&maybecr
  1675. .{do}&|do_like|: stars&maybecr
  1676. .{double}&|raw_int|: stars&maybecr
  1677. .{elif}&|if_like|: stars&maybecr
  1678. .{else}&|else_like|: stars&maybecr
  1679. .{endif}&|if_like|: stars&maybecr
  1680. .{enum}&|struct_like|: stars&maybecr
  1681. .{error}&|if_like|: stars&maybecr
  1682. .{extern}&|int_like|: stars&maybecr
  1683. .{FILE}&|raw_int|: stars&maybecr
  1684. .{float}&|raw_int|: stars&maybecr
  1685. .{for}&|for_like|: stars&maybecr
  1686. .{fpos_t}&|raw_int|: stars&maybecr
  1687. .{friend}&|int_like|: stars&maybecr
  1688. .{goto}&|case_like|: stars&maybecr
  1689. .{if}&|if_like|: stars&maybecr
  1690. .{ifdef}&|if_like|: stars&maybecr
  1691. .{ifndef}&|if_like|: stars&maybecr
  1692. .{include}&|if_like|: stars&maybecr
  1693. .{inline}&|int_like|: stars&maybecr
  1694. .{int}&|raw_int|: stars&maybecr
  1695. .{jmp_buf}&|raw_int|: stars&maybecr
  1696. .{ldiv_t}&|raw_int|: stars&maybecr
  1697. .{line}&|if_like|: stars&maybecr
  1698. .{long}&|raw_int|: stars&maybecr
  1699. .{new}&|new_like|: stars&maybecr
  1700. .{NULL}&|exp|: .{\NULL}&yescr
  1701. .{offsetof}&|sizeof_like|: stars&maybecr
  1702. .{operator}&|operator_like|: stars&maybecr
  1703. .{pragma}&|if_like|: stars&maybecr
  1704. .{private}&|public_like|: stars&maybecr
  1705. .{protected}&|public_like|: stars&maybecr
  1706. .{ptrdiff_t}&|raw_int|: stars&maybecr
  1707. .{public}&|public_like|: stars&maybecr
  1708. .{register}&|int_like|: stars&maybecr
  1709. .{return}&|case_like|: stars&maybecr
  1710. .{short}&|raw_int|: stars&maybecr
  1711. .{sig_atomic_t}&|raw_int|: stars&maybecr
  1712. .{signed}&|raw_int|: stars&maybecr
  1713. .{size_t}&|raw_int|: stars&maybecr
  1714. .{sizeof}&|sizeof_like|: stars&maybecr
  1715. .{static}&|int_like|: stars&maybecr
  1716. .{struct}&|struct_like|: stars&maybecr
  1717. .{switch}&|if_like|: stars&maybecr
  1718. .{template}&|int_like|: stars&maybecr
  1719. .{TeX}&|exp|: .{\TeX}&yescr
  1720. .{this}&|exp|: .{\this}&yescr
  1721. .{throw}&|case_like|: stars&maybecr
  1722. .{time_t}&|raw_int|: stars&maybecr
  1723. .{try}&|else_like|: stars&maybecr
  1724. .{typedef}&|typedef_like|: stars&maybecr
  1725. .{undef}&|if_like|: stars&maybecr
  1726. .{union}&|struct_like|: stars&maybecr
  1727. .{unsigned}&|raw_int|: stars&maybecr
  1728. .{va_dcl}&|decl|: stars&maybecr
  1729. .{va_list}&|raw_int|: stars&maybecr
  1730. .{virtual}&|int_like|: stars&maybecr
  1731. .{void}&|raw_int|: stars&maybecr
  1732. .{volatile}&|const_like|: stars&maybecr
  1733. .{wchar_t}&|raw_int|: stars&maybecr
  1734. .{while}&|if_like|: stars&maybecr
  1735. .{@@,}&|insert|: .{\,}&maybecr
  1736. .{@@v}&|insert|:  |opt| .0&maybecr
  1737. .{@@/}&|insert|:  |force|&nocr
  1738. .{@@#}&|insert|:  |big_force|&nocr
  1739. .{@@+}&|insert|:  |big_cancel| .{{}} |break_space|
  1740.   .{{}} |big_cancel|&nocr
  1741. .{@@;}&|semi|: &maybecr
  1742. .{@@[@q]@>}&|begin_arg|: &maybecr
  1743. .{@q[@>@@]}&|end_arg|: &maybecr
  1744. .{@@&}&|insert|: .{\J}&maybecr
  1745. .{@@h}&|insert|: |force| .{\ATH} |force|&nocr
  1746. .{@@<}thinspace section namethinspace.{@@>}&|section_scrap|:
  1747.  .{\X}$n$.:translated section name.{\X}&maybecr
  1748. .{@@(@q)@>}thinspace section namethinspace.{@@>}&|section_scrap|:
  1749.  .{\X}$n$.{:\.{}section name with special characters
  1750.       quoted.{ }\X}&maybecr
  1751. .{/*}comment.{*/}&|insert|: |cancel|
  1752.       .{\C{}translated comment.} |force|&nocr
  1753. .{//}comment&|insert|: |cancel|
  1754.       .{\SHC{}translated comment.} |force|&nocr
  1755. }
  1756. The construction .{@@t}thinspace stuff/thinspace.{@@>} contributes
  1757. .{\hbox{}thinspace  stuff/thinspace.} to the following scrap.
  1758. @i prod.w
  1759. @* Implementing the productions.
  1760. More specifically, a scrap is a structure consisting of a category
  1761. |cat| and a |text_pointer| |trans|, which points to the translation in
  1762. |tok_start|.  When CEE/ text is to be processed with the grammar above,
  1763. we form an array |scrap_info| containing the initial scraps.
  1764. Our production rules have the nice property that the right-hand side is never
  1765. longer than the left-hand side. Therefore it is convenient to use sequential
  1766. allocation for the current sequence of scraps. Five pointers are used to
  1767. manage the parsing:
  1768. yskiphang |pp| is a pointer into |scrap_info|.  We will try to match
  1769. the category codes |pp->cat,@,@,(pp+1)->cat|$,,,ldots,$
  1770. to the left-hand sides of productions.
  1771. yskiphang |scrap_base|, |lo_ptr|, |hi_ptr|, and |scrap_ptr| are such that
  1772. the current sequence of scraps appears in positions |scrap_base| through
  1773. |lo_ptr| and |hi_ptr| through |scrap_ptr|, inclusive, in the |cat| and
  1774. |trans| arrays. Scraps located between |scrap_base| and |lo_ptr| have
  1775. been examined, while those in positions |>=hi_ptr| have not yet been
  1776. looked at by the parsing process.
  1777. yskipnoindent Initially |scrap_ptr| is set to the position of the final
  1778. scrap to be parsed, and it doesn't change its value. The parsing process
  1779. makes sure that |lo_ptr>=pp+3|, since productions have as many as four terms,
  1780. by moving scraps from |hi_ptr| to |lo_ptr|. If there are
  1781. fewer than |pp+3| scraps left, the positions up to |pp+3| are filled with
  1782. blanks that will not match in any productions. Parsing stops when
  1783. |pp==lo_ptr+1| and |hi_ptr==scrap_ptr+1|.
  1784. Since the |scrap| structure will later be used for other purposes, we
  1785. declare its second element as unions.
  1786. @<Type...@>=
  1787. typedef struct {
  1788.   eight_bits cat;
  1789.   eight_bits mathness;
  1790.   union {
  1791.     text_pointer Trans;
  1792.     @<Rest of |trans_plus| union@>@;
  1793.   } trans_plus;
  1794. } scrap;
  1795. typedef scrap *scrap_pointer;
  1796. @ @d trans trans_plus.Trans /* translation texts of scraps */
  1797. @<Global...@>=
  1798. scrap scrap_info[max_scraps]; /* memory array for scraps */
  1799. scrap_pointer scrap_info_end=scrap_info+max_scraps -1; /* end of |scrap_info| */
  1800. scrap_pointer pp; /* current position for reducing productions */
  1801. scrap_pointer scrap_base; /* beginning of the current scrap sequence */
  1802. scrap_pointer scrap_ptr; /* ending of the current scrap sequence */
  1803. scrap_pointer lo_ptr; /* last scrap that has been examined */
  1804. scrap_pointer hi_ptr; /* first scrap that has not been examined */
  1805. scrap_pointer max_scr_ptr; /* largest value assumed by |scrap_ptr| */
  1806. @ @<Set init...@>=
  1807. scrap_base=scrap_info+1;
  1808. max_scr_ptr=scrap_ptr=scrap_info;
  1809. @ Token lists in |@!tok_mem| are composed of the following kinds of
  1810. items for TEX/ output.
  1811. yskipitem{$bullet$}Character codes and special codes like |force| and
  1812. |math_rel| represent themselves;
  1813. item{$bullet$}|id_flag+p| represents .{\\{{rm identifier $p$}}};
  1814. item{$bullet$}|res_flag+p| represents .{\&{{rm identifier $p$}}};
  1815. item{$bullet$}|section_flag+p| represents section name |p|;
  1816. item{$bullet$}|tok_flag+p| represents token list number |p|;
  1817. item{$bullet$}|inner_tok_flag+p| represents token list number |p|, to be
  1818. translated without line-break controls.
  1819. @d id_flag 10240 /* signifies an identifier */
  1820. @d res_flag 2*id_flag /* signifies a reserved word */
  1821. @d section_flag 3*id_flag /* signifies a section name */
  1822. @d tok_flag 4*id_flag /* signifies a token list */
  1823. @d inner_tok_flag 5*id_flag /* signifies a token list in `pb' */
  1824. @c
  1825. void
  1826. print_text(p) /* prints a token list for debugging; not used in |main| */
  1827. text_pointer p;
  1828. {
  1829.   token_pointer j; /* index into |tok_mem| */
  1830.   sixteen_bits r; /* remainder of token after the flag has been stripped off */
  1831.   if (p>=text_ptr) printf("BAD");
  1832.   else for (j=*p; j<*(p+1); j++) {
  1833.     r=*j%id_flag;
  1834.     switch (*j/id_flag) {
  1835.       case 1: printf("\\{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}");
  1836.         break; /* |id_flag| */
  1837.       case 2: printf("\&{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}");
  1838.         break; /* |res_flag| */
  1839.       case 3: printf("<"); print_section_name((name_dir+r)); printf(">");
  1840.         break; /* |section_flag| */
  1841.       case 4: printf("[[%d]]",r); break; /* |tok_flag| */
  1842.       case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */
  1843.       default: @<Print token |r| in symbolic form@>;
  1844.     }
  1845.   }
  1846.   fflush(stdout);
  1847. }
  1848. @ @<Print token |r|...@>=
  1849. switch (r) {
  1850.   case math_rel: printf("\mathrel{"@q}@>); break;
  1851.   case big_cancel: printf("[ccancel]"); break;
  1852.   case cancel: printf("[cancel]"); break;
  1853.   case indent: printf("[indent]"); break;
  1854.   case outdent: printf("[outdent]"); break;
  1855.   case backup: printf("[backup]"); break;
  1856.   case opt: printf("[opt]"); break;
  1857.   case break_space: printf("[break]"); break;
  1858.   case force: printf("[force]"); break;
  1859.   case big_force: printf("[fforce]"); break;
  1860.   case preproc_line: printf("[preproc]"); break;
  1861.   case quoted_char: j++; printf("[%o]",(unsigned)*j); break;
  1862.   case end_translation: printf("[quit]"); break;
  1863.   case inserted: printf("[inserted]"); break;
  1864.   default: putxchar(r);
  1865. }
  1866. @ The production rules listed above are embedded directly into .{CWEAVE},
  1867. since it is easier to do this than to write an interpretive system
  1868. that would handle production systems in general. Several macros are defined
  1869. here so that the program for each production is fairly short.
  1870. All of our productions conform to the general notion that some |k|
  1871. consecutive scraps starting at some position |j| are to be replaced by a
  1872. single scrap of some category |c| whose translation is composed from the
  1873. translations of the disappearing scraps. After this production has been
  1874. applied, the production pointer |pp| should change by an amount |d|. Such
  1875. a production can be represented by the quadruple |(j,k,c,d)|. For example,
  1876. the production `|exp@,comma@,exp| $RA$ |exp|' would be represented by
  1877. `|(pp,3,exp,-2)|'; in this case the pointer |pp| should decrease by 2
  1878. after the production has been applied, because some productions with
  1879. |exp| in their second or third positions might now match,
  1880. but no productions have
  1881. |exp| in the fourth position of their left-hand sides. Note that
  1882. the value of |d| is determined by the whole collection of productions, not
  1883. by an individual one.
  1884. The determination of |d| has been
  1885. done by hand in each case, based on the full set of productions but not on
  1886. the grammar of CEE/ or on the rules for constructing the initial
  1887. scraps.
  1888. We also attach a serial number to each production, so that additional
  1889. information is available when debugging. For example, the program below
  1890. contains the statement `|reduce(pp,3,exp,-2,4)|' when it implements
  1891. the production just mentioned.
  1892. Before calling |reduce|, the program should have appended the tokens of
  1893. the new translation to the |tok_mem| array. We commonly want to append
  1894. copies of several existing translations, and macros are defined to
  1895. simplify these common cases. For example, \{app2}|(pp)| will append the
  1896. translations of two consecutive scraps, |pp->trans| and |(pp+1)->trans|, to
  1897. the current token list. If the entire new translation is formed in this
  1898. way, we write `|squash(j,k,c,d,n)|' instead of `|reduce(j,k,c,d,n)|'. For
  1899. example, `|squash(pp,3,exp,-2,3)|' is an abbreviation for `\{app3}|(pp);
  1900. reduce(pp,3,exp,-2,3)|'.
  1901. A couple more words of explanation:
  1902. Both |big_app| and |app| append a token (while |big_app1| to |big_app4|
  1903. append the specified number of scrap translations) to the current token list.
  1904. The difference between |big_app| and |app| is simply that |big_app|
  1905. checks whether there can be a conflict between math and non-math
  1906. tokens, and intercalates a `.{$}' token if necessary.  When in
  1907. doubt what to use, use |big_app|.
  1908. The |mathness| is an attribute of scraps that says whether they are
  1909. to be printed in a math mode context or not.  It is separate from the
  1910. ``part of speech'' (the |cat|) because to make each |cat| have
  1911. a fixed |mathness| (as in the original .{WEAVE}) would multiply the
  1912. number of necessary production rules.
  1913. The low two bits (i.e. |mathness % 4|) control the left boundary.
  1914. (We need two bits because we allow cases |yes_math|, |no_math| and
  1915. |maybe_math|, which can go either way.)
  1916. The next two bits (i.e. |mathness / 4|) control the right boundary.
  1917. If we combine two scraps and the right boundary of the first has
  1918. a different mathness from the left boundary of the second, we
  1919. insert a .{$} in between.  Similarly, if at printing time some
  1920. irreducible scrap has a |yes_math| boundary the scrap gets preceded
  1921. or followed by a .{$}. The left boundary is |maybe_math| if and
  1922. only if the right boundary is.
  1923. The code below is an exact translation of the production rules into
  1924. CEE/, using such macros, and the reader should have no difficulty
  1925. understanding the format by comparing the code with the symbolic
  1926. productions as they were listed earlier.
  1927. @d no_math 2 /* should be in horizontal mode */
  1928. @d yes_math 1 /* should be in math mode */
  1929. @d maybe_math 0 /* works in either horizontal or math mode */
  1930. @d big_app2(a) big_app1(a);big_app1(a+1)
  1931. @d big_app3(a) big_app2(a);big_app1(a+2)
  1932. @d big_app4(a) big_app3(a);big_app1(a+3)
  1933. @d app(a) *(tok_ptr++)=a
  1934. @d app1(a) *(tok_ptr++)=tok_flag+(int)((a)->trans-tok_start)
  1935. @<Global...@>=
  1936. int cur_mathness, init_mathness;
  1937. @ @c
  1938. void
  1939. app_str(s)
  1940. char *s;
  1941. {
  1942.   while (*s) app_tok(*(s++));
  1943. }
  1944. void
  1945. big_app(a)
  1946. token a;
  1947. {
  1948.         if (a==' ' || (a>=big_cancel && a<=big_force)) /* non-math token */ {
  1949.                 if (cur_mathness==maybe_math) init_mathness=no_math;
  1950.                 else if (cur_mathness==yes_math) app_str("{}$");
  1951.                 cur_mathness=no_math;
  1952.         }
  1953.         else {
  1954.                 if (cur_mathness==maybe_math) init_mathness=yes_math;
  1955.                 else if (cur_mathness==no_math) app_str("${}");
  1956.                 cur_mathness=yes_math;
  1957.         }
  1958.         app(a);
  1959. }
  1960. void
  1961. big_app1(a)
  1962. scrap_pointer a;
  1963. {
  1964.   switch (a->mathness % 4) { /* left boundary */
  1965.   case (no_math):
  1966.     if (cur_mathness==maybe_math) init_mathness=no_math;
  1967.     else if (cur_mathness==yes_math) app_str("{}$");
  1968.     cur_mathness=a->mathness / 4; /* right boundary */
  1969.     break;
  1970.   case (yes_math):
  1971.     if (cur_mathness==maybe_math) init_mathness=yes_math;
  1972.     else if (cur_mathness==no_math) app_str("${}");
  1973.     cur_mathness=a->mathness / 4; /* right boundary */
  1974.     break;
  1975.   case (maybe_math): /* no changes */ break;
  1976.   }
  1977.   app(tok_flag+(int)((a)->trans-tok_start));
  1978. }
  1979. @ Let us consider the big switch for productions now, before looking
  1980. at its context. We want to design the program so that this switch
  1981. works, so we might as well not keep ourselves in suspense about exactly what
  1982. code needs to be provided with a proper environment.
  1983. @d cat1 (pp+1)->cat
  1984. @d cat2 (pp+2)->cat
  1985. @d cat3 (pp+3)->cat
  1986. @d lhs_not_simple (pp->cat!=semi && pp->cat!=raw_int && pp->cat!=raw_unorbin
  1987.             && pp->cat!=raw_rpar && pp->cat!=const_like)
  1988. @<Match a production at |pp|, or increase |pp| if there is no match@>= {
  1989.   if (cat1==end_arg && lhs_not_simple)
  1990.     if (pp->cat==begin_arg) squash(pp,2,exp,-2,110);
  1991.     else squash(pp,2,end_arg,-1,111);
  1992.   else if (cat1==insert) squash(pp,2,pp->cat,-2,0);
  1993.   else if (cat2==insert) squash(pp+1,2,(pp+1)->cat,-1,0);
  1994.   else if (cat3==insert) squash(pp+2,2,(pp+2)->cat,0,0);
  1995.   else
  1996.   switch (pp->cat) {
  1997.     case exp: @<Cases for |exp|@>; @+break;
  1998.     case lpar: @<Cases for |lpar|@>; @+break;