home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / reviewed / volume02 / crefine / part03 < prev    next >
Encoding:
Internet Message Format  |  1992-07-14  |  31.8 KB

  1. From: Lutz Prechelt <prechelt@ira.uka.de>
  2. Subject: v02i016: crefine - (Ver. 3.0) C language extension, Part03/06
  3. Newsgroups: comp.sources.reviewed
  4. Approved: csr@calvin.dgbt.doc.ca
  5.  
  6. Submitted-by: Lutz Prechelt <prechelt@ira.uka.de>
  7. Posting-number: Volume 2, Issue 16
  8. Archive-name: crefine/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of shell archive."
  17. # Contents:  crefine.cr
  18. # Wrapped by prechelt@Sansibar on Fri Jun 12 13:13:44 1992
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'crefine.cr' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'crefine.cr'\"
  22. else
  23. echo shar: Extracting \"'crefine.cr'\" \(30456 characters\)
  24. sed "s/^X//" >'crefine.cr' <<'END_OF_FILE'
  25. X/*************************************************************************
  26. XProject : C-Refine Precompiler
  27. XModule  : main module
  28. XAuthor  : Lutz Prechelt, Karlsruhe
  29. XDate    : 12.06.92  Version 17
  30. XCompiler: C, C-Refine
  31. X**************************************************************************/
  32. X/*
  33. X    Copyright (C) 1988,89,90,91 by Lutz Prechelt, Karlsruhe
  34. X
  35. X    This program is free software; you can redistribute it and/or modify
  36. X    it under the terms of the GNU General Public License as published by
  37. X    the Free Software Foundation; either version 1, or (at your option)
  38. X    any later version.
  39. X    This program is distributed in the hope that it will be useful,
  40. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  41. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  42. X    GNU General Public License for more details.
  43. X    You should have received a copy of the GNU General Public License
  44. X    along with this program; if not, write to the Free Software
  45. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  46. X*/
  47. X
  48. X/************************************************************************
  49. X*********************** C - R e f i n e *********************************
  50. X*************************************************************************/
  51. X
  52. X#if 0
  53. XREMARK:
  54. X  This program was originally written using german identifiers and
  55. X  comments. I worked through it to change this (at least in most parts)
  56. X  but please do not flame me if there are relicts from this state.
  57. X  I did not find a sensible replacement for the german word 'Klammer' that
  58. X  may stand for any of the characters ( ) [ ] { }  so sometimes I still
  59. X  use the german one.
  60. X
  61. XVariants:
  62. X#define deutsch   fuer deutsche Meldungen statt englische
  63. X#define ms_dos    for  MS-DOS "Operating System"
  64. X#define __STDC__  for  ANSI-C Compiler (as opposed to K&R-C)
  65. X
  66. XFor version changes see refinement startup message and file cr_texts.h
  67. X
  68. X============================== History: ====================================
  69. X
  70. X
  71. XVersion 1.0  (Alpha)    (0, 1)
  72. X
  73. X1987
  74. X  procedural refinements only
  75. X  not comfortable, few error messages
  76. X
  77. X
  78. XVersion 2.0  (Alpha)    (2, 3)
  79. X
  80. XFeb. 88
  81. X  value-returning refinements,
  82. X  improved error handling,
  83. X  Options comment, feedback, list, numbering, refinementsymbol, small
  84. X
  85. X
  86. XVersion 2.1  (Beta)     (4, 5)
  87. X
  88. X09.04.88  ( --> Martin, Ihno, Volker, Beat)
  89. X  improved error handling
  90. X  triple error messages (german, english, german nonsense),
  91. X  Context description in error messages,
  92. X  Options anyway, feedback, ibm chars, message type, tabsize, warning level
  93. X  Expires 31.07.88
  94. X
  95. X
  96. XVersion 2.2             (6, 7, 8)
  97. X
  98. X08.07.88   ( --> Martin)
  99. X  corr: Changes blanks in namen to underscrores again (like in Version 1.0)
  100. X        (otherwise error in goto occur)
  101. X  corr: Removed semicolon after value-returning refinements kept
  102. X        (via introduction of refcallr)
  103. X  improved error handling: Warning for "often used" only for
  104. X  "big" refinements.
  105. X03.08.88
  106. X  corr: When inserting file names in "#line"-commands, backslashes
  107. X        are doubled (backslash is Escape symbol in C string denoters)
  108. X13.09.88
  109. X  corr: empty refinements will not give syntax errors anymore.
  110. X
  111. X
  112. XVersion 2.3             (9, 10, 11, 12, 13)
  113. X
  114. X29.09.88 ( --> Martin, Ihno)
  115. X  corr: refinements with just 1 semicolon are enclosed in braces also
  116. X        (to avoid "else"-conflict)
  117. X  C++ Mode (i.e. // Kommentare) as option p
  118. X17.03.89
  119. X  "std.h" introduced,  #ifdefs for environment switches introduced.
  120. X  Look-through, further "refinementized", several small corrections
  121. X  ported to SUN-OS (Berkeley-Unix)
  122. X  Size restrictions released (500 -> 800 lines, 50 -> 100 Refinements)
  123. X18.03.89
  124. X  dito, expires 31.07.89
  125. X11.09.89
  126. X  ported to PCS maschine under Munix 5.3 (System V)
  127. X  further #ifdefs for deutsch, expire
  128. X  The switches are given in the Makefile
  129. X11.09.89
  130. X  dito, expires 31.10.89
  131. X
  132. X
  133. XVersion 2.4             (14, 15, 16)
  134. X
  135. X27.08.90 ( --> Uni)
  136. X  Line numbering switchable in 4 levels.
  137. X  Quiet-Option
  138. X  Buffersizes selectable via option.
  139. X  New name handling for input/output files
  140. X  
  141. X23.01.91 ( --> Uni, Usenet announcement, iraun1)
  142. X  Names and Comments changed to english (was german before)
  143. X  error in level switching of line numbering fixed.
  144. X  
  145. X10.06.91 (comp.sources.misc)
  146. X  History translated to english
  147. X  some small corrections
  148. X  corr: REF_INFO storage has to be 0-initialized, 
  149. X        so use calloc instead of malloc
  150. X  Eliminated duplication of function declarations for ansi and non-ansi
  151. X  by introduction of the A(a) macro in std.h  
  152. X
  153. X
  154. XVersion 3.0             (17)
  155. X
  156. X15.11.91
  157. X  Getargs deeply changed: disallow mixing of options and normal args but
  158. X  allow values for options to be in separate argument.
  159. X  Handle multiple input file names.
  160. X  Introduced -o option for explicit output filename, all other are built
  161. X  by deleting a trailing r from input filename.
  162. X  Handle "-" for stdin and stdout in filenames.
  163. X  React on #line commands in input file.  !!!INCOMPLETE!!!
  164. X  Changed #include commands in sourcess for better portability
  165. X  Replaced 'ansi' #define with '__STDC__'
  166. X12.06.92 (comp.sources.reviewed)
  167. X  replaced -q (quiet) flag with a -v (verbose) flag with inverse meaning.
  168. X  added humorous messages for english, changed -m option appropriately.
  169. X
  170. X=============================================================================
  171. X#endif
  172. X
  173. X#include <stdio.h>
  174. X
  175. X#if __STDC__
  176. X#include <stdlib.h>
  177. X#else
  178. Xextern char* malloc();  /* some systems don't have malloc.h or the like */
  179. Xextern char* calloc();
  180. X#endif
  181. X
  182. X#include <time.h>
  183. X
  184. X#define DATA_HERE     /* Here the data declarations are NOT extern */
  185. X#include "cr_decl.h"  /* global Functions, Types and Data */
  186. X#include "getargs.h"
  187. X
  188. X
  189. X/******************* lokal Functions ************************************/
  190. X
  191. Xextern int  main A((int argc,  charp argv[]));
  192. Xstatic int  crefine A(());
  193. Xstatic void process_c_refine A((FILE *in, FILE *out));
  194. Xstatic void process_line A((FILE *out, int semicolons));
  195. Xstatic void insert_refinements A((FILE *out));
  196. Xstatic void insert_refinement A((FILE *out, LINE_INFO *l, int startindent,
  197. X                               int recursive_level));
  198. Xstatic void line_cmd A((FILE* out, int nr, int indent, int min_level));
  199. Xstatic void put_indent A((FILE *out, int how_much));
  200. Xstatic void put_line A((FILE *out, LINE_INFO *line, int additional_indent,
  201. X                      int min_linenumbering_level));
  202. Xstatic int  refinement_nr A((char *refinementname));
  203. Xstatic void reset_l_r_s A(());
  204. X
  205. X/*********************** Lokal Data ************************************/
  206. X
  207. X/***** line info, refinement info *****/
  208. Xstatic LINES l;           /* line info */
  209. Xstatic int   l_pos;
  210. X
  211. Xstatic REFS  r;           /* refinement info */
  212. Xstatic int   r_pos;
  213. X
  214. X/***** Status *****/
  215. Xstatic int   old_level;          /* level at line before */
  216. X
  217. X/***** Sonstiges *****/
  218. Xstatic char  blanks[] =  /* indents are made from this. */
  219. X  "                                                                       ";
  220. X/* "blanks" is taken as  72 Blanks long (see put_indent) */
  221. X
  222. Xstatic char *outputfilename = "";
  223. Xstatic int   option_msg;
  224. X
  225. X#define refdecl_line_nr(i)  /* line number of refinement head of r[i] */\
  226. X                          (l [r[i].firstentry].line_no)
  227. X
  228. X/******************************** crefine *********************************/
  229. X
  230. Xstatic ARG argtab[] = {
  231. X#if  deutsch
  232. X  {'a', BOOLEAN, &option_anyway,
  233. X   "alle: Ausgabedatei trotz Fehlern nicht loeschen" },
  234. X  {'c', BOOLEAN, &option_comment,  "Refinementnamen-Kommentare in Ausgabe" },
  235. X  {'e', BOOLEAN, &option_indent,   "#line Kommandos einruecken" },
  236. X#if ms_dos
  237. X  {'I', BOOLEAN, &option_ibmchars, 
  238. X   "erlaube IBM internationale Zeichen fuer Namen" },
  239. X#endif
  240. X  {'k', BOOLEAN, &option_comment,  "Refinementnamen-Kommentare in Ausgabe" },
  241. X  {'l', BOOLEAN, &option_list,     "liste alle Refinementnamen" },
  242. X  {'m', CHARACTER, &option_msg,    
  243. X   "Meldungen in: d=deutsch, e=english, Grossbuchstabe -> humorig" },
  244. X  {'n', INTEGER, &numbering_level,
  245. X   "Stufe der Numerierung mit #line Kommandos" },
  246. X  {'o', STRING,  &outputfilename,  "setze Name der Ausgabedatei" },
  247. X  {'p', BOOLEAN, &option_cplusplus,"C++ Modus" },
  248. X  {'v', BOOLEAN, &option_verbose,    "Versionsmeldung ausgeben" },
  249. X  {'r', CHARACTER, &refinementsymbol, "Refinementsymbol (als Zeichen)" },
  250. X  {'R', INTEGER, &refinementsymbol, "Refinementsymbol (als Zahl)" },
  251. X  {'s', BOOLEAN, &option_small,    "strippen: Kompaktifizierte Ausgabe" },
  252. X  {'w', INTEGER, &warning_level,   "Warnstufe (0 - 3)" }
  253. X  {'A', INTEGER, &feedback_interval, "Intervall der Fortschrittsanzeige" },
  254. X  {'F', INTEGER, &maxerrors,       "Max. Anzahl Fehler" },
  255. X  {'L', INTEGER, &(int*)b_size,    "Max. Zeilenlaenge in Byte" },
  256. X  {'N', INTEGER, &maxref,          "Max. Refinements je Funktion" },
  257. X  {'P', INTEGER, &(int*)s_size,    "Codepuffer in Bytes" },
  258. X  {'T', INTEGER, &tabsize,         "Tabulatorgroesse" },
  259. X  {'W', INTEGER, &maxwarnings,     "Max. Anzahl Warnungen" },
  260. X  {'Z', INTEGER, &maxline,         "Max. Anzahl Zeilen je Funktion" },
  261. X#else
  262. X  {'a', BOOLEAN, &option_anyway,   "anyway: don't delete output on errors" },
  263. X  {'c', BOOLEAN, &option_comment,  "comment refinement names in output" },
  264. X  {'i', BOOLEAN, &option_indent,   "indent the #line commands" },
  265. X#if ms_dos
  266. X  {'I', BOOLEAN, &option_ibmchars,
  267. X   "enable IBM International Charset for names" },
  268. X#endif
  269. X  {'l', BOOLEAN, &option_list,     "list all refinement names" },
  270. X  {'m', CHARACTER, &option_msg,  
  271. X   "Messages in: g=german, e=english, G,E=humorous" },
  272. X  {'n', INTEGER, &numbering_level,
  273. X   "level of numbering with #line commands" },
  274. X  {'o', STRING,  (int*)&outputfilename,  "set output filename" },
  275. X  {'p', BOOLEAN, &option_cplusplus,"C++ mode" },
  276. X  {'v', BOOLEAN, &option_verbose,    "verbose mode (startup message)" },
  277. X  {'r', CHARACTER, &refinementsymbol, "refinementsymbol (character form)" },
  278. X  {'R', INTEGER, &refinementsymbol, "refinementsymbol (decimal form)" },
  279. X  {'s', BOOLEAN, &option_small,    "small compactified output" },
  280. X  {'w', INTEGER, &warning_level,   "warning level (0 - 3)" },
  281. X  {'B', INTEGER, (int*)&s_size,    "code buffer in bytes" },
  282. X  {'E', INTEGER, &maxerrors,       "max errors" },
  283. X  {'L', INTEGER, (int*)&maxline,   "max lines per function" },
  284. X  {'M', INTEGER, (int*)&b_size,    "max length of a line" },
  285. X  {'N', INTEGER, (int*)&maxref,    "max refinements per function" },
  286. X  {'P', INTEGER, &feedback_interval, "interval of progress display" },
  287. X  {'T', INTEGER, &tabsize,         "tab size" },
  288. X  {'W', INTEGER, &maxwarnings,     "max warnings" },
  289. X#endif
  290. X};
  291. X
  292. X
  293. Xextern int main (argc, argv)
  294. X  int   argc;
  295. X  charp argv[];
  296. X{
  297. X  /* Analyses options and generates pairs of input/output filenames.
  298. X     Then calls  crefine with each of these pairs.
  299. X     Returns the number of errors that have been found totally.
  300. X  */
  301. X  int  wrong_options, total_errors = 0;
  302. X  int  i;
  303. X  FILE *in, *out;
  304. X  bool explicit_outputfilename_given;
  305. X  `analysis of options;
  306. X  if (wrong_options || argc <= 1) {
  307. X     print_usage (argv[0], usagestring[msg_type],
  308. X                  argtab, ARGTABSIZE (argtab));
  309. X    `startup message;
  310. X     exit (100);
  311. X  }
  312. X  if (option_verbose)
  313. X    `startup message;
  314. X  `reserve memory and complain if necessary;
  315. X  explicit_outputfilename_given = (outputfilename[0] != 0);
  316. X  for (i = 1; i < argc; i++)
  317. X    `generate filename pair and call crefine;
  318. X  return (total_errors);
  319. X
  320. X`analysis of options:
  321. X  option_anyway = option_indent = option_comment
  322. X                = option_list = option_ibmchars = option_cplusplus
  323. X                = false;
  324. X  option_small = true;
  325. X  numbering_level = 3;
  326. X#if deutsch
  327. X  option_msg  = 'd';   /* deutsche Meldungen als Standard */
  328. X#else
  329. X  option_msg  = 'e';   /* english warnings and errors as default */
  330. X#endif
  331. X  refinementsymbol = std_refinementsymbol;
  332. X  outputfilename   = "";
  333. X  tabsize          = 1;
  334. X  warning_level    = 3;
  335. X  maxline          = STD_MAXLINE;
  336. X  maxref           = STD_MAXREF;
  337. X  b_size           = STD_MAXLINELENGTH;
  338. X  s_size           = STD_S_SIZE;
  339. X  feedback_interval= 0;  /* feedback off */
  340. X  maxerrors        = STD_MAXERRORS;
  341. X  maxwarnings      = STD_MAXWARNINGS;
  342. X  wrong_options = getargs (&argc, &argv, argtab, ARGTABSIZE (argtab));
  343. X  if (option_small) {
  344. X     tabsize = 1;
  345. X  }
  346. X  switch (option_msg) {
  347. X    case 'd':
  348. X    case 'g':  msg_type = 0;  break;
  349. X    case 'e':  msg_type = 1;  break;
  350. X    case 'D':
  351. X    case 'G':  msg_type = 2;  break;
  352. X    case 'E':  msg_type = 3;  break;
  353. X  }
  354. X
  355. X`startup message:
  356. X  fprintf (stderr, 
  357. X           "C-Refine Precompiler   %s\n", versionstring[msg_type]);
  358. X  fprintf (stderr, 
  359. X           "Copyright (C) 1988-1992  Lutz Prechelt, Karlsruhe\n");
  360. X
  361. X`reserve memory and complain if necessary:
  362. X  b      = malloc (b_size);
  363. X  r      = (REFS)calloc ((maxref+1), sizeof (REF_INFO));
  364. X  l      = (LINES)malloc ((maxline+1) * sizeof (LINE_INFO));
  365. X  s_root = malloc (s_size);
  366. X  if (!(b && s_root && r && l)) {
  367. X     fprintf (stderr, Ememory[msg_type]);
  368. X     exit (100);
  369. X  }
  370. X
  371. X`generate filename pair and call crefine:
  372. X  strcpy (name_in, argv[i]);
  373. X  copy_with_doubled_backslashes (name_in, modified_name_in);
  374. X  if (explicit_outputfilename_given)
  375. X     `use explicit filename;
  376. X  else if (!strcmp (name_in, "-"))
  377. X     `use standard out;
  378. X  else
  379. X     `use input file name and strip r;
  380. X
  381. X`use explicit filename:
  382. X   strcpy (name_out, outputfilename);
  383. X   total_errors += crefine ();
  384. X
  385. X`use standard out:
  386. X   strcpy (name_out, "-");
  387. X   total_errors += crefine ();
  388. X     
  389. X`use input file name and strip r:
  390. X   strcpy (name_out, argv[i]);
  391. X   if (`filename ok) {
  392. X     name_out[strlen(name_out)-1] = 0; /* remove 'r' from end */
  393. X     total_errors += crefine ();
  394. X   }
  395. X   else {
  396. X     fprintf (stderr, Emissing_r[msg_type], name_in);
  397. X     total_errors++;
  398. X   }
  399. X
  400. X`filename_ok:
  401. X   name_out[strlen(name_out)-1] == 'r'
  402. X
  403. X}
  404. X
  405. X
  406. Xstatic int crefine ()    /* C-REFINE */
  407. X{
  408. X  /* Opens files name_in and name_out.
  409. X     Then calls  process_c_refine and closes files again.
  410. X     Returns the number of errors that have been found
  411. X  */
  412. X  FILE *in, *out;
  413. X  `open files and complain if necessary;
  414. X  /* here we go: */
  415. X  rewind (in);  /* Begin at the beginning, then proceed until you come */
  416. X                /* to the end, there stop.   (from: Alice in Wonderland) */
  417. X  process_c_refine (in, out);
  418. X  if (in != stdin)
  419. X    fclose (in);
  420. X  if (out != stdout) {
  421. X    fclose (out);   /* Schliessen vor unlink noetig ! */
  422. X    if (errors && !option_anyway) /* don't produce errorneous outputfiles */
  423. X       unlink (name_out);         /* delete file if possible */
  424. X  }
  425. X  if (errors || warnings)
  426. X#if deutsch
  427. X     fprintf (stderr, "%d Fehler%s   %d Warnung%s   Ausgabedatei %s\n",
  428. X              errors,   errors   != 1 ? "" : "",
  429. X              warnings, warnings != 1 ? "en" : "",
  430. X              errors && !option_anyway ?
  431. X                 "geloescht" : (errors ? "dennoch erhalten" 
  432. X                                       : "ist fragwuerdig"));
  433. X#else
  434. X     fprintf (stderr, "%d error%s   %d warning%s   Output %s\n",
  435. X              errors,   errors   != 1 ? "s" : "",
  436. X              warnings, warnings != 1 ? "s" : "",
  437. X              errors && !option_anyway ?
  438. X                 "deleted" : (errors ? "kept anyway" : "is doubtful"));
  439. X#endif
  440. X  return (errors);
  441. X
  442. X`open files and complain if necessary:
  443. X  if (!strcmp (name_in, "-"))
  444. X    in = stdin;
  445. X  else {
  446. X#if ms_dos
  447. X  in = fopen (name_in, "rt");  /* read, translated mode */
  448. X#else
  449. X  in = fopen (name_in, "r");  /* read */
  450. X#endif
  451. X  }
  452. X  if (in == NULL || ferror (in)) {
  453. X     fprintf (stderr, Eopen[msg_type], name_in);
  454. X     exit (100);
  455. X  }
  456. X  if (!strcmp (name_out, "-"))
  457. X    out = stdout;
  458. X  else {
  459. X#if ms_dos
  460. X  out = fopen (name_out, "wt");  /* write, translated mode */
  461. X#else
  462. X  out = fopen (name_out, "w");  /* write */
  463. X#endif
  464. X  }
  465. X  if (out == NULL || ferror (out)) {
  466. X     fprintf (stderr, Eopen[msg_type], name_out);
  467. X     exit (100);
  468. X  }
  469. X
  470. X}
  471. X
  472. X/************************ process_c_refine *********************************/
  473. X
  474. Xstatic void process_c_refine (in, out)
  475. X  FILE *in, *out;
  476. X{
  477. X  /* Reads the file 'in' to the end line by line via 'get_line' and
  478. X     generates the C source code by inserting the refinement bodies for
  479. X     the calls.
  480. X     Generates error messages for undeclares refinements and warnings for
  481. X     unused or often used ones.
  482. X     Uses the variables stop_processing, errors, warnings,
  483. X     s, l, r and the option indicators.
  484. X  */
  485. X  commanded_line_no = line_no = 0;
  486. X  errors = warnings = 0;
  487. X  stop_processing = error_in_this_function = false;
  488. X  reset_l_r_s ();
  489. X  init_scanner ();
  490. X  if (numbering_level > 0)
  491. X    /* we get a linefeed anyway! */
  492. X    fprintf (out, "#line 1 \"%s\"", modified_name_in);
  493. X  while (!stop_processing)
  494. X     `handle next line;
  495. X  if (feedback_interval)
  496. X     cout (line_no);
  497. X
  498. X`handle next line:
  499. X     int semicolons = 0;
  500. X     if (feedback_interval && line_no % feedback_interval == 0)
  501. X        cout (line_no);
  502. X     if (ferror (in))
  503. X        fatal_error (Ereadinput, l[l_pos-1].start, line_no);
  504. X     if (ferror (out))
  505. X        fatal_error (Ewriteoutput, NULL, line_no);
  506. X#undef  test_
  507. X#ifdef test_
  508. X  usleep (5000);
  509. X#endif
  510. X     get_line (in, l+l_pos, &semicolons);
  511. X     process_line (out, semicolons);
  512. X}
  513. X
  514. X/************************** process_line ************************************/
  515. X
  516. Xstatic void process_line (out, semicolons)
  517. X  FILE *out;
  518. X  int   semicolons;
  519. X{
  520. X  /* Works on the lines up to the current line l[l_pos] in the way that
  521. X     it decides whether a function has ended and thus the insertion of
  522. X     refinements has to be started.
  523. X     On level 0 all lines are copied from in to out immediately.
  524. X     After a state change from level 0 to level 1 all lines (along with
  525. X     a lineinfo) are kept until the next transition to level 0 and the
  526. X     refinement info is being built.
  527. X     If necessary, error messages for overflow or refinement errors and
  528. X     warnings for not or multiply used refinements are generated.
  529. X  */
  530. X  if (r_pos > 0)
  531. X     r[r_pos - 1].semicolons += semicolons;
  532. X  if (old_level == 0)
  533. X     `we came from level 0;
  534. X  else
  535. X     `we were inside a function or so;
  536. X
  537. X`we came from level 0:
  538. X   assert (l_pos == 0);   /* nothing can be stored from level 0 */
  539. X   if (l[0].level == 0 || stop_processing)
  540. X      `remains on level 0 so just copy it;
  541. X   else
  542. X      `function has begun;
  543. X
  544. X`remains on level 0 so just copy it:
  545. X   if (l[0].type != normal_line && l[0].type != empty_line)
  546. X      error (Elevel0_ref, l[0].start, line_no);
  547. X   put_line (out, &l[0], 0, 1);
  548. X   reset_l_r_s ();
  549. X
  550. X`function has begun:
  551. X   error_in_this_function = false;
  552. X   old_level = l[0].level;    /* neuen Level merken */
  553. X   if (l[0].type == refdecl_line && r_pos < maxref) {  /* empty function */
  554. X      r[r_pos].name         = l[0].start;
  555. X      r[r_pos].firstentry   = 0;
  556. X      r[r_pos].active       = false;
  557. X      r[r_pos++].semicolons = 0;
  558. X      warning (Wempty_function, NULL, line_no - 1, 3);
  559. X   }
  560. X   l_pos++;                   /* store line */
  561. X
  562. X`we were inside a function or so:
  563. X   if (l[l_pos].level == 0 || stop_processing)
  564. X      `but now we are outside;
  565. X   else
  566. X      `and still keep being in;
  567. X
  568. X`but now we are outside:
  569. X   insert_refinements (out);
  570. X   put_line (out, &l[l_pos-1], 0, 1);  /* last line (Blockklammer) */
  571. X   put_line (out, &l[l_pos], 0, 1);    /* the level 0 line */
  572. X   error_in_this_function = false;
  573. X   reset_l_r_s ();
  574. X
  575. X`and still keep being in:
  576. X   if (l[l_pos].type == refdecl_line && r_pos < maxref) {
  577. X      r[r_pos].name         = l[l_pos].start;   /* enter Refinement */
  578. X      r[r_pos].active       = false;
  579. X      r[r_pos].firstentry   = l_pos;
  580. X      r[r_pos++].semicolons = 0;
  581. X   }
  582. X   old_level = l[l_pos].level;/* store new level */
  583. X   l_pos++;                   /* store line */
  584. X   if (l_pos >= maxline)
  585. X      fatal_error (Elines_in_func, l[l_pos].start, line_no);
  586. X   if (s - s_root >= s_size - 150)  /* Reserve too small */
  587. X      fatal_error (Ebytes_in_func, l[l_pos].start, line_no);
  588. X}
  589. X
  590. X/************************ insert_refinements ******************************/
  591. X
  592. Xstatic void insert_refinements (out)
  593. X  FILE *out;
  594. X{
  595. X  /* Replaces the refinement calls with the bodies, after the whole function
  596. X     has been read in.
  597. X     In the output #line statements are generated, except if option 
  598. X     numbering_level is zero. 
  599. X     Comments and indentations are thrown away if option_small is true.
  600. X     Comments stating the refinement names are inserted in the output if
  601. X     option_comment is true.
  602. X  */
  603. X  int  i, end;
  604. X  bool extern_stop = stop_processing;  /* Protect last function against */
  605. X  stop_processing  = false;            /* local use of this variable */
  606. X  r[r_pos].firstentry = l_pos-1;       /* line of Blockklammer */
  607. X  r[r_pos].name       = NULL;
  608. X  `generate refinement list if necessary;
  609. X  `find last line to insert;
  610. X  for (i = 0; i <= end; i++) {  /* lines up to first ref. declaration */
  611. X      switch (l[i].type) {
  612. X         case refcall_line  :
  613. X         case refcallr_line :
  614. X                `insert refinement;
  615. X                break;
  616. X         case leave_line    :
  617. X                `whatshallthatbe;
  618. X                break;
  619. X         case normal_line   :
  620. X                `insert normal line;
  621. X                break;
  622. X         case empty_line    :
  623. X                putc ('\n', out);
  624. X                commanded_line_no++;
  625. X                break;
  626. X         case refdecl_line  :
  627. X         default       :
  628. X                 assert (false);
  629. X      }
  630. X  }
  631. X  `maybe give sermon on refinements;
  632. X  stop_processing = stop_processing || extern_stop;  /* Merging-Restore */
  633. X
  634. X`generate refinement list if necessary:
  635. X  if (option_list && r_pos > 0) {
  636. X     fputc ('\n', stdout);
  637. X     for (i = 0; i < r_pos; i++)
  638. X         fprintf (stdout, "(%d) %s\n", refdecl_line_nr (i), r[i].name);
  639. X  }
  640. X
  641. X`find last line to insert:
  642. X  end = r[0].firstentry - 1;
  643. X  while (l[end].type == empty_line)   /* suppress trailing empty lines */
  644. X     end--;
  645. X
  646. X`insert refinement:
  647. X   insert_refinement (out, l+i, l[i].indent, 1);
  648. X   if (stop_processing)
  649. X      return;
  650. X
  651. X`whatshallthatbe:
  652. X  assert (false);
  653. X
  654. X`insert normal line:
  655. X   put_line (out, &l[i], 0, 1);
  656. X
  657. X`maybe give sermon on refinements:
  658. X  for (i = 0; i < r_pos; i++)
  659. X      if (r[i].semicolons > 50)
  660. X         warning (Wlong_ref, l[r[i].firstentry].start,
  661. X                  refdecl_line_nr (i), 3);
  662. X      else if (r[i].calls > 5 && r[i].semicolons > 2)
  663. X         warning (Wref_often_used, l[r[i].firstentry].start,
  664. X                  refdecl_line_nr (i), 3);
  665. X      else if (r[i].calls == 0)
  666. X         warning (Wref_unused, l[r[i].firstentry].start,
  667. X                  refdecl_line_nr (i), 1);
  668. X}
  669. X
  670. X/************************* insert_refinement ******************************/
  671. X
  672. Xstatic void insert_refinement (out, z, startindent, recursive_level)
  673. X  FILE *out;
  674. X  LINE_INFO *z;
  675. X  int  startindent, recursive_level;
  676. X{
  677. X  /* Looks for the refinement to insert by its name, computes the range
  678. X     of lines to work on and does then do the same as insert_refinements
  679. X     does.
  680. X     If necessary the refinement name is given as a comment before the
  681. X     body is inserted.
  682. X     The refinement body is enclosed in delimiters:
  683. X       if ref.semicolons == 0 in parentheses (on first and last line)
  684. X       if ref.semicolons >= 1 in curly braces (on separate lines)
  685. X     The refinement calls are counted and maybe messages generated.
  686. X     In case of leave-statements the refinement that shall be leave'd is
  687. X     marked, so a label can be generated.
  688. X     Errors:
  689. X       1. Refinement is not declared
  690. X       2. recursive call to refinement
  691. X       3. leave is impossible because the refinement is not
  692. X          present in static call hierarchy
  693. X  */
  694. X  int i;
  695. X  int  nr, ref_startindent, end;
  696. X  assert (startindent > 0);
  697. X  nr = refinement_nr (`name);  /* search for refinement */
  698. X  if (nr == -1) {
  699. X     error (Eref_not_decl, `name, z->line_no);
  700. X     return;
  701. X  }
  702. X  else if (r[nr].active)
  703. X     `complain for recursive refinement call;
  704. X  else {
  705. X     r[nr].calls++;           /* register the call */
  706. X     r[nr].active   = true;
  707. X     r[nr].leave_it = false;
  708. X  }
  709. X  end = r[nr+1].firstentry - 1;
  710. X  while (l[end].type == empty_line)   /* suppress trailing empty lines */
  711. X     end--;
  712. X  i = r[nr].firstentry + 1;
  713. X  if (i > end)
  714. X     warning (Wref_empty, l[r[nr].firstentry].start, refdecl_line_nr (nr), 2);
  715. X  else
  716. X     `insert the refinement;
  717. X  r[nr].active = false;
  718. X  return;
  719. X
  720. X`complain for recursive refinement call:
  721. X   error (Erecursive_ref, `name, z->line_no);
  722. X   stop_processing = true;
  723. X   return;
  724. X
  725. X`insert the refinement:
  726. X  /* for an empty refinement, this is not called at all! */
  727. X  `write indentation and opening klammer;
  728. X  ref_startindent = l[i].indent;
  729. X  for ( ; i <= end; i++) {
  730. X      switch (l[i].type) {
  731. X         case refcall_line  :
  732. X         case refcallr_line :
  733. X                `insert refinement;
  734. X                break;
  735. X         case leave_line    :
  736. X                `insert goto statement;
  737. X                break;
  738. X         case normal_line   :
  739. X                `insert normal line;
  740. X                break;
  741. X         case empty_line    :
  742. X                putc ('\n', out);
  743. X                commanded_line_no++;
  744. X                break;
  745. X         case refdecl_line  :
  746. X         default       :
  747. X                 assert (false);
  748. X      }
  749. X  }
  750. X  if (r[nr].leave_it)
  751. X     `generate label;
  752. X  `write closing klammer;
  753. X
  754. X`write indentation and opening klammer:
  755. X  int sc = r[nr].semicolons;
  756. X  if (sc > 0)
  757. X     put_indent (out, startindent);
  758. X  putc (sc > 0 ? '{' : '(', out);  /* Klammer auf */
  759. X  if (option_comment && sc > 0)
  760. X     fprintf (out, Tlistline[msg_type], `name, recursive_level);
  761. X
  762. X`insert refinement:
  763. X   insert_refinement (out, l+i,
  764. X                      startindent + l[i].indent
  765. X                                  - ref_startindent,
  766. X                      recursive_level+1);
  767. X
  768. X`insert goto statement:
  769. X   int leave_nr = refinement_nr (l[i].start);
  770. X   if (leave_nr == -1)
  771. X      error (Eunknown_leave, l[i].start, l[i].line_no);
  772. X   else if (!r[leave_nr].active)
  773. X      error (Eleave_unpresent, l[i].start, l[i].line_no);
  774. X   else {
  775. X      r[leave_nr].leave_it = true;
  776. X      put_indent (out, startindent);
  777. X      fprintf (out, "goto %s_%d;",
  778. X               l[i].start, r[leave_nr].calls);
  779. X   }
  780. X
  781. X`insert normal line:
  782. X   put_line (out, &l[i], startindent - ref_startindent, `num level);
  783. X   
  784. X`num level:
  785. X  r[nr].semicolons == 0 ? 3 : 2
  786. X
  787. X`generate label:
  788. X  fprintf (out, "\n%s_%d: ;", `name, r[nr].calls);
  789. X  commanded_line_no++;
  790. X
  791. X`write closing klammer:
  792. X  int sc = r[nr].semicolons;
  793. X  if (sc > 0) {
  794. X     put_indent (out, startindent);
  795. X     putc ('}', out);
  796. X  }
  797. X  else {
  798. X     putc (')', out);
  799. X     if (z->type == refcallr_line)  /* semicolon has been removed illegaly */
  800. X        putc (';', out);
  801. X  }
  802. X
  803. X`name:
  804. X  z->start
  805. X}
  806. X
  807. X/************************* line_cmd **************************************/
  808. X
  809. Xstatic void line_cmd (out, nr, indent, min_level)
  810. X  FILE *out;
  811. X  int  nr;
  812. X  int  indent;
  813. X  int  min_level;
  814. X{
  815. X  /* Writes a "preprocessor #line directive" including file name if
  816. X     requested.
  817. X     Is suppressed, if min_level is less than numbering_level.
  818. X     Using numbering_level, option_indent, commanded_line_no and name_in
  819. X  */
  820. X  if (numbering_level >= min_level) {
  821. X     if (option_indent)
  822. X        put_indent (out, indent);
  823. X     else
  824. X        putc ('\n', out);
  825. X     fprintf (out, "#line %d \"%s\"", nr, modified_name_in);
  826. X     commanded_line_no = nr-1; /* #line 3  means: next comes line 3 ! */
  827. X  }
  828. X}
  829. X
  830. X/********************** put_indent **************************************/
  831. X
  832. Xstatic void put_indent (out, how_far)
  833. X  FILE *out;
  834. X  int how_far;
  835. X{
  836. X  putc ('\n', out);      /* begin newline */
  837. X  commanded_line_no++;
  838. X  if (!option_small)
  839. X     fwrite (blanks, how_far > 72 ? 72 : (how_far < 0 ? 0 : how_far),
  840. X             1, out);
  841. X}
  842. X
  843. X/*************************** put_line ***********************************/
  844. X
  845. Xstatic void put_line (out, line, additional_indent, min_level)
  846. X  FILE       *out;
  847. X  LINE_INFO  *line;    /* pointer for efficiency (is big object) */
  848. X  int        additional_indent;
  849. X  int        min_level;
  850. X{
  851. X  /* Writes the line 'line' to 'out' with the appropriate indentation 
  852. X     (which is the line's indentation plus additional_indent).
  853. X     If the current line numbering is not right a line_cmd is made before.
  854. X  */
  855. X  if (line->line_no != commanded_line_no + 1)
  856. X     line_cmd (out, line->line_no, line->indent + additional_indent,
  857. X               min_level);
  858. X  if (line->type == empty_line) {    /* for empty lines: nothing */
  859. X     putc ('\n', out);
  860. X     commanded_line_no++;
  861. X     return;
  862. X  }
  863. X  else if (option_small || (!option_indent && *line->start == '#')) {
  864. X     putc ('\n', out);
  865. X     commanded_line_no++;
  866. X  }
  867. X  else
  868. X     put_indent (out,
  869. X                 line->indent + additional_indent);  /* starts new line */
  870. X  assert (line->start != NULL);
  871. X  fputs (line->start, out);
  872. X#if debug
  873. X  fprintf (stdout, "put:\"%s\"\n", line->start);
  874. X#endif
  875. X}
  876. X
  877. X/********************** refinement_nr ************************************/
  878. X
  879. Xstatic int refinement_nr (name)
  880. X  char *name;
  881. X{
  882. X  /* computes the number of a refinement from its name 'name'.
  883. X     Uses r from 0 to r_pos. Returns the number or -1 if undeclared.
  884. X     If the refinement is declared more than once an error message is 
  885. X     generated.
  886. X  */
  887. X  int i, match = -1, matches = 0;
  888. X  assert (name != NULL);
  889. X  for (i = 0; i < r_pos; i++)
  890. X      if (!strcmp (name, r[i].name)) {
  891. X         match = i;
  892. X         matches++;
  893. X      }
  894. X  if (matches > 1)
  895. X     error (Eref_multi_decl, r[match].name, refdecl_line_nr (match));
  896. X  return (match);
  897. X}
  898. X
  899. X/********************* Auxiliary functions ******************************/
  900. X
  901. Xextern void copy_with_doubled_backslashes (string, copy)
  902. X  char *string, *copy;
  903. X{
  904. X  /* copies the string string to the location copy. All backslash
  905. X     characters (code 92) in string are copied twice, so for example
  906. X     "back\slas\\h" is copied to "back\\slas\\\\h".
  907. X     The purpose of this is to make the copy usable as a C string denoter,
  908. X     in which the backslash is interpreted as an escape symbol.
  909. X     No checks are made, thus there must be enough memory allocated
  910. X     to make the copy.
  911. X  */
  912. X  assert (string != NULL);
  913. X  assert (copy != NULL);
  914. X  while (*string != 0) {
  915. X     *copy = *string;
  916. X     string++;
  917. X     if (*copy == 92) {      /* is backslash ? */
  918. X       *(copy + 1) = 92;     /* then put another and */
  919. X       copy += 2;            /* proceed two bytes */
  920. X     }
  921. X     else                    /* else */
  922. X       copy++;               /* proceed one byte */
  923. X  }
  924. X  *copy = 0;
  925. X}
  926. X
  927. X
  928. Xstatic void reset_l_r_s ()
  929. X{
  930. X  /* Sets LINE_INFO- and REF_INFO-Arrays 'l' and 'r' into 
  931. X     their empty state.
  932. X  */
  933. X  int i;
  934. X  for (i = 0; i <= r_pos; i++) { /* Alle Refinements loeschen */
  935. X      r[i].name  = NULL;
  936. X      r[i].calls = 0;
  937. X  }
  938. X  s = s_root;                    /* Zeilenspeicher loeschen */
  939. X  l_pos = r_pos = old_level = 0;
  940. X}
  941. X
  942. X
  943. END_OF_FILE
  944. if test 30456 -ne `wc -c <'crefine.cr'`; then
  945.     echo shar: \"'crefine.cr'\" unpacked with wrong size!
  946. fi
  947. # end of 'crefine.cr'
  948. fi
  949. echo shar: End of shell archive.
  950. exit 0
  951.  
  952. exit 0 # Just in case...
  953.