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

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