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

通讯编程

开发平台:

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. mathchardefRA="3221 % right arrow
  19. mathchardefBA="3224 % double arrow
  20. deftitle{CTANGLE (Version 3.4)}
  21. deftopofcontents{nullvfill
  22.   centerline{titlefont The {ttitlefont CTANGLE} processor}
  23.   vskip 15pt
  24.   centerline{(Version 3.4)}
  25.   vfill}
  26. defbotofcontents{vfill
  27. noindent
  28. Copyright copyright 1987, 1990, 1993 Silvio Levy and Donald E. Knuth
  29. bigskipnoindent
  30. Permission is granted to make and distribute verbatim copies of this
  31. document provided that the copyright notice and this permission notice
  32. are preserved on all copies.
  33. smallskipnoindent
  34. Permission is granted to copy and distribute modified versions of this
  35. document under the conditions for verbatim copying, provided that the
  36. entire resulting derived work is given a different name and distributed
  37. under the terms of a permission notice identical to this one.
  38. }
  39. pageno=contentspagenumber advancepageno by 1
  40. letmaybe=iftrue
  41. @** Introduction.
  42. This is the .{CTANGLE} program by Silvio Levy and Donald E. Knuth,
  43. based on .{TANGLE} by Knuth.
  44. We are thankful to
  45. Nelson Beebe, Hans-Hermann Bode (to whom the CPLUSPLUS/ adaptation is due),
  46. Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter,
  47. Joachim Schrod, Lee Wittenberg, and others who have contributed improvements.
  48. The ``banner line'' defined here should be changed whenever .{CTANGLE}
  49. is modified.
  50. @d banner "This is CTANGLE (Version 3.4)n"
  51. @c
  52. @<Include files@>@/
  53. @h
  54. @<Common code for .{CWEAVE} and .{CTANGLE}@>@/
  55. @<Typedef declarations@>@/
  56. @<Global variables@>@/
  57. @<Predeclaration of procedures@>@/
  58. @ We predeclare several standard system functions here instead of including
  59. their system header files, because the names of the header files are not as
  60. standard as the names of the functions. (For example, some CEE/ environments
  61. have .{<string.h>} where others have .{<strings.h>}.)
  62. @<Predecl...@>=
  63. extern int strlen(); /* length of string */
  64. extern int strcmp(); /* compare strings lexicographically */
  65. extern char* strcpy(); /* copy one string to another */
  66. extern int strncmp(); /* compare up to $n$ string characters */
  67. extern char* strncpy(); /* copy up to $n$ string characters */
  68. @ .{CTANGLE} has a fairly straightforward outline.  It operates in
  69. two phases: first it reads the source file, saving the CEE/ code in
  70. compressed form; then outputs the code, after shuffling it around.
  71. Please read the documentation for .{common}, the set of routines common
  72. to .{CTANGLE} and .{CWEAVE}, before proceeding further.
  73. @c
  74. int main (ac, av)
  75. int ac;
  76. char **av;
  77. {
  78.   argc=ac; argv=av;
  79.   program=ctangle;
  80.   @<Set initial values@>;
  81.   common_init();
  82.   if (show_banner) printf(banner); /* print a ``banner line'' */
  83.   phase_one(); /* read all the user's text and compress it into |tok_mem| */
  84.   phase_two(); /* output the contents of the compressed tables */
  85.   return wrap_up(); /* and exit gracefully */
  86. }
  87. @ The following parameters were sufficient in the original .{TANGLE} to
  88. handle TEX/,
  89. so they should be sufficient for most applications of .{CTANGLE}.
  90. If you change |max_bytes|, |max_names| or |hash_size| you should also
  91. change them in the file |"common.w"|.
  92. @d max_bytes 90000 /* the number of bytes in identifiers,
  93.   index entries, and section names; used in |"common.w"| */
  94. @d max_toks 270000 /* number of bytes in compressed CEE/ code */
  95. @d max_names 4000 /* number of identifiers, strings, section names;
  96.   must be less than 10240; used in |"common.w"| */
  97. @d max_texts 2500 /* number of replacement texts, must be less than 10240 */
  98. @d hash_size 353 /* should be prime; used in |"common.w"| */
  99. @d longest_name 1000 /* section names shouldn't be longer than this */
  100. @d stack_size 50 /* number of simultaneous levels of macro expansion */
  101. @d buf_size 100 /* for .{CWEAVE} and .{CTANGLE} */
  102. @ The next few sections contain stuff from the file |"common.w"| that must
  103. be included in both |"ctangle.w"| and |"cweave.w"|. It appears in
  104. file |"common.h"|, which needs to be updated when |"common.w"| changes.
  105. @i common.h
  106. @* Data structures exclusive to {tt CTANGLE}.
  107. We've already seen that the |byte_mem| array holds the names of identifiers,
  108. strings, and sections;
  109. the |tok_mem| array holds the replacement texts
  110. for sections. Allocation is sequential, since things are deleted only
  111. during Phase II, and only in a last-in-first-out manner.
  112. A &{text} variable is a structure containing a pointer into
  113. |tok_mem|, which tells where the corresponding text starts, and an
  114. integer |text_link|, which, as we shall see later, is used to connect
  115. pieces of text that have the same name.  All the &{text}s are stored in
  116. the array |text_info|, and we use a |text_pointer| variable to refer
  117. to them.
  118. The first position of |tok_mem| that is unoccupied by
  119. replacement text is called |tok_ptr|, and the first unused location of
  120. |text_info| is called |text_ptr|.  Thus we usually have the identity
  121. |text_ptr->tok_start==tok_ptr|.
  122. If your machine does not support |unsigned char| you should change
  123. the definition of &{eight_bits} to |unsigned short|.
  124. @^system dependencies@>
  125. @<Typed...@>=
  126. typedef struct {
  127.   eight_bits *tok_start; /* pointer into |tok_mem| */
  128.   sixteen_bits text_link; /* relates replacement texts */
  129. } text;
  130. typedef text *text_pointer;
  131. @ @<Glob...@>=
  132. text text_info[max_texts];
  133. text_pointer text_info_end=text_info+max_texts-1;
  134. text_pointer text_ptr; /* first unused position in |text_info| */
  135. eight_bits tok_mem[max_toks];
  136. eight_bits *tok_mem_end=tok_mem+max_toks-1;
  137. eight_bits *tok_ptr; /* first unused position in |tok_mem| */
  138. @ @<Set init...@>=
  139. text_info->tok_start=tok_ptr=tok_mem;
  140. text_ptr=text_info+1; text_ptr->tok_start=tok_mem;
  141.   /* this makes replacement text 0 of length zero */
  142. @ If |p| is a pointer to a section name, |p->equiv| is a pointer to its
  143. replacement text, an element of the array |text_info|.
  144. @d equiv equiv_or_xref /* info corresponding to names */
  145. @ @<Set init...@>=
  146. name_dir->equiv=(char *)text_info; /* the undefined section has no replacement text */
  147. @ Here's the procedure that decides whether a name of length |l|
  148. starting at position |first| equals the identifier pointed to by |p|:
  149. @c
  150. int names_match(p,first,l)
  151. name_pointer p; /* points to the proposed match */
  152. char *first; /* position of first character of string */
  153. int l; /* length of identifier */
  154. {
  155.   if (length(p)!=l) return 0;
  156.   return !strncmp(first,p->byte_start,l);
  157. }
  158. @ The common lookup routine refers to separate routines |init_node| and
  159. |init_p| when the data structure grows. Actually |init_p| is called only by
  160. .{CWEAVE}, but we need to declare a dummy version so that
  161. the loader won't complain of its absence.
  162. @c
  163. void
  164. init_node(node)
  165. name_pointer node;
  166. {
  167.     node->equiv=(char *)text_info;
  168. }
  169. void
  170. init_p() {}
  171. @* Tokens.
  172. Replacement texts, which represent CEE/ code in a compressed format,
  173. appear in |tok_mem| as mentioned above. The codes in
  174. these texts are called `tokens'; some tokens occupy two consecutive
  175. eight-bit byte positions, and the others take just one byte.
  176. If $p$ points to a replacement text, |p->tok_start| is the |tok_mem| position
  177. of the first eight-bit code of that text. If |p->text_link==0|,
  178. this is the replacement text for a macro, otherwise it is the replacement
  179. text for a section. In the latter case |p->text_link| is either equal to
  180. |section_flag|, which means that there is no further text for this section, or
  181. |p->text_link| points to a continuation of this replacement text; such
  182. links are created when several sections have CEE/ texts with the same
  183. name, and they also tie together all the CEE/ texts of unnamed sections.
  184. The replacement text pointer for the first unnamed section appears in
  185. |text_info->text_link|, and the most recent such pointer is |last_unnamed|.
  186. @d section_flag max_texts /* final |text_link| in section replacement texts */
  187. @<Glob...@>=
  188. text_pointer last_unnamed; /* most recent replacement text of unnamed section */
  189. @ @<Set init...@>= last_unnamed=text_info; text_info->text_link=0;
  190. @ If the first byte of a token is less than |0200|, the token occupies a
  191. single byte. Otherwise we make a sixteen-bit token by combining two consecutive
  192. bytes |a| and |b|. If |0200<=a<0250|, then |(a-0200)@t${}times2^8$@>+b|
  193. points to an identifier; if |0250<=a<0320|, then
  194. |(a-0250)@t${}times2^8$@>+b| points to a section name
  195. (or, if it has the special value |output_defs_flag|,
  196. to the area where the preprocessor definitions are stored); and if
  197. |0320<=a<0400|, then |(a-0320)@t${}times2^8$@>+b| is the number of the section
  198. in which the current replacement text appears.
  199. Codes less than |0200| are 7-bit |char| codes that represent themselves.
  200. Some of the 7-bit codes will not be present, however, so we can
  201. use them for special purposes. The following symbolic names are used:
  202. yskip hang |join| denotes the concatenation of adjacent items with no
  203. space or line breaks allowed between them (the .{@@&} operation of .{CWEB}).
  204. hang |string| denotes the beginning or end of a string, verbatim
  205. construction or numerical constant.
  206. @^ASCII code dependencies@>
  207. @d string 02 /* takes the place of extended ASCII .{char2} */
  208. @d join 0177 /* takes the place of ASCII delete */
  209. @d output_defs_flag (2*024000-1)
  210. @ The following procedure is used to enter a two-byte value into
  211. |tok_mem| when a replacement text is being generated.
  212. @c
  213. void
  214. store_two_bytes(x)
  215. sixteen_bits x;
  216. {
  217.   if (tok_ptr+2>tok_mem_end) overflow("token");
  218.   *tok_ptr++=x>>8; /* store high byte */
  219.   *tok_ptr++=x&0377; /* store low byte */
  220. }
  221. @** Stacks for output.  The output process uses a stack to keep track
  222. of what is going on at different ``levels'' as the sections are being
  223. written out.  Entries on this stack have five parts:
  224. yskiphang |end_field| is the |tok_mem| location where the replacement
  225. text of a particular level will end;
  226. hang |byte_field| is the |tok_mem| location from which the next token
  227. on a particular level will be read;
  228. hang |name_field| points to the name corresponding to a particular level;
  229. hang |repl_field| points to the replacement text currently being read
  230. at a particular level;
  231. hang |section_field| is the section number, or zero if this is a macro.
  232. yskipnoindent The current values of these five quantities are referred to
  233. quite frequently, so they are stored in a separate place instead of in
  234. the |stack| array. We call the current values |cur_end|, |cur_byte|,
  235. |cur_name|, |cur_repl|, and |cur_section|.
  236. The global variable |stack_ptr| tells how many levels of output are
  237. currently in progress. The end of all output occurs when the stack is
  238. empty, i.e., when |stack_ptr==stack|.
  239. @<Typed...@>=
  240. typedef struct {
  241.   eight_bits *end_field; /* ending location of replacement text */
  242.   eight_bits *byte_field; /* present location within replacement text */
  243.   name_pointer name_field; /* |byte_start| index for text being output */
  244.   text_pointer repl_field; /* |tok_start| index for text being output */
  245.   sixteen_bits section_field; /* section number or zero if not a section */
  246. } output_state;
  247. typedef output_state *stack_pointer;
  248. @ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */
  249. @d cur_byte cur_state.byte_field /* location of next output byte in |tok_mem|*/
  250. @d cur_name cur_state.name_field /* pointer to current name being expanded */
  251. @d cur_repl cur_state.repl_field /* pointer to current replacement text */
  252. @d cur_section cur_state.section_field /* current section number being expanded */
  253. @<Global...@>=
  254. output_state cur_state; /* |cur_end|, |cur_byte|, |cur_name|, |cur_repl|
  255.   and |cur_section| */
  256. output_state stack[stack_size+1]; /* info for non-current levels */
  257. stack_pointer stack_ptr; /* first unused location in the output state stack */
  258. stack_pointer stack_end=stack+stack_size; /* end of |stack| */
  259. @ To get the output process started, we will perform the following
  260. initialization steps. We may assume that |text_info->text_link| is nonzero,
  261. since it points to the CEE/ text in the first unnamed section that generates
  262. code; if there are no such sections, there is nothing to output, and an
  263. error message will have been generated before we do any of the initialization.
  264. @<Initialize the output stacks@>=
  265. stack_ptr=stack+1; cur_name=name_dir; cur_repl=text_info->text_link+text_info;
  266. cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start; cur_section=0;
  267. @ When the replacement text for name |p| is to be inserted into the output,
  268. the following subroutine is called to save the old level of output and get
  269. the new one going.
  270. We assume that the CEE/ compiler can copy structures.
  271. @^system dependencies@>
  272. @c
  273. void
  274. push_level(p) /* suspends the current level */
  275. name_pointer p;
  276. {
  277.   if (stack_ptr==stack_end) overflow("stack");
  278.   *stack_ptr=cur_state;
  279.   stack_ptr++;
  280.   if (p!=NULL) { /* |p==NULL| means we are in |output_defs| */
  281.     cur_name=p; cur_repl=(text_pointer)p->equiv;
  282.     cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start;
  283.     cur_section=0;
  284.   }
  285. }
  286. @ When we come to the end of a replacement text, the |pop_level| subroutine
  287. does the right thing: It either moves to the continuation of this replacement
  288. text or returns the state to the most recently stacked level.
  289. @c
  290. void
  291. pop_level(flag) /* do this when |cur_byte| reaches |cur_end| */
  292. int flag; /* |flag==0| means we are in |output_defs| */
  293. {
  294.   if (flag && cur_repl->text_link<section_flag) { /* link to a continuation */
  295.     cur_repl=cur_repl->text_link+text_info; /* stay on the same level */
  296.     cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start;
  297.     return;
  298.   }
  299.   stack_ptr--; /* go down to the previous level */
  300.   if (stack_ptr>stack) cur_state=*stack_ptr;
  301. }
  302. @ The heart of the output procedure is the function |get_output|,
  303. which produces the next token of output and sends it on to the lower-level
  304. function |out_char|. The main purpose of |get_output| is to handle the
  305. necessary stacking and unstacking. It sends the value |section_number|
  306. if the next output begins or ends the replacement text of some section,
  307. in which case |cur_val| is that section's number (if beginning) or the
  308. negative of that value (if ending). (A section number of 0 indicates
  309. not the beginning or ending of a section, but a &{#line} command.)
  310. And it sends the value |identifier|
  311. if the next output is an identifier, in which case
  312. |cur_val| points to that identifier name.
  313. @d section_number 0201 /* code returned by |get_output| for section numbers */
  314. @d identifier 0202 /* code returned by |get_output| for identifiers */
  315. @<Global...@>=
  316. int cur_val; /* additional information corresponding to output token */
  317. @ If |get_output| finds that no more output remains, it returns with
  318. |stack_ptr==stack|.
  319. @^high-bit character handling@>
  320. @c
  321. void
  322. get_output() /* sends next token to |out_char| */
  323. {
  324.   sixteen_bits a; /* value of current byte */
  325.   restart: if (stack_ptr==stack) return;
  326.   if (cur_byte==cur_end) {
  327.     cur_val=-((int)cur_section); /* cast needed because of sign extension */
  328.     pop_level(1);
  329.     if (cur_val==0) goto restart;
  330.     out_char(section_number); return;
  331.   }
  332.   a=*cur_byte++;
  333.   if (out_state==verbatim && a!=string && a!=constant && a!='n')
  334.     C_putc(a); /* a high-bit character can occur in a string */
  335.   else if (a<0200) out_char(a); /* one-byte token */
  336.   else {
  337.     a=(a-0200)*0400+*cur_byte++;
  338.     switch (a/024000) { /* |024000==(0250-0200)*0400| */
  339.       case 0: cur_val=a; out_char(identifier); break;
  340.       case 1: if (a==output_defs_flag) output_defs();
  341.         else @<Expand section |a-024000|, |goto restart|@>;
  342.         break;
  343.       default: cur_val=a-050000; if (cur_val>0) cur_section=cur_val;
  344.         out_char(section_number);
  345.     }
  346.   }
  347. }
  348. @ The user may have forgotten to give any CEE/ text for a section name,
  349. or the CEE/ text may have been associated with a different name by mistake.
  350. @<Expand section |a-...@>=
  351. {
  352.   a-=024000;
  353.   if ((a+name_dir)->equiv!=(char *)text_info) push_level(a+name_dir);
  354.   else if (a!=0) {
  355.     printf("n! Not present: <");
  356.     print_section_name(a+name_dir); err_print(">");
  357. @.Not present: <section name>@>
  358.   }
  359.   goto restart;
  360. }
  361. @* Producing the output.
  362. The |get_output| routine above handles most of the complexity of output
  363. generation, but there are two further considerations that have a nontrivial
  364. effect on .{CTANGLE}'s algorithms.
  365. @ First,
  366. we want to make sure that the output has spaces and line breaks in
  367. the right places (e.g., not in the middle of a string or a constant or an
  368. identifier, not at a `.{@@&}' position
  369. where quantities are being joined together, and certainly after an .=
  370. because the CEE/ compiler thinks .{=-} is ambiguous).
  371. The output process can be in one of following states:
  372. yskiphang |num_or_id| means that the last item in the buffer is a number or
  373. identifier, hence a blank space or line break must be inserted if the next
  374. item is also a number or identifier.
  375. yskiphang |unbreakable| means that the last item in the buffer was followed
  376. by the .{@@&} operation that inhibits spaces between it and the next item.
  377. yskiphang |verbatim| means we're copying only character tokens, and
  378. that they are to be output exactly as stored.  This is the case during
  379. strings, verbatim constructions and numerical constants.
  380. yskiphang |post_slash| means we've just output a slash.
  381. yskiphang |normal| means none of the above.
  382. yskipnoindent Furthermore, if the variable |protect| is positive, newlines
  383. are preceded by a `.\'.
  384. @d normal 0 /* non-unusual state */
  385. @d num_or_id 1 /* state associated with numbers and identifiers */
  386. @d post_slash 2 /* state following a ./ */
  387. @d unbreakable 3 /* state associated with .{@@&} */
  388. @d verbatim 4 /* state in the middle of a string */
  389. @<Global...@>=
  390. eight_bits out_state; /* current status of partial output */
  391. boolean protect; /* should newline characters be quoted? */
  392. @ Here is a routine that is invoked when we want to output the current line.
  393. During the output process, |cur_line| equals the number of the next line
  394. to be output.
  395. @c
  396. void
  397. flush_buffer() /* writes one line to output file */
  398. {
  399.   C_putc('n');
  400.   if (cur_line % 100 == 0 && show_progress) {
  401.     printf(".");
  402.     if (cur_line % 500 == 0) printf("%d",cur_line);
  403.     update_terminal; /* progress report */
  404.   }
  405.   cur_line++;
  406. }
  407. @ Second, we have modified the original .{TANGLE} so that it will write output
  408. on multiple files.
  409. If a section name is introduced in at least one place by .{@@(}
  410. instead of .{@@<}, we treat it as the name of a file.
  411. All these special sections are saved on a stack, |output_files|.
  412. We write them out after we've done the unnamed section.
  413. @d max_files 256
  414. @<Glob...@>=
  415. name_pointer output_files[max_files];
  416. name_pointer *cur_out_file, *end_output_files, *an_output_file;
  417. char cur_section_name_char; /* is it |'<'| or |'('| */
  418. char output_file_name[longest_name]; /* name of the file */
  419. @ We make |end_output_files| point just beyond the end of
  420. |output_files|. The stack pointer
  421. |cur_out_file| starts out there. Every time we see a new file, we
  422. decrement |cur_out_file| and then write it in.
  423. @<Set initial...@>=
  424. cur_out_file=end_output_files=output_files+max_files;
  425. @ @<If it's not there, add |cur_section_name| to the output file stack, or
  426. complain we're out of room@>=
  427. {
  428.   for (an_output_file=cur_out_file;
  429.         an_output_file<end_output_files; an_output_file++)
  430.             if (*an_output_file==cur_section_name) break;
  431.   if (an_output_file==end_output_files) {
  432.     if (cur_out_file>output_files)
  433.         *--cur_out_file=cur_section_name;
  434.     else {
  435.       overflow("output files");
  436.     }
  437.   }
  438. }
  439. @* The big output switch.  Here then is the routine that does the
  440. output.
  441. @<Predecl...@>=
  442. void phase_two();
  443. @ @c
  444. void
  445. phase_two () {
  446.   web_file_open=0;
  447.   cur_line=1;
  448.   @<Initialize the output stacks@>;
  449.   @<Output macro definitions if appropriate@>;
  450.   if (text_info->text_link==0 && cur_out_file==end_output_files) {
  451.     printf("n! No program text was specified."); mark_harmless;
  452. @.No program text...@>
  453.   }
  454.   else {
  455.     if(cur_out_file==end_output_files) {
  456.       if(show_progress)
  457.         printf("nWriting the output file (%s):",C_file_name);
  458.     }
  459.     else {
  460.       if (show_progress) {
  461.         printf("nWriting the output files:");
  462. @.Writing the output...@>
  463.         printf(" (%s)",C_file_name);
  464.         update_terminal;
  465.       }
  466.       if (text_info->text_link==0) goto writeloop;
  467.     }
  468.     while (stack_ptr>stack) get_output();
  469.     flush_buffer();
  470. writeloop:   @<Write all the named output files@>;
  471.     if(show_happiness) printf("nDone.");
  472.   }
  473. }
  474. @ To write the named output files, we proceed as for the unnamed
  475. section.
  476. The only subtlety is that we have to open each one.
  477. @<Write all the named output files@>=
  478. for (an_output_file=end_output_files; an_output_file>cur_out_file;) {
  479.     an_output_file--;
  480.     sprint_section_name(output_file_name,*an_output_file);
  481.     fclose(C_file);
  482.     C_file=fopen(output_file_name,"w");
  483.     if (C_file ==0) fatal("! Cannot open output file:",output_file_name);
  484. @.Cannot open output file@>
  485.     printf("n(%s)",output_file_name); update_terminal;
  486.     cur_line=1;
  487.     stack_ptr=stack+1;
  488.     cur_name= (*an_output_file);
  489.     cur_repl= (text_pointer)cur_name->equiv;
  490.     cur_byte=cur_repl->tok_start;
  491.     cur_end=(cur_repl+1)->tok_start;
  492.     while (stack_ptr > stack) get_output();
  493.     flush_buffer();
  494. }
  495. @ If a .{@@h} was not encountered in the input,
  496. we go through the list of replacement texts and copy the ones
  497. that refer to macros, preceded by the .{#define} preprocessor command.
  498. @<Output macro definitions if appropriate@>=
  499.   if (!output_defs_seen)
  500.     output_defs();
  501. @ @<Glob...@>=
  502. boolean output_defs_seen=0;
  503. @ @<Predecl...@>=
  504. void output_defs();
  505. @ @c
  506. void
  507. output_defs()
  508. {
  509.   sixteen_bits a;
  510.   push_level(NULL);
  511.   for (cur_text=text_info+1; cur_text<text_ptr; cur_text++)
  512.     if (cur_text->text_link==0) { /* |cur_text| is the text for a macro */
  513.       cur_byte=cur_text->tok_start;
  514.       cur_end=(cur_text+1)->tok_start;
  515.       C_printf("%s","#define ");
  516.       out_state=normal;
  517.       protect=1; /* newlines should be preceded by |'\'| */
  518.       while (cur_byte<cur_end) {
  519.         a=*cur_byte++;
  520.         if (cur_byte==cur_end && a=='n') break; /* disregard a final newline */
  521.         if (out_state==verbatim && a!=string && a!=constant && a!='n')
  522.           C_putc(a); /* a high-bit character can occur in a string */
  523. @^high-bit character handling@>
  524.         else if (a<0200) out_char(a); /* one-byte token */
  525.         else {
  526.           a=(a-0200)*0400+*cur_byte++;
  527.           if (a<024000) { /* |024000==(0250-0200)*0400| */
  528.             cur_val=a; out_char(identifier);
  529.           }
  530.           else if (a<050000) { confusion("macro defs have strange char");}
  531.           else {
  532.             cur_val=a-050000; cur_section=cur_val; out_char(section_number);
  533.           }
  534.       /* no other cases */
  535.         }
  536.       }
  537.       protect=0;
  538.       flush_buffer();
  539.     }
  540.   pop_level(0);
  541. }
  542. @ A many-way switch is used to send the output.  Note that this function
  543. is not called if |out_state==verbatim|, except perhaps with arguments
  544. |'n'| (protect the newline), |string| (end the string), or |constant|
  545. (end the constant).
  546. @<Predecl...@>=
  547. static void out_char();
  548. @ @c
  549. static void
  550. out_char(cur_char)
  551. eight_bits cur_char;
  552. {
  553.   char *j, *k; /* pointer into |byte_mem| */
  554. restart:
  555.     switch (cur_char) {
  556.       case 'n': if (protect) C_putc(' ');
  557.         if (protect || out_state==verbatim) C_putc('\');
  558.         flush_buffer(); if (out_state!=verbatim) out_state=normal; break;
  559.       @/@t4@>@<Case of an identifier@>;
  560.       @/@t4@>@<Case of a section number@>;
  561.       @/@t4@>@<Cases like .{!=}@>;
  562.       case '=': C_putc('='); C_putc(' '); out_state=normal; break;
  563.       case join: out_state=unbreakable; break;
  564.       case constant: if (out_state==verbatim) {
  565.           out_state=num_or_id; break;
  566.         }
  567.         if(out_state==num_or_id) C_putc(' '); out_state=verbatim; break;
  568.       case string: if (out_state==verbatim) out_state=normal;
  569.         else out_state=verbatim; break;
  570.       case '/': C_putc('/'); out_state=post_slash; break;
  571.       case '*': if (out_state==post_slash) C_putc(' ');
  572.         /* fall through */
  573.       default: C_putc(cur_char); out_state=normal; break;
  574.     }
  575. }
  576. @ @<Cases like .{!=}@>=
  577. case plus_plus: C_putc('+'); C_putc('+'); out_state=normal; break;
  578. case minus_minus: C_putc('-'); C_putc('-'); out_state=normal; break;
  579. case minus_gt: C_putc('-'); C_putc('>'); out_state=normal; break;
  580. case gt_gt: C_putc('>'); C_putc('>'); out_state=normal; break;
  581. case eq_eq: C_putc('='); C_putc('='); out_state=normal; break;
  582. case lt_lt: C_putc('<'); C_putc('<'); out_state=normal; break;
  583. case gt_eq: C_putc('>'); C_putc('='); out_state=normal; break;
  584. case lt_eq: C_putc('<'); C_putc('='); out_state=normal; break;
  585. case not_eq: C_putc('!'); C_putc('='); out_state=normal; break;
  586. case and_and: C_putc('&'); C_putc('&'); out_state=normal; break;
  587. case or_or: C_putc('|'); C_putc('|'); out_state=normal; break;
  588. case dot_dot_dot: C_putc('.'); C_putc('.'); C_putc('.'); out_state=normal;
  589.     break;
  590. case colon_colon: C_putc(':'); C_putc(':'); out_state=normal; break;
  591. case period_ast: C_putc('.'); C_putc('*'); out_state=normal; break;
  592. case minus_gt_ast: C_putc('-'); C_putc('>'); C_putc('*'); out_state=normal;
  593.     break;
  594. @ When an identifier is output to the CEE/ file, characters in the
  595. range 128--255 must be changed into something else, so the CEE/
  596. compiler won't complain.  By default, .{CTANGLE} converts the
  597. character with code $16 x+y$ to the three characters `.X$xy$', but
  598. a different transliteration table can be specified.  Thus a German
  599. might want {it gr"un/} to appear as a still readable .{gruen}.
  600. This makes debugging a lot less confusing.
  601. @d translit_length 10
  602. @<Glo...@>=
  603. char translit[128][translit_length];
  604. @ @<Set init...@>=
  605. {
  606.   int i;
  607.   for (i=0;i<128;i++) sprintf(translit[i],"X%02X",(unsigned)(128+i));
  608. }
  609. @ @<Case of an identifier@>=
  610. case identifier:
  611.   if (out_state==num_or_id) C_putc(' ');
  612.   j=(cur_val+name_dir)->byte_start;
  613.   k=(cur_val+name_dir+1)->byte_start;
  614.   while (j<k) {
  615.     if ((unsigned char)(*j)<0200) C_putc(*j);
  616. @^high-bit character handling@>
  617.     else C_printf("%s",translit[(unsigned char)(*j)-0200]);
  618.     j++;
  619.   }
  620.   out_state=num_or_id; break;
  621. @ @<Case of a sec...@>=
  622. case section_number:
  623.   if (cur_val>0) C_printf("/*%d:*/",cur_val);
  624.   else if(cur_val<0) C_printf("/*:%d*/",-cur_val);
  625.   else if (protect) {
  626.     cur_byte +=4; /* skip line number and file name */
  627.     cur_char = 'n';
  628.     goto restart;
  629.   } else {
  630.     sixteen_bits a;
  631.     a=0400* *cur_byte++;
  632.     a+=*cur_byte++; /* gets the line number */
  633.     C_printf("n#line %d "",a);
  634. @:line}{.{#line}@>
  635.     cur_val=*cur_byte++;
  636.     cur_val=0400*(cur_val-0200)+ *cur_byte++; /* points to the file name */
  637.     for (j=(cur_val+name_dir)->byte_start, k=(cur_val+name_dir+1)->byte_start;
  638.          j<k; j++) C_putc(*j);
  639.     C_printf("%s",""n");
  640.   }
  641.   break;
  642. @** Introduction to the input phase.
  643. We have now seen that .{CTANGLE} will be able to output the full
  644. CEE/ program, if we can only get that program into the byte memory in
  645. the proper format. The input process is something like the output process
  646. in reverse, since we compress the text as we read it in and we expand it
  647. as we write it out.
  648. There are three main input routines. The most interesting is the one that gets
  649. the next token of a CEE/ text; the other two are used to scan rapidly past
  650. TEX/ text in the .{CWEB} source code. One of the latter routines will jump to
  651. the next token that starts with `.{@@}', and the other skips to the end
  652. of a CEE/ comment.
  653. @ Control codes in .{CWEB} begin with `.{@@}', and the next character
  654. identifies the code. Some of these are of interest only to .{CWEAVE},
  655. so .{CTANGLE} ignores them; the others are converted by .{CTANGLE} into
  656. internal code numbers by the |ccode| table below. The ordering
  657. of these internal code numbers has been chosen to simplify the program logic;
  658. larger numbers are given to the control codes that denote more significant
  659. milestones.
  660. @d ignore 0 /* control code of no interest to .{CTANGLE} */
  661. @d ord 0302 /* control code for `.{@@'}' */
  662. @d control_text 0303 /* control code for `.{@@t}', `.{@@^}', etc. */
  663. @d translit_code 0304 /* control code for `.{@@l}' */
  664. @d output_defs_code 0305 /* control code for `.{@@h}' */
  665. @d format_code 0306 /* control code for `.{@@f}' */
  666. @d definition 0307 /* control code for `.{@@d}' */
  667. @d begin_C 0310 /* control code for `.{@@c}' */
  668. @d section_name 0311 /* control code for `.{@@<}' */
  669. @d new_section 0312 /* control code for `.{@@ }' and `.{@@*}' */
  670. @<Global...@>=
  671. eight_bits ccode[256]; /* meaning of a char following .{@@} */
  672. @ @<Set ini...@>= {
  673.   int c; /* must be |int| so the |for| loop will end */
  674.   for (c=0; c<256; c++) ccode[c]=ignore;
  675.   ccode[' ']=ccode['t']=ccode['n']=ccode['v']=ccode['r']=ccode['f']
  676.    =ccode['*']=new_section;
  677.   ccode['@@']='@@'; ccode['=']=string;
  678.   ccode['d']=ccode['D']=definition;
  679.   ccode['f']=ccode['F']=ccode['s']=ccode['S']=format_code;
  680.   ccode['c']=ccode['C']=ccode['p']=ccode['P']=begin_C;
  681.   ccode['^']=ccode[':']=ccode['.']=ccode['t']=ccode['T']=
  682.    ccode['q']=ccode['Q']=control_text;
  683.   ccode['h']=ccode['H']=output_defs_code;
  684.   ccode['l']=ccode['L']=translit_code;
  685.   ccode['&']=join;
  686.   ccode['<']=ccode['(']=section_name;
  687.   ccode[''']=ord;
  688. }
  689. @ The |skip_ahead| procedure reads through the input at fairly high speed
  690. until finding the next non-ignorable control code, which it returns.
  691. @c
  692. eight_bits
  693. skip_ahead() /* skip to next control code */
  694. {
  695.   eight_bits c; /* control code found */
  696.   while (1) {
  697.     if (loc>limit && (get_line()==0)) return(new_section);
  698.     *(limit+1)='@@';
  699.     while (*loc!='@@') loc++;
  700.     if (loc<=limit) {
  701.       loc++; c=ccode[(eight_bits)*loc]; loc++;
  702.       if (c!=ignore || *(loc-1)=='>') return(c);
  703.     }
  704.   }
  705. }
  706. @ The |skip_comment| procedure reads through the input at somewhat high
  707. speed in order to pass over comments, which .{CTANGLE} does not transmit
  708. to the output. If the comment is introduced by .{/*}, |skip_comment|
  709. proceeds until finding the end-comment token .{*/} or a newline; in the
  710. latter case |skip_comment| will be called again by |get_next|, since the
  711. comment is not finished.  This is done so that the each newline in the
  712. CEE/ part of a section is copied to the output; otherwise the &{#line}
  713. commands inserted into the CEE/ file by the output routines become useless.
  714. On the other hand, if the comment is introduced by .{//} (i.e., if it
  715. is a CPLUSPLUS/ ``short comment''), it always is simply delimited by the next
  716. newline. The boolean argument |is_long_comment| distinguishes between
  717. the two types of comments.
  718. If |skip_comment| comes to the end of the section, it prints an error message.
  719. No comment, long or short, is allowed to contain `.{@@ }' or `.{@@*}'.
  720. @<Global...@>=
  721. boolean comment_continues=0; /* are we scanning a comment? */
  722. @ @c
  723. int skip_comment(is_long_comment) /* skips over comments */
  724. boolean is_long_comment;
  725. {
  726.   char c; /* current character */
  727.   while (1) {
  728.     if (loc>limit) {
  729.       if (is_long_comment) {
  730.         if(get_line()) return(comment_continues=1);
  731.         else{
  732.           err_print("! Input ended in mid-comment");
  733. @.Input ended in mid-comment@>
  734.           return(comment_continues=0);
  735.         }
  736.       }
  737.       else return(comment_continues=0);
  738.     }
  739.     c=*(loc++);
  740.     if (is_long_comment && c=='*' && *loc=='/') {
  741.       loc++; return(comment_continues=0);
  742.     }
  743.     if (c=='@@') {
  744.       if (ccode[(eight_bits)*loc]==new_section) {
  745.         err_print("! Section name ended in mid-comment"); loc--;
  746. @.Section name ended in mid-comment@>
  747.         return(comment_continues=0);
  748.       }
  749.       else loc++;
  750.     }
  751.   }
  752. }
  753. @* Inputting the next token.
  754. @d constant 03
  755. @<Global...@>=
  756. name_pointer cur_section_name; /* name of section just scanned */
  757. int no_where; /* suppress |print_where|? */
  758. @ @<Include...@>=
  759. #include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
  760. #include <stdlib.h> /* definition of |exit| */
  761. @ As one might expect, |get_next| consists mostly of a big switch
  762. that branches to the various special cases that can arise.
  763. @d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */
  764. @d ishigh(c) ((unsigned char)(c)>0177)
  765. @^high-bit character handling@>
  766. @c
  767. eight_bits
  768. get_next() /* produces the next input token */
  769. {
  770.   static int preprocessing=0;
  771.   eight_bits c; /* the current character */
  772.   while (1) {
  773.     if (loc>limit) {
  774.       if (preprocessing && *(limit-1)!='\') preprocessing=0;
  775.       if (get_line()==0) return(new_section);
  776.       else if (print_where && !no_where) {
  777.           print_where=0;
  778.           @<Insert the line number into |tok_mem|@>;
  779.         }
  780.         else return ('n');
  781.     }
  782.     c=*loc;
  783.     if (comment_continues || (c=='/' && (*(loc+1)=='*' || *(loc+1)=='/'))) {
  784.       skip_comment(comment_continues||*(loc+1)=='*');
  785.           /* scan to end of comment or newline */
  786.       if (comment_continues) return('n');
  787.       else continue;
  788.     }
  789.     loc++;
  790.     if (xisdigit(c) || c=='\' || c=='.') @<Get a constant@>@;
  791.     else if (c==''' || c=='"' || (c=='L'&&(*loc==''' || *loc=='"')))
  792.         @<Get a string@>@;
  793.     else if (isalpha(c) || isxalpha(c) || ishigh(c))
  794.       @<Get an identifier@>@;
  795.     else if (c=='@@') @<Get control code and possible section name@>@;
  796.     else if (xisspace(c)) {
  797.         if (!preprocessing || loc>limit) continue;
  798.           /* we don't want a blank after a final backslash */
  799.         else return(' '); /* ignore spaces and tabs, unless preprocessing */
  800.     }
  801.     else if (c=='#' && loc==buffer+1) preprocessing=1;
  802.     mistake: @<Compress two-symbol operator@>@;
  803.     return(c);
  804.   }
  805. }
  806. @ The following code assigns values to the combinations .{++},
  807. .{--}, .{->}, .{>=}, .{<=}, .{==}, .{<<}, .{>>}, .{!=}, .{||} and
  808. .{&&}, and to the CPLUSPLUS/
  809. combinations .{...}, .{::}, .{.*} and .{->*}.
  810. The compound assignment operators (e.g., .{+=}) are
  811. treated as separate tokens.
  812. @d compress(c) if (loc++<=limit) return(c)
  813. @<Compress tw...@>=
  814. switch(c) {
  815.   case '+': if (*loc=='+') compress(plus_plus); break;
  816.   case '-': if (*loc=='-') {compress(minus_minus);}
  817.     else if (*loc=='>') if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);}
  818.                         else compress(minus_gt); break;
  819.   case '.': if (*loc=='*') {compress(period_ast);}
  820.             else if (*loc=='.' && *(loc+1)=='.') {
  821.               loc++; compress(dot_dot_dot);
  822.             }
  823.             break;
  824.   case ':': if (*loc==':') compress(colon_colon); break;
  825.   case '=': if (*loc=='=') compress(eq_eq); break;
  826.   case '>': if (*loc=='=') {compress(gt_eq);}
  827.     else if (*loc=='>') compress(gt_gt); break;
  828.   case '<': if (*loc=='=') {compress(lt_eq);}
  829.     else if (*loc=='<') compress(lt_lt); break;
  830.   case '&': if (*loc=='&') compress(and_and); break;
  831.   case '|': if (*loc=='|') compress(or_or); break;
  832.   case '!': if (*loc=='=') compress(not_eq); break;
  833. }
  834. @ @<Get an identifier@>= {
  835.   id_first=--loc;
  836.   while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc));
  837.   id_loc=loc; return(identifier);
  838. }
  839. @ @<Get a constant@>= {
  840.   id_first=loc-1;
  841.   if (*id_first=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */
  842.   if (*id_first=='\') while (xisdigit(*loc)) loc++; /* octal constant */
  843.   else {
  844.     if (*id_first=='0') {
  845.       if (*loc=='x' || *loc=='X') { /* hex constant */
  846.         loc++; while (xisxdigit(*loc)) loc++; goto found;
  847.       }
  848.     }
  849.     while (xisdigit(*loc)) loc++;
  850.     if (*loc=='.') {
  851.     loc++;
  852.     while (xisdigit(*loc)) loc++;
  853.     }
  854.     if (*loc=='e' || *loc=='E') { /* float constant */
  855.       if (*++loc=='+' || *loc=='-') loc++;
  856.       while (xisdigit(*loc)) loc++;
  857.     }
  858.   }
  859.   found: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
  860.              || *loc=='f' || *loc=='F') loc++;
  861.   id_loc=loc;
  862.   return(constant);
  863. }
  864. @ CEE/ strings and character constants, delimited by double and single
  865. quotes, respectively, can contain newlines or instances of their own
  866. delimiters if they are protected by a backslash.  We follow this
  867. convention, but do not allow the string to be longer than |longest_name|.
  868. @<Get a string@>= {
  869.   char delim = c; /* what started the string */
  870.   id_first = section_text+1;
  871.   id_loc = section_text; *++id_loc=delim;
  872.   if (delim=='L') { /* wide character constant */
  873.     delim=*loc++; *++id_loc=delim;
  874.   }
  875.   while (1) {
  876.     if (loc>=limit) {
  877.       if(*(limit-1)!='\') {
  878.         err_print("! String didn't end"); loc=limit; break;
  879. @.String didn't end@>
  880.       }
  881.       if(get_line()==0) {
  882.         err_print("! Input ended in middle of string"); loc=buffer; break;
  883. @.Input ended in middle of string@>
  884.       }
  885.       else if (++id_loc<=section_text_end) *id_loc='n'; /* will print as
  886.       .{"\\\n"} */
  887.     }
  888.     if ((c=*loc++)==delim) {
  889.       if (++id_loc<=section_text_end) *id_loc=c;
  890.       break;
  891.     }
  892.     if (c=='\') {
  893.       if (loc>=limit) continue;
  894.       if (++id_loc<=section_text_end) *id_loc = '\';
  895.       c=*loc++;
  896.     }
  897.     if (++id_loc<=section_text_end) *id_loc=c;
  898.   }
  899.   if (id_loc>=section_text_end) {
  900.     printf("n! String too long: ");
  901. @.String too long@>
  902.     term_write(section_text+1,25);
  903.     err_print("...");
  904.   }
  905.   id_loc++;
  906.   return(string);
  907. }
  908. @ After an .{@@} sign has been scanned, the next character tells us
  909. whether there is more work to do.
  910. @<Get control code and possible section name@>= {
  911.   c=ccode[(eight_bits)*loc++];
  912.   switch(c) {
  913.     case ignore: continue;
  914.     case output_defs_code: output_defs_seen=1; return(c);
  915.     case translit_code: err_print("! Use @@l in limbo only"); continue;
  916. @.Use @@l in limbo...@>
  917.     case control_text: while ((c=skip_ahead())=='@@');
  918.       /* only .{@@@@} and .{@@>} are expected */
  919.       if (*(loc-1)!='>')
  920.         err_print("! Double @@ should be used in control text");
  921. @.Double @@ should be used...@>
  922.       continue;
  923.     case section_name:
  924.       cur_section_name_char=*(loc-1);
  925.       @<Scan the section name and make |cur_section_name| point to it@>;
  926.     case string: @<Scan a verbatim string@>;
  927.     case ord: @<Scan an ASCII constant@>;
  928.     default: return(c);
  929.   }
  930. }
  931. @ After scanning a valid ASCII constant that follows
  932. .{@@'}, this code plows ahead until it finds the next single quote.
  933. (Special care is taken if the quote is part of the constant.)
  934. Anything after a valid ASCII constant is ignored;
  935. thus, .{@@'\nopq'} gives the same result as .{@@'\n'}.
  936. @<Scan an ASCII constant@>=
  937.   id_first=loc;
  938.   if (*loc=='\') {
  939.     if (*++loc==''') loc++;
  940.   }
  941.   while (*loc!=''') {
  942.     if (*loc=='@@') {
  943.       if (*(loc+1)!='@@')
  944.         err_print("! Double @@ should be used in ASCII constant");
  945. @.Double @@ should be used...@>
  946.       else loc++;
  947.     }
  948.     loc++;
  949.     if (loc>limit) {
  950.         err_print("! String didn't end"); loc=limit-1; break;
  951. @.String didn't end@>
  952.     }
  953.   }
  954.   loc++;
  955.   return(ord);
  956. @ @<Scan the section name...@>= {
  957.   char *k; /* pointer into |section_text| */
  958.   @<Put section name into |section_text|@>;
  959.   if (k-section_text>3 && strncmp(k-2,"...",3)==0)
  960.     cur_section_name=section_lookup(section_text+1,k-3,1); /* 1 means is a prefix */
  961.   else cur_section_name=section_lookup(section_text+1,k,0);
  962.   if (cur_section_name_char=='(')
  963.     @<If it's not there, add |cur_section_name| to the output file stack, or
  964.           complain we're out of room@>;
  965.   return(section_name);
  966. }
  967. @ Section names are placed into the |section_text| array with consecutive spaces,
  968. tabs, and carriage-returns replaced by single spaces. There will be no
  969. spaces at the beginning or the end. (We set |section_text[0]=' '| to facilitate
  970. this, since the |section_lookup| routine uses |section_text[1]| as the first
  971. character of the name.)
  972. @<Set init...@>=section_text[0]=' ';
  973. @ @<Put section name...@>=
  974. k=section_text;
  975. while (1) {
  976.   if (loc>limit && get_line()==0) {
  977.     err_print("! Input ended in section name");
  978. @.Input ended in section name@>
  979.     loc=buffer+1; break;
  980.   }
  981.   c=*loc;
  982.   @<If end of name or erroneous nesting, |break|@>;
  983.   loc++; if (k<section_text_end) k++;
  984.   if (xisspace(c)) {
  985.     c=' '; if (*(k-1)==' ') k--;
  986.   }
  987. *k=c;
  988. }
  989. if (k>=section_text_end) {
  990.   printf("n! Section name too long: ");
  991. @.Section name too long@>
  992.   term_write(section_text+1,25);
  993.   printf("..."); mark_harmless;
  994. }
  995. if (*k==' ' && k>section_text) k--;
  996. @ @<If end of name or erroneous nesting,...@>=
  997. if (c=='@@') {
  998.   c=*(loc+1);
  999.   if (c=='>') {
  1000.     loc+=2; break;
  1001.   }
  1002.   if (ccode[(eight_bits)c]==new_section) {
  1003.     err_print("! Section name didn't end"); break;
  1004. @.Section name didn't end@>
  1005.   }
  1006.   if (ccode[(eight_bits)c]==section_name) {
  1007.     err_print("! Nesting of section names not allowed"); break;
  1008. @.Nesting of section names...@>
  1009.   }
  1010.   *(++k)='@@'; loc++; /* now |c==*loc| again */
  1011. }
  1012. @ At the present point in the program we
  1013. have |*(loc-1)==string|; we set |id_first| to the beginning
  1014. of the string itself, and |id_loc| to its ending-plus-one location in the
  1015. buffer.  We also set |loc| to the position just after the ending delimiter.
  1016. @<Scan a verbatim string@>= {
  1017.   id_first=loc++; *(limit+1)='@@'; *(limit+2)='>';
  1018.   while (*loc!='@@' || *(loc+1)!='>') loc++;
  1019.   if (loc>=limit) err_print("! Verbatim string didn't end");
  1020. @.Verbatim string didn't end@>
  1021.   id_loc=loc; loc+=2;
  1022.   return(string);
  1023. }
  1024. @* Scanning a macro definition.
  1025. The rules for generating the replacement texts corresponding to macros and
  1026. CEE/ texts of a section are almost identical; the only differences are that
  1027. yskip item{a)}Section names are not allowed in macros;
  1028. in fact, the appearance of a section name terminates such macros and denotes
  1029. the name of the current section.
  1030. item{b)}The symbols .{@@d} and .{@@f} and .{@@c} are not allowed after
  1031. section names, while they terminate macro definitions.
  1032. item{c)}Spaces are inserted after right parentheses in macros, because the
  1033. ANSI CEE/ preprocessor sometimes requires it.
  1034. yskip Therefore there is a single procedure |scan_repl| whose parameter
  1035. |t| specifies either |macro| or |section_name|. After |scan_repl| has
  1036. acted, |cur_text| will point to the replacement text just generated, and
  1037. |next_control| will contain the control code that terminated the activity.
  1038. @d macro  0
  1039. @d app_repl(c)  {if (tok_ptr==tok_mem_end) overflow("token"); *tok_ptr++=c;}
  1040. @<Global...@>=
  1041. text_pointer cur_text; /* replacement text formed by |scan_repl| */
  1042. eight_bits next_control;
  1043. @ @c
  1044. void
  1045. scan_repl(t) /* creates a replacement text */
  1046. eight_bits t;
  1047. {
  1048.   sixteen_bits a; /* the current token */
  1049.   if (t==section_name) {@<Insert the line number into |tok_mem|@>;}
  1050.   while (1) switch (a=get_next()) {
  1051.       @<In cases that |a| is a non-|char| token (|identifier|,
  1052.         |section_name|, etc.), either process it and change |a| to a byte
  1053.         that should be stored, or |continue| if |a| should be ignored,
  1054.         or |goto done| if |a| signals the end of this replacement text@>@;
  1055.       case ')': app_repl(a);
  1056.         if (t==macro) app_repl(' ');
  1057.         break;
  1058.       default: app_repl(a); /* store |a| in |tok_mem| */
  1059.     }
  1060.   done: next_control=(eight_bits) a;
  1061.   if (text_ptr>text_info_end) overflow("text");
  1062.   cur_text=text_ptr; (++text_ptr)->tok_start=tok_ptr;
  1063. }
  1064. @ Here is the code for the line number: first a |sixteen_bits| equal
  1065. to |0150000|; then the numeric line number; then a pointer to the
  1066. file name.
  1067. @<Insert the line...@>=
  1068. store_two_bytes(0150000);
  1069. if (changing) id_first=change_file_name;
  1070. else id_first=cur_file_name;
  1071. id_loc=id_first+strlen(id_first);
  1072. if (changing) store_two_bytes((sixteen_bits)change_line);
  1073. else store_two_bytes((sixteen_bits)cur_line);
  1074. {int a=id_lookup(id_first,id_loc,0)-name_dir; app_repl((a / 0400)+0200);
  1075.   app_repl(a % 0400);}
  1076. @ @<In cases that |a| is...@>=
  1077. case identifier: a=id_lookup(id_first,id_loc,0)-name_dir;
  1078.   app_repl((a / 0400)+0200);
  1079.   app_repl(a % 0400); break;
  1080. case section_name: if (t!=section_name) goto done;
  1081.   else {
  1082.     @<Was an `@@' missed here?@>;
  1083.     a=cur_section_name-name_dir;
  1084.     app_repl((a / 0400)+0250);
  1085.     app_repl(a % 0400);
  1086.     @<Insert the line number into |tok_mem|@>; break;
  1087.   }
  1088. case output_defs_code:
  1089.   a=output_defs_flag;
  1090.   app_repl((a / 0400)+0200);
  1091.   app_repl(a % 0400);
  1092.   @<Insert the line number into |tok_mem|@>; break;
  1093. case constant: case string:
  1094.   @<Copy a string or verbatim construction or numerical constant@>;
  1095. case ord:
  1096.   @<Copy an ASCII constant@>;
  1097. case definition: case format_code: case begin_C: if (t!=section_name) goto done;
  1098.   else {
  1099.     err_print("! @@d, @@f and @@c are ignored in C text"); continue;
  1100. @.@@d, @@f and @@c are ignored in C text@>
  1101.   }
  1102. case new_section: goto done;
  1103. @ @<Was an `@@'...@>= {
  1104.   char *try_loc=loc;
  1105.   while (*try_loc==' ' && try_loc<limit) try_loc++;
  1106.   if (*try_loc=='+' && try_loc<limit) try_loc++;
  1107.   while (*try_loc==' ' && try_loc<limit) try_loc++;
  1108.   if (*try_loc=='=') err_print ("! Missing `@@ ' before a named section");
  1109. @.Missing `@@ '...@>
  1110.   /* user who isn't defining a section should put newline after the name,
  1111.      as explained in the manual */
  1112. }
  1113. @ @<Copy a string...@>=
  1114.   app_repl(a); /* |string| or |constant| */
  1115.   while (id_first < id_loc) { /* simplify .{@@@@} pairs */
  1116.     if (*id_first=='@@') {
  1117.       if (*(id_first+1)=='@@') id_first++;
  1118.       else err_print("! Double @@ should be used in string");
  1119. @.Double @@ should be used...@>
  1120.     }
  1121.     app_repl(*id_first++);
  1122.   }
  1123.   app_repl(a); break;
  1124. @ This section should be rewritten on machines that don't use ASCII
  1125. code internally.
  1126. @^ASCII code dependencies@>
  1127. @<Copy an ASCII constant@>= {
  1128.   int c=(eight_bits) *id_first;
  1129.   if (c=='\') {
  1130.     c=*++id_first;
  1131.     if (c>='0' && c<='7') {
  1132.       c-='0';
  1133.       if (*(id_first+1)>='0' && *(id_first+1)<='7') {
  1134.         c=8*c+*(++id_first) - '0';
  1135.         if (*(id_first+1)>='0' && *(id_first+1)<='7' && c<32)
  1136.           c=8*c+*(++id_first)- '0';
  1137.       }
  1138.     }
  1139.     else switch (c) {
  1140.     case 't':c='t';@+break;
  1141.     case 'n':c='n';@+break;
  1142.     case 'b':c='b';@+break;
  1143.     case 'f':c='f';@+break;
  1144.     case 'v':c='v';@+break;
  1145.     case 'r':c='r';@+break;
  1146.     case 'a':c='7';@+break;
  1147.     case '?':c='?';@+break;
  1148.     case 'x':
  1149.       if (xisdigit(*(id_first+1))) c=*(++id_first)-'0';
  1150.       else if (xisxdigit(*(id_first+1))) {
  1151.         ++id_first;
  1152.         c=toupper(*id_first)-'A'+10;
  1153.       }
  1154.       if (xisdigit(*(id_first+1))) c=16*c+*(++id_first)-'0';
  1155.       else if (xisxdigit(*(id_first+1))) {
  1156.         ++id_first;
  1157.         c=16*c+toupper(*id_first)-'A'+10;
  1158.       }
  1159.       break;
  1160.     case '\':c='\';@+break;
  1161.     case ''':c=''';@+break;
  1162.     case '"':c='"';@+break;
  1163.     default: err_print("! Unrecognized escape sequence");
  1164. @.Unrecognized escape sequence@>
  1165.     }
  1166.   }@/
  1167.   /* at this point |c| should have been converted to its ASCII code number */
  1168.   app_repl(constant);
  1169.   if (c>=100) app_repl('0'+c/100);
  1170.   if (c>=10) app_repl('0'+(c/10)%10);
  1171.   app_repl('0'+c%10);
  1172.   app_repl(constant);
  1173. }
  1174. break;
  1175. @* Scanning a section.
  1176. The |scan_section| procedure starts when `.{@@ }' or `.{@@*}' has been
  1177. sensed in the input, and it proceeds until the end of that section.  It
  1178. uses |section_count| to keep track of the current section number; with luck,
  1179. .{CWEAVE} and .{CTANGLE} will both assign the same numbers to sections.
  1180. @<Global...@>=
  1181. extern sixteen_bits section_count; /* the current section number */
  1182. @ The body of |scan_section| is a loop where we look for control codes
  1183. that are significant to .{CTANGLE}: those
  1184. that delimit a definition, the CEE/ part of a module, or a new module.
  1185. @c
  1186. void
  1187. scan_section()
  1188. {
  1189.   name_pointer p; /* section name for the current section */
  1190.   text_pointer q; /* text for the current section */
  1191.   sixteen_bits a; /* token for left-hand side of definition */
  1192.   section_count++; @+ no_where=1;
  1193.   if (*(loc-1)=='*' && show_progress) { /* starred section */
  1194.     printf("*%d",section_count); update_terminal;
  1195.   }
  1196.   next_control=0;
  1197.   while (1) {
  1198.     @<Skip ahead until |next_control| corresponds to .{@@d}, .{@@<},
  1199.       .{@@ } or the like@>;
  1200.     if (next_control == definition) {  /* .{@@d} */
  1201.         @<Scan a definition@>@;
  1202.         continue;
  1203.     }
  1204.     if (next_control == begin_C) {  /* .{@@c} or .{@@p} */
  1205.       p=name_dir; break;
  1206.     }
  1207.     if (next_control == section_name) { /* .{@@<} or .{@@(} */
  1208.       p=cur_section_name;
  1209.       @<If section is not being defined, |continue| @>;
  1210.       break;
  1211.     }
  1212.     return; /* .{@@ } or .{@@*} */
  1213.   }
  1214.   no_where=print_where=0;
  1215.   @<Scan the CEE/ part of the current section@>;
  1216. }
  1217. @ At the top of this loop, if |next_control==section_name|, the
  1218. section name has already been scanned (see |@<Get control code
  1219. and...@>|).  Thus, if we encounter |next_control==section_name| in the
  1220. skip-ahead process, we should likewise scan the section name, so later
  1221. processing will be the same in both cases.
  1222. @<Skip ahead until |next_control| ...@>=
  1223. while (next_control<definition)
  1224.       /* |definition| is the lowest of the ``significant'' codes */
  1225.   if((next_control=skip_ahead())==section_name){
  1226.     loc-=2; next_control=get_next();
  1227.   }
  1228. @ @<Scan a definition@>= {
  1229.   while ((next_control=get_next())=='n'); /*allow newline before definition */
  1230.   if (next_control!=identifier) {
  1231.     err_print("! Definition flushed, must start with identifier");
  1232. @.Definition flushed...@>
  1233.     continue;
  1234.   }
  1235.   app_repl(((a=id_lookup(id_first,id_loc,0)-name_dir) / 0400)+0200);
  1236.         /* append the lhs */
  1237.   app_repl(a % 0400);
  1238.   if (*loc!='(') { /* identifier must be separated from replacement text */
  1239.     app_repl(string); app_repl(' '); app_repl(string);
  1240.   }
  1241.   scan_repl(macro);
  1242.   cur_text->text_link=0; /* |text_link==0| characterizes a macro */
  1243. }
  1244. @ If the section name is not followed by .{=} or .{+=}, no CEE/
  1245. code is forthcoming: the section is being cited, not being
  1246. defined.  This use is illegal after the definition part of the
  1247. current section has started, except inside a comment, but
  1248. .{CTANGLE} does not enforce this rule: it simply ignores the offending
  1249. section name and everything following it, up to the next significant
  1250. control code.
  1251. @<If section is not being defined, |continue| @>=
  1252. while ((next_control=get_next())=='+'); /* allow optional .{+=} */
  1253. if (next_control!='=' && next_control!=eq_eq)
  1254.   continue;
  1255. @ @<Scan the CEE/...@>=
  1256. @<Insert the section number into |tok_mem|@>;
  1257. scan_repl(section_name); /* now |cur_text| points to the replacement text */
  1258. @<Update the data structure so that the replacement text is accessible@>;
  1259. @ @<Insert the section number...@>=
  1260. store_two_bytes((sixteen_bits)(0150000+section_count));
  1261.   /* |0150000==0320*0400| */
  1262. @ @<Update the data...@>=
  1263. if (p==name_dir||p==0) { /* unnamed section, or bad section name */
  1264.   (last_unnamed)->text_link=cur_text-text_info; last_unnamed=cur_text;
  1265. }
  1266. else if (p->equiv==(char *)text_info) p->equiv=(char *)cur_text;
  1267.   /* first section of this name */
  1268. else {
  1269.   q=(text_pointer)p->equiv;
  1270.   while (q->text_link<section_flag)
  1271.     q=q->text_link+text_info; /* find end of list */
  1272.   q->text_link=cur_text-text_info;
  1273. }
  1274. cur_text->text_link=section_flag;
  1275.   /* mark this replacement text as a nonmacro */
  1276. @ @<Predec...@>=
  1277. void phase_one();
  1278. @ @c
  1279. void
  1280. phase_one() {
  1281.   phase=1;
  1282.   section_count=0;
  1283.   reset_input();
  1284.   skip_limbo();
  1285.   while (!input_has_ended) scan_section();
  1286.   check_complete();
  1287.   phase=2;
  1288. }
  1289. @ Only a small subset of the control codes is legal in limbo, so limbo
  1290. processing is straightforward.
  1291. @<Predecl...@>=
  1292. void skip_limbo();
  1293. @ @c
  1294. void
  1295. skip_limbo()
  1296. {
  1297.   char c;
  1298.   while (1) {
  1299.     if (loc>limit && get_line()==0) return;
  1300.     *(limit+1)='@@';
  1301.     while (*loc!='@@') loc++;
  1302.     if (loc++<=limit) {
  1303.       c=*loc++;
  1304.       if (ccode[(eight_bits)c]==new_section) break;
  1305.       switch (ccode[(eight_bits)c]) {
  1306.         case translit_code: @<Read in transliteration of a character@>; break;
  1307.         case format_code: case '@@': break;
  1308.         case control_text: if (c=='q' || c=='Q') {
  1309.           while ((c=skip_ahead())=='@@');
  1310.           if (*(loc-1)!='>')
  1311.             err_print("! Double @@ should be used in control text");
  1312. @.Double @@ should be used...@>
  1313.           break;
  1314.           } /* otherwise fall through */
  1315.         default: err_print("! Double @@ should be used in limbo");
  1316. @.Double @@ should be used...@>
  1317.       }
  1318.     }
  1319.   }
  1320. }
  1321. @ @<Read in transliteration of a character@>=
  1322.   while(xisspace(*loc)&&loc<limit) loc++;
  1323.   loc+=3;
  1324.   if (loc>limit || !xisxdigit(*(loc-3)) || !xisxdigit(*(loc-2)) @|
  1325.          || (*(loc-3)>='0' && *(loc-3)<='7') || !xisspace(*(loc-1)))
  1326.     err_print("! Improper hex number following @@l");
  1327. @.Improper hex number...@>
  1328.   else {
  1329.     unsigned i;
  1330.     char *beg;
  1331.     sscanf(loc-3,"%x",&i);
  1332.     while(xisspace(*loc)&&loc<limit) loc++;
  1333.     beg=loc;
  1334.     while(loc<limit&&(xisalpha(*loc)||xisdigit(*loc)||*loc=='_')) loc++;
  1335.     if (loc-beg>=translit_length)
  1336.       err_print("! Replacement string in @@l too long");
  1337. @.Replacement string in @@l...@>
  1338.     else{
  1339.       strncpy(translit[i-0200],beg,loc-beg);
  1340.       translit[i-0200][loc-beg]='';
  1341.     }
  1342.   }
  1343. @ Because on some systems the difference between two pointers is a |long|
  1344. but not an |int|, we use .{%ld} to print these quantities.
  1345. @c
  1346. void
  1347. print_stats() {
  1348.   printf("nMemory usage statistics:n");
  1349.   printf("%ld names (out of %ld)n",
  1350.           (long)(name_ptr-name_dir),(long)max_names);
  1351.   printf("%ld replacement texts (out of %ld)n",
  1352.           (long)(text_ptr-text_info),(long)max_texts);
  1353.   printf("%ld bytes (out of %ld)n",
  1354.           (long)(byte_ptr-byte_mem),(long)max_bytes);
  1355.   printf("%ld tokens (out of %ld)n",
  1356.           (long)(tok_ptr-tok_mem),(long)max_toks);
  1357. }
  1358. @** Index.
  1359. Here is a cross-reference table for .{CTANGLE}.
  1360. All sections in which an identifier is
  1361. used are listed with that identifier, except that reserved words are
  1362. indexed only when they appear in format definitions, and the appearances
  1363. of identifiers in section names are not indexed. Underlined entries
  1364. correspond to where the identifier was declared. Error messages and
  1365. a few other things like ``ASCII code dependencies'' are indexed here too.