🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: de.comp.sources.unix
1 messages
1 total messages Started by Frank Kaefer Thu, 06 Aug 1992 21:10
v01i011: Crefine - C language extension, Part03/06
#11
Author: Frank Kaefer
Date: Thu, 06 Aug 1992 21:10
1181 lines
41787 bytes
Submitted-by: prechelt@ira.uka.de (Lutz Prechelt)
Posting-number: Volume 1, Issue 11
Archive-name: crefine/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 6)."
# Contents:  crefine/cr_getln.cr crefine/crefine.1
# Wrapped by fkk@stasys on Thu Aug  6 22:49:34 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'crefine/cr_getln.cr' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'crefine/cr_getln.cr'\"
else
echo shar: Extracting \"'crefine/cr_getln.cr'\" \(18326 characters\)
sed "s/^X//" >'crefine/cr_getln.cr' <<'END_OF_FILE'
X/*************************************************************************
XProject : C-Refine Precompiler
XModule  : Line Scanner
XAuthor  : Lutz Prechelt, Karlsruhe
XDate    : 08.05.92  Version 17
XCompiler: C, C-Refine
X**************************************************************************/
X/*
X    Copyright (C) 1988,89,90,91 by Lutz Prechelt, Karlsruhe
X
X    This program is free software; you can redistribute it and/or modify
X    it under the terms of the GNU General Public License as published by
X    the Free Software Foundation; either version 1, or (at your option)
X    any later version.
X    This program is distributed in the hope that it will be useful,
X    but WITHOUT ANY WARRANTY; without even the implied warranty of
X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X    GNU General Public License for more details.
X    You should have received a copy of the GNU General Public License
X    along with this program; if not, write to the Free Software
X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X*/
X
X/************************************************************************
X*********************** C - R e f i n e *********************************
X*************************************************************************/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#include "cr_decl.h"  /* globale Funktionen, Typen und Daten */
X
X/******************* lokale Funktionen ************************************/
X
Xstatic void  push_refinement_name A(());
Xstatic int   normal_scanner A((LINE_INFO*));
Xstatic int   comment_scanner A((LINE_INFO*));
Xstatic int   text_scanner A((LINE_INFO*));
Xstatic int   char_scanner A((LINE_INFO*));
Xstatic int   preprocessor_scanner A((LINE_INFO*));
X
X/*************************** defines ***************************************/
X
X#define push(ch) ((*((s)++)) = (char)(ch))
X
X#define leave_sequence    "leave"   /* e.g. "leave" (no leading blank!) */
X#define leave_sequence_length  5
X
X#define normal_end_of_line       1   /* real end of line */
X#define continueing_end_of_line  2   /* logical end of line */
X#define refinementsymbol_found   3
X#define leave_keyword_found      4
X
X/*********************** Lokale Daten ************************************/
X
X/***** one line buffer *****/
Xstatic char *act;             /* current position in b */
X
X/***** Control *****/
X#if ansi
Xstatic int (*scanner) (LINE_INFO*);
X#else
Xstatic int (*scanner) ();
X#endif
X/***** Status *****/
Xstatic int  level,                 /* brace-nesting */
X            just_was, event,       /* event memory */
X            semicolon_count,
X            lines_in_denoter,
X            old_indent;
X
X/*********************** init_scanner ************************************/
X
Xextern void init_scanner ()
X{
X  /* Initializes the state of this module */
X  level = 0;
X  just_was = event = normal_end_of_line;
X  scanner = normal_scanner;
X}
X
X/*********************** get_line ****************************************/
X
Xextern void get_line (fp, l, semicolons)
X  FILE       *fp;
X  LINE_INFO  *l;
X  int        *semicolons;  /* is increased only ! */
X{
X  /* Reads on line from file fp and sets up l accordingly.
X     The preprocessed line is copied to *s and s is increased appropriately.
X     (A null terminator is appended.)
X     The line is a complete line only, if there is no refinement involved 
X     with that line:
X     For refinement calls and refinement declaration headers a separate line
X     is generated.
X     At end of file stop_processing is set to true. Problems yield a 
X     message and let 'errors' or 'warnings' increase.
X     This function uses the option indicator variables, and the variables
X     line_no and commanded_line_no.
X  */
X  charp old_s = s;    /* store s to compute length later */
X  bool stop = false;
X  bool three_witches;
X  semicolon_count = 0;
X  `init l;
X  if (just_was == normal_end_of_line) {
X     `read line;
X     `get indent;
X  }
X  else {                       /* continued line */
X     l->indent = old_indent;
X     l->line_no = line_no;
X  }
X  `handle line;
X
X`init l:
X#if debug
X  printf ("get_line:");
X#endif
X  l->level   = level;   /* level is defined as level at start of line! */
X  l->start   = s;
X  l->indent  = 0;
X  l->type    = normal_line;
X
X`read line:
X  l->line_no = ++line_no;
X  act = (char*)fgets (b, b_size, fp);  /* get next line*/
X#if debug
X  printf ("->%s<-", act == NULL ? "(NULL)" : (char*)act);
X#endif
X  if (act == NULL) {                /* check for EOF */
X     stop_processing = true;
X     l->type = empty_line;
X     if (level > 0)
X        error (Eeof_brace, NULL, line_no);
X     if (scanner == comment_scanner)
X        error (Eeof_comment, NULL, line_no);
X     if (scanner == text_scanner)
X        error (Eeof_string, NULL, line_no);
X     if (scanner == char_scanner)
X        error (Eeof_char, NULL, line_no);
X     return;
X  }
X
X`get indent:
X   while (!stop)
X      if (*act == ' ') {
X         l->indent++;
X         act++;
X      }
X      else if (*act == TAB) {    /* expand Tabs */
X         l->indent = (l->indent/tabsize + 1) * tabsize;
X         act++;
X      }
X      else
X         stop = true;
X   old_indent = l->indent;    /* store for next call */
X
X`handle line:
X   three_witches = l->indent == 0 && level > 0 && scanner == normal_scanner;
X   if (three_witches && (int)*act == refinementsymbol)
X        `handle_refinement_declaration;
X   else {
X      `check column 0;
X      if (just_was != refinementsymbol_found &&
X          just_was != leave_keyword_found)
X         event = (*scanner) (l);
X      `handle_event;
X      if (option_small || event == normal_end_of_line)
X        `delete trailing blanks;
X   }
X   l->length = s - old_s;
X   if (l->length == 0)
X      l->type = empty_line;
X   push (0);  /* String Terminator */
X   `perhaps warn for level changes;
X   assert (!(l->type == refdecl_line && semicolon_count != 0));
X   *semicolons += semicolon_count;
X
X`handle_refinement_declaration:
X   act++;                     /* skip refinementsymbol */
X   push_refinement_name ();
X   if (*act != ':')
X      error (Erefdecl_syntax, act, line_no);
X   else
X      act++;
X   if (level > 1)
X      error (Erefdecl_nested, NULL, line_no);
X   l->type = refdecl_line;
X   just_was = (*act == '\n' || *act == 0) ? normal_end_of_line :
X                                            continueing_end_of_line;
X
X`check column 0:
X  if (three_witches && !iscntrl (*act) &&
X      just_was != continueing_end_of_line &&
X      *act != '}' && *act != '#' && *act != '*' && *act != '/')
X     warning (Wcol0, act, line_no, 1);
X
X`handle_event:
X  if (event == refinementsymbol_found || event == leave_keyword_found)
X     `handle refinementcall or leave;
X  else
X     just_was = normal_end_of_line;
X
X`handle refinementcall or leave:
X   if (s - old_s == 0) {        /* line empty */
X      push_refinement_name ();
X      l->type = event == leave_keyword_found ? leave_line : refcall_line;
X      `skip semicolon and blanks;
X      just_was = (*act == 0 || *act == '\n') ? normal_end_of_line :
X                                               continueing_end_of_line;
X   }
X   else
X      just_was = event;
X
X`skip semicolon and blanks:
X   if (*act == ';') {        /* skip semikolon if present */
X      act++;
X      semicolon_count++;
X      if (l->type == refcall_line)
X         l->type = refcallr_line;   /* note the removed ";" */
X   }
X   while (*(act++) == ' ')   /* skip following blanks */
X           ;
X   act--;                    /* recover char after last blank */
X
X`delete trailing blanks:
X   while (*(s-1) == ' ')      /* remove trailing blanks */
X     s--;
X
X`perhaps warn for level changes:
X   int lev = level;
X   if (lev < 0) {  /* Syntax error!  (or C-Refine does not work...) */
X      if (option_anyway)
X         error (Emany_braces, NULL, line_no);
X      else
X         fatal_error (Emany_braces, NULL, line_no);
X   }
X   else if (lev > 5 && level > l->level)
X         warning (Wnesting, NULL, line_no, 3);
X   else if (l->indent > 35 && `is refcall && !option_small)
X         warning (Wmuch_indent, NULL, line_no, 3);
X
X`is refcall:
X   l->type == refcall_line || l->type == refcallr_line
X}
X
X/********************** push_refinement_name *******************************/
X
Xstatic void push_refinement_name ()
X{
X  /* reads input using 'act' and generates output using 's'.
X     reads all following blanks, letters, digits and underscores (that is,
X     stops on other characters) and generates from that a C identifier
X     on the output by suppressing leading and trailing blanks.
X     With option_ibmchars the Umlaute and Accentcharacters from the
X     IBM International Charset are also allowed.
X  */
X#define is_legal(ch)  (isalnum(ch) || (ch) == ' ' || ch == '_' || \
X                       (option_ibmchars && \
X                           (((ch) >= 128 && (ch) <= 167)) || (ch) == 225))
X  int ch;
X  charp old_s = s, start = s;
X  `suppress leading blanks;
X  `copy legal chars;
X  `suppress trailing blanks;
X  assert (*(s-1) != ' ');
X  assert (*old_s != ' ');
X  assert (s - old_s >= 0);
X  `change inner blanks to underlines;
X  if (s - old_s == 0)
X     error (Erefname_missing, act, line_no);
X
X`suppress leading blanks:
X   while (*act == ' ')               /* suppress leading blanks */
X     act++;
X
X`copy legal chars:
X   do {                              /* copy legal chars */
X     ch = *(act++);
X     push (ch);
X   }
X   while (is_legal (ch));
X   s--; act--;                       /* unpush illegal last char */
X
X`suppress trailing blanks:
X   while (*(s-1) == ' ' && s > old_s) /* suppress trailing blanks */
X      s--;
X
X`change inner blanks to underlines:
X   for (start++; start < s; start++) /* change inner blanks to underlines */
X     if (*start == ' ')
X        *start = '_';
X#undef is_legal
X}
X
X/***********************  S C A N N I N G  *********************************/
X
X#define q    39      /* Quote */
X#define dq   34      /* Double-Quote */
X
X/*********************** normal_scanner ***********************************/
X
Xstatic int normal_scanner (l)
X  LINE_INFO *l;
X{
X  /* Changes to reading comments, strings, quoted chars or preprocessor
X     directives as necessary.
X     Ends only at the end of a line.
X     Tries to identify refinement calls and refinement declarations;
X     in these cases the lines are reduced to only the refinement name.
X  */
X  register int ch;
X  for (;;) {
X    ch = *(act++);
X    switch (ch) {
X      case '\n':
X      case 0   : return (normal_end_of_line);
X      case '/' : if (*act == '*')              /* start of comment ? */
X                    `handle normal comment;
X                 else if (*act == '/' && option_cplusplus)
X                    `handle doubleslash style comment;
X                 else                           /* No --> normal */
X                    push (ch);
X                 break;
X      case dq  : `handle text denoter;
X      case q   : `handle char denoter;
X      case '#' : `handle preprocessor directive;
X      case ';' : semicolon_count++;
X                 push (';');
X                 break;
X      case '{' : level++;
X                 push (ch);
X                 break;
X      case '}' : level--;
X                 push (ch);
X                 break;
X      default  :
X                 if (ch == refinementsymbol)
X                   `check for leave or refinement call;
X                 else
X                   push (ch);
X    }
X  }
X
X`handle normal comment:
X   if (!option_small) {
X      push (ch); push ('*');
X   }
X   act++;
X   scanner = comment_scanner;
X   return ((*scanner) (l));
X
X`handle doubleslash style comment:
X   if (option_small)
X      return (normal_end_of_line);   /* just pgnore rest of line */
X   push (ch); push (ch);             /*  put  //   */
X   act++;
X   while (*act != '\n' && *act != 0)   /* put rest of line */
X      push (*(act++));
X   return (normal_end_of_line);
X
X`handle text denoter:
X   push (ch);
X   scanner = text_scanner;
X   lines_in_denoter = 0;
X   return ((*scanner) (l));
X
X`handle char denoter:
X   push (ch);
X   scanner = char_scanner;
X   lines_in_denoter = 0;
X   return ((*scanner) (l));
X
X`handle preprocessor directive:
X   push (ch);
X   scanner = preprocessor_scanner;
X   return ((*scanner) (l));
X
X`check for leave or refinement call :
X   /* Precondition: Refinement symbol found, 'act' is right behind it.
X      if a 'leave' surrounded by blanks is found in front of the 
X      refinement symbol, it and its blanks are stripped and 
X      leave_keyword_found is returned.
X      Otherwise refinementsymbol_found gemeldet is returned
X   */
X   charp old_s = s--;
X   while (*s == ' ')
X      s--;
X   s++;
X   if (!memcmp (s - leave_sequence_length, leave_sequence,
X                leave_sequence_length)) {
X      s -= leave_sequence_length;     /* Remove leave_sequence from Output */
X      return (leave_keyword_found);
X   }
X   else {
X      s = old_s;
X      return (refinementsymbol_found);
X   }
X}
X
X/********************* comment_scanner *************************************/
X
Xstatic int comment_scanner (l)
X  LINE_INFO *l;
X{
X  /* Precondition: position is right behind a start of a comment 
X     (which is already copied if not option_small is true)
X     Postcondition: position is right after a comment end.
X  */
X  register int ch;
X  for (;;) {
X    ch = *(act++);
X    switch (ch) {
X      case '\n':
X      case 0   : return (normal_end_of_line);
X      case '*' : if (*act == '/')       /* end of comment : */
X                    `handle comment end;
X                 /* no break ! */
X      default  : if (!option_small)
X                    push (ch);
X    }
X  }
X
X`handle comment end:
X   if (!option_small) {
X      push (ch); push ('/');
X   }
X   act++;
X   scanner = normal_scanner;   /* change to normal scanner */
X   return ((*scanner) (l));    /* and continue scanning */
X
X}
X
X/********************* text_scanner *************************************/
X
Xstatic int text_scanner (l)
X  LINE_INFO *l;
X{
X  /* Precondition: position is right behind the (already copied) 
X                   double quote that starts a string denoter 
X                   (string literal)
X     Postcondition:position is right behind the closing double
X                   quote of a string denoter
X  */
X  register int ch;
X  lines_in_denoter++;
X  for (;;) {
X    ch = *(act++);
X    switch (ch) {
X      case '\n':
X      case 0   : return (normal_end_of_line);  /* allowed ??? */
X      case dq  : `end of stringdenoter;
X      case '\\': push (ch);
X                 if (*act == dq || *act == '\\') {
X                    push (*act);
X                    act++;
X                 }
X                 break;
X      default  : push (ch);
X    }
X }
X
X`end of stringdenoter:
X   push (ch);
X   if (lines_in_denoter > 1)
X      warning (Wlong_string, act-1, line_no,
X               lines_in_denoter > 5 ? 1 : 2);
X   scanner = normal_scanner;
X   return ((*scanner) (l));
X
X}
X
X/********************* char_scanner *************************************/
X
Xstatic int char_scanner (l)
X  LINE_INFO *l;
X{
X  /* Is analogous to text scanner, but uses single quote instead of double
X     quote.
X  */
X  int ch;
X  lines_in_denoter++;
X  for (;;) {
X    ch = *(act++);
X    switch (ch) {
X      case '\n':
X      case 0   : return (normal_end_of_line);  /* allowed ??? */
X      case q   : `end of chardenoter;
X      case '\\': push (ch);
X                 if (*act == q || *act == '\\') {
X                    push (*act);
X                    act++;
X                 }
X                 break;
X      default  : push (ch);
X    }
X  }
X
X`end of chardenoter:
X   push (ch);
X   if (lines_in_denoter > 1)
X      warning (Wlong_char, act-1, line_no,
X               lines_in_denoter > 5 ? 1 : 2);
X   scanner = normal_scanner;
X   return ((*scanner) (l));
X
X}
X
X/********************* preprocessor_scanner ******************************/
X
Xstatic int preprocessor_scanner (l)
X  LINE_INFO *l;
X{
X  /* Scans a line with a preprocessor directive on it.
X     If this line contains a #line directive, reads the line number and
X     file name and sets line_no and name_in accordingly. 
X     This scanner is called immediately after the # has been seen.
X     The line is copied verbatim.
X  */
X  int ch;
X  ch = *(act++);
X  `skip whitespace;
X  `try to read line command;
X  `copy rest of line;
X  
X`skip whitespace:
X   for (;;) {
X     switch (ch) {
X       case ' ' :
X       case TAB : push (ch);
X                  break;
X       case '\n':
X       case 0   : scanner = normal_scanner;
X                  return (normal_end_of_line);
X       default  : leave `skip whitespace;
X     }
X     ch = *(act++);
X   }
X
X`try to read line command:
X   /* precondition:  ch = <first nonwhitespace character after '#' >
X      postcondition: ch = <first char not belonging to line command>
X   */
X   `read the command token;
X   `skip whitespace;
X   `read the line number;
X   `skip whitespace;
X   `read the filename;
X  
X`read the command token:
X   /* ch = <first nonwhitespace character after '#' > */
X   if (strncmp ("line", act, 4)) {
X     if (!isdigit (ch))
X       leave `try to read line command;
X   }
X   else {
X     push (*(act++));
X     push (*(act++));
X     push (*(act++));
X     push (*(act++));
X     ch = *(act++);
X     if (ch != ' ' && ch != TAB)  /* 'line<something> without whitespace */
X       leave `try to read line command;
X   }
X
X`read the line number:
X   int number = 0;
X   while (isdigit (ch)) {
X     push (ch);
X     number = 10*number + (ch - '0');
X     ch = *(act++);
X   }
X   line_no = commanded_line_no = number - 1;
X
X`read the filename:
X   bool has_quotes = ch == '\"';
X   char *current_letter = name_in;
X   if (has_quotes) {
X     push (ch);
X     ch = *(act++);
X   }
X   for (;;) {
X     switch (ch) {
X       case '\n':
X       case 0   : `terminate name_in;
X                  if (has_quotes)
X                    warning (Eunterminated, name_in, line_no, warning_level);
X                  scanner = normal_scanner;
X                  return (normal_end_of_line);
X       case dq  : `terminate name_in;
X                  leave `read the filename;
X       default  : push (ch);
X                  *(current_letter++) = ch;
X     }
X     ch = *(act++);
X   }
X
X`terminate name_in:
X   if (current_letter != name_in)  /* if new name present */
X     *current_letter = 0;  /* terminate name */
X   copy_with_doubled_backslashes (name_in, modified_name_in);
X
X`copy rest of line:
X   for (;;) {
X     switch (ch) {
X       case '\n':
X       case 0   : scanner = normal_scanner;
X                  return (normal_end_of_line);
X       default  : push (ch);
X     }
X     ch = *(act++);
X   }
X
X}
X
END_OF_FILE
if test 18326 -ne `wc -c <'crefine/cr_getln.cr'`; then
    echo shar: \"'crefine/cr_getln.cr'\" unpacked with wrong size!
fi
# end of 'crefine/cr_getln.cr'
fi
if test -f 'crefine/crefine.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'crefine/crefine.1'\"
else
echo shar: Extracting \"'crefine/crefine.1'\" \(18721 characters\)
sed "s/^X//" >'crefine/crefine.1' <<'END_OF_FILE'
X.TH CREFINE 1 "12 June 1992"
X.SH NAME
Xcrefine \- refinement preprocessor for C and C++
X.SH SYNOPSIS
X.B crefine
X[
X.B options
X]
X.I inputfile ...
X.SH DESCRIPTION
X.B crefine (C-Refine)
X(spoken like 'see refine') is a preprocessor that adds a new language
Xconstruct to C and C++: the 
X.I refinement.
Xcrefine massages source code files to produce plain C output from
XC input with refinements or plain C++ from C++ with refinements and so on.
XThe syntax of refinements is described in the USAGE section.
XThe name of the
Xoutput file, if not given explicitly with option -o,
Xis derived from the name of the input file by removing its last
Xcharacter, if that is an 
X.B r
X(which is the filename convention for C\-Refine).
XStdin and stdout can be referenced as '-'
XError messages go to the standard output. The startup message,
Xif not suppressed, goes to standard error.
X
XC\-Refine does not act in any way upon the directives for the
XC preprocessor (except #line). 
XThis especially means that include files have to be 
Xprocessed separately. Usually, this will not be necessary, since they do
Xnot typically contain anything that C\-Refine should work on.
XA second consequence is, that it is possible for C\-Refine to give error
Xmessages on correct programs, because it does not see the effects of 
Xrunning the preprocessor. In these cases you either have to change your 
Xsource code or run the C preprocessor before C\-Refine. In the latter case, 
XC\-Refine will correctly process the #line directives that the
Xpreprocessor inserts into your code in its output and thus give you
Xmessages with the correct line numbers.
X.SH OPTIONS
X.TP
X.B \-a
Xanyway. Normally, if any error was detected by C\-Refine, the output file 
Xwill automatically be deleted. This option says not to do so.
X.TP
X.B \-c
Xcomment refinement names in the output. Any inserted 
Xrefinement body in the output is titled by a comment giving the refinement
Xname and the refinement nesting level.
X.TP
X.B \-i
Xindent the 
X.I #line
Xdirectives in the resulting output to the appropriate
Xindentation level as indicated by the nesting of refinements. Not an 
Xespecially important option, but since this is a true UNIX program, it is
Xpresent anyway.
X.TP
X.B \-l
Xlist all refinement names.
XThe names of all processed refinements are listed
Xto the standard output along with their line numbers. 
XI do not know exactly what this option may be good
Xfor, but I believe someday somebody will need it.
X.TP
X.B \-m<ch>
Xmessage language. Originally, C\-Refine was written by a typical german
Xprogrammer in the typical german programmer schizophrenia situation: 
Xas a german the native tongue is german,
Xas a programmer the native tongue is
Xenglish. So both languages were supported for the error messages.
XUse -mg for German and -me for English (which is the default).
XEven worse, since I believe the whole data processing world is much too
Xserious, I liked to have a somewhat humorous version either.
XUse -mG for german humorous messages, and -mE for english humorous messages.
X.TP
X.B \-n<num>
Xnumbering with
X.I #line
Xcommands. By default, every insertion of a
Xrefinement body is accompanied by a #line preprocessor directive in the 
Xoutput. This is the default numbering level 3.
XBy giving a smaller number just after the option character
X.B n
X, the amount of
X.I #line
Xdirectives used can be 
Xreduced (level 2 or 1) or set to zero (level 0). What is best depends on 
Xthe behavior of your local C or C++ compiler.
XJust try it out, beginning with the default level 3.
X.TP
X.B \-o<string>
Xset name of output file explicitly. Normally, the name of the output file
Xis the name of the input file with an 'r' stripped off of the end (and 
Xstdout when input is stdin). This can be overridden with this option.
X.TP
X.B \-p
Xplus. The C++ mode. The only difference between C mode and C++ mode for
XC\-Refine is, that in C++ mode the C++ doubleslash comment convention is
Xobeyed, while in C mode it is not. This is possible because C\-Refine knows
Xvery little about the actual syntax of these two languages.
XSo in most cases, this difference makes no difference at all.
X.TP
X.B \-v
Xverbose mode. Makes C\-Refine display a startup message.
X.TP
X.B \-r<ch>
Xrefinement symbol. Select what character shall be recognized as the 
Xrefinement symbol in the input file. The character to chose must be given
Xon the command line after the option character
X.B r.
XThis is the
Xbackquote (ASCII code 95) by default. Since there are only two printable
XASCII characters that are unused in the syntax of C (the backquote, 
Xcode 96, and the dollar or currency sign, code 36) there is very little 
Xchoice on a machine with 7 bit character set. This choice is further 
Xrestricted because on some systems (such as VMS) the dollar sign is
Xacutally being allowed and used for identifiers.
XSome more possiblilities arise when having an 8 bit character set, such
Xas the IBM international character set (proposed symbol there is the
Xlittle double right angle bracket, code 175, which really looks nice),
Xbut take into account that any change in refinement symbol is bad
Xfor the portability of your source files.
XNote that some characters have to be quoted in the shell.
X.TP
X.B \-R<num>
Xrefinement symbol. Same as before, but the new symbol is given by its
Xcharacter code instead of by itself.
X.TP
X.B \-s
Xstrip. Produces smaller output by stripping of all indentation, whether
Xpresent in the input or generated by C\-Refine, and all comments.
XThis is on by default. To switch it off, use the syntax 
X.B \-s\-
X.TP
X.B \-w<num>
Xwarning level. C\-Refine is able to give various warnings about your
Xsource code. These can be suppressed in three stages. The default warning
Xlevel is 3 (all warnings). You can chose any level from 0 (no warnings)
Xto 3 by giving the appropriate number after the option character
X.B w
Xon the command line.
X.TP
X.B \-B<num>
Xbuffer. Select the size of the source code buffer (in bytes)
Xin which C\-Refine holds the
Xcode for a function while processing it. The default is 150000 bytes.
X.TP
X.B \-E<num>
Xerrors. Select the maximum number of errors that may occur in the input
Xbefore C\-Refine stops processing prematurely. The default is 20.
X.TP
X.B \-L<num>
Xlines. Select the maximum number of source code lines per single function
Xthat C\-Refine is able to hold. The default is 2500. 
X.TP
X.B \-M<num>
Xmaximum number of characters per line.
XThe default is 500.
X.TP
X.B \-N<num>
Xnumber of refinements per function.
XSelects the maximum number of refinement
Xdeclarations that may be present within any single function. 
XThe default is 200.
X.TP
X.B \-P<num>
Xinterval of progress display. For the homo ludens in the programmer or people
Xwith incredibly overloaded machines.
XAfter every <num> lines of processing C\-Refine echoes the current
Xline number to stdout.
XThe default is 0, which means that this function is suppressed.
X.TP
X.B \-T<num>
Xtab size. Select the number of spaces to which a TAB character expands.
XC\-Refine expands all TAB characters at the beginning of a line, i.e. those
Xthat act as indentation. Other TABs are left untouched. The default is 1.
X.TP
X.B \-W<num>
Xwarnings. Select the maximum number of warnings that may occur
Xbefore C\-Refine stops processing prematurely. The default is 30.
X.TP
X.B \-\-
Xindicate 'end of options'. You may use a dash as the input filename
X(to use C\-Refine as a filter from standard input to standard output),
Xbut it can be recognized only after you have used a double dash to
Xindicate that it is not an option.
X.SH USAGE
XThere are three new syntactic elements with C\-Refine:
Xthe refinement definition, the refinement call and the leave construct.
XThe purpose of refinements is to support
Xthe Top\-Down style of programming
X(a) within a function and (b) in both, thinking and writing.
XEssentially, refinements are just parameterless macros with
Xlong descriptive names.
XRefinements are in any case local to a function. They may be called 
Xbefore they are declared; declaration and definition of a 
Xrefinement are one.
XThe syntax of refinements as defined by C\-Refine is
X.I not
Xformat free, but lays significance upon whether a special symbol (the
Xrefinement symbol) is occuring in column 0 or somewhere else.
X
XAlong with the new language constructs are some layout restrictions
Xfor the program text being defined. This is necessary, because (a) the
Xsyntax of the refinement constructs breaks basic syntactic rules of C and
X(b) the C\-Refine preprocessor relies on some simple formatting rules, so
Xits algorithms can be kept simple and the whole thing small, portable,
Xrobust, reliable, and fast.
X
XHere are the (very informal) descriptions of the syntax and semantics of
Xthe language elements introduced by C\-Refine:
X.TP
Xrefinement names
XA 
X.I refinement name
Xis just a normal C identifier, with one important addition:
Xblanks are allowed within (!)
Xit (i.e. anywhere after the first nonblank character
Xof the name and before the last nonblank one); they are equivalent to
Xunderscores. The end of a refinement name is always detected by the
Xappearence of a special symbol, typically a semicolon, a colon or an
Xoperator.
XA refinement name must, however, be on a single line.
X.TP
X.B refinement calls
XA
X.I refinement call
Xconsists of the refinement symbol, immediately followed
Xby a refinement name. The refinement symbol must not be in colums 0 of the
Xsource line. Refinement calls are principally allowed anywhere within 
Xa function. The called refinement must be defined in that function, although
Xthe definition may (and usually will) appear later than the call.
XThe semantics of a refinement call is as follows:
XA 
X.I procedural refinement
X(i.e. one that contains at least one semicolon in
Xits body) is inserted instead of its call, surrounded by a pair of curly 
Xbraces. This insertion is recursively applied to nested refinements.
XA 
X.I valued refinement
X(i.e. one that contains just an expression and no 
Xsemicolon in its body) is inserted instead of its call, surrounded by 
Xa pair of parentheses.
XThis insertion is recursively applied to nested valued refinements.
XSo procedural refinements can be called anywhere where a block statement is
Xlegal. Valued refinements can be called anywhere where a parenthesed 
Xexpression is legal.
XAn illegal form of refinement call will be detected by C\-Refine.
X.TP
X.B refinement definitions
Xa refinement definition consists of the refinement symbol, immediately 
Xfollowed by a refinement name, followed by a colon. 
XThe refinement symbol must be in column 0 of the
Xsource line. Refinement definitions are allowed only on block nesting
Xlevel 1, i.e. in the outermost block of a function.
XThe body of a refinement is examined to decide what type of
Xrefinement it is:
XAll refinements that contain one or more semicolons in their body,
Xthat are not part of a comment, character denoter or string denoter, 
Xare called
X.I procedural refinements,
Xsince they contain statements.
XAll other refinements are called
X.I valued refinements,
Xsince they only contain an expression and thus return a value.
XIllegal syntax of a refinement declaration and the declaration of 
Xrefinements that are never used will be detected by C\-Refine.
X.TP
X.B leave
XThe 
X.I leave construct
Xmay be used from within any procedural refinement at any place where a 
Xstatement is legal. It consists of the keyword
X.B leave
Xfollowed by the refinement symbol, followed by a refinement name
X.I ref.
XThe semantics of this construct is, that a 
X.I goto
Xstatement is inserted instead of the leave construct, that jumps to
Xa point right after the last statement of the refinement 
X.I ref.
XFor this to be legal
X.I ref
Xmust be present in the current static nesting of refinement calls.
XThis means that not only the current refinement can be left with 
X.I leave,
Xbut any number of refinements that are statically nested at that point
Xof your code. Illegal use of the leave construct is detected by C\-Refine.
X
XAs by now, I assume, almost any understanding that may initially have been
Xthere, will probably have vanished. I will try to get it back to you by 
Xmeans of the following example. This is a (very simple\-minded) version
Xof the Sieve of Eratosthenes. It should not be thought that I believe the
Xrefinement technique to be especially well suited to this problem, but this
Xwas the smallest 'real' problem I could think of to demonstrate at least
Xmost of what the possibilities of C\-Refine are. So here it is:
X
X.nf
X#define MAX        10000
X#define PRIME      0
X#define NON_PRIME  1
X
Xstatic int sieve[MAX+1];
X
Xint main ()
X{
X  `initialize;
X  `do sieve;
X  `make output;
X  return (0);
X  
X`initialize:
X  int current;
X  for (current = 2; current <= MAX; current++)
X    sieve[current] = PRIME;
X    
X`do sieve:
X  int current_prime = 1;
X  for (;;) {
X    `find next bigger prime;  /* perhaps STOP here */
X    `delete all multiples of current_prime;
X  }
X
X`find next bigger prime:
X  int current_candidate = current_prime + 1;
X  while (sieve[current_candidate] == NON_PRIME)
X    if (current_candidate == MAX)
X      leave `do sieve;    /* leave two refinements at once */
X    else
X      current_candidate++;
X  /* now current_candidate is a prime (or we leave `sieve) */
X  current_prime = current_candidate;
X  
X`delete all multiples of current_prime:
X  int current = `first multiple of current_prime;
X  while (current <= MAX) {
X    sieve[current] = NON_PRIME;
X    current += current_prime;
X  }
X  
X`first multiple of current_prime:
X  2 * current_prime
X
X`make output:
X  int current;  /* different from 'current' above */
X  printf ("The primes between 2 and %d are\\n", MAX);
X  for (current = 2; current <= MAX; current++)
X    if (`current is prime)
X      printf ("%5d ", current);
X
X`current is prime:
X  sieve[current] == PRIME
X
X} /* end of main() */
X
X/***** End of example *****/
X.fi
XTo make the self documentation aspect of C\-Refine more clear, look at
Xthe following example: A function that tests, whether its parameters
Xform a pythagorean triple:
X.nf
Xbool pythagorean (int x, int y, int z)
X{
X  return (`all legs positive && `one is hypotenuse)
X  
X`all legs positive:
X   x > 0  &&  y > 0  &&  z > 0
X
X`one is hypotenuse:
X  `x is hypotenuse || `y is hypotenuse || `z is hypotenuse
X  
X`x is hypotenuse:
X  x*x == y*y + z*z 
X
X`y is hypotenuse:
X  y*y == x*x + z*z
X
X`z is hypotenuse:
X  z*z == x*x + y*y
X  
X}
X.fi
XThis is good style: you write down just what you want to express and
Xwith an optimizing compiler such code will also be perfectly efficient.
XTry to imagine what this would have looked like, if it had all been 
Xin a single parenthesesed expression.
X.SH FILES
X.PD 0
X.TP 18
Xcrefine
Xthe executable program
X.TP
Xfilename.cr
XC\-with\-refinements input file.
X.TP
Xfilename.c
XC output file.
X.TP
Xfilename.ccr
XC++\-with\-refinements input file.
X.TP
Xfilename.cc
XC++ output file.
X.PD
X.SH EXAMPLES
X.TP
Xcrefine firsttest.cr
Xprocess the input file firsttest.cr producing the output file firsttest.c
X.TP
Xcrefine -p+ -q+ -o outfile -w 2 next.ccr
Xprocess the C++\-Refine inputfile next.ccr producing the output file outfile.
XThe startup message is suppressed, C++ mode is selected and the 
Xwarning level is reduced to 2.
X.TP
Xcrefine -pqw2 -ooutfile next.ccr
Xsame as before.
X.TP
Xcrefine -o outfile -p+a-l-qw2 next.ccr
Xsame as before.
X.TP
Xcrefine -c -s- -n0 -T8 last.cr
Xprocess the inputfile last.cr in order to get a readable C source.
XComments and indentation are not stripped, inserted refinement bodies 
Xare tagged by an additional comment giving the refinement name,
Xall 
X.I #line
Xpreprocessor directives are left out and leading tabs expand
Xto 8 spaces.
X.TP
Xcrefine -cs-n0T8 last.cr
Xsame as before.
X.SH DIAGNOSTICS
XThe warnings and error messages are intended to be self explanatory. If you
Xdo not understand one of them anyway: chose a different language for
Xthe messages (see option \-m), get yourself a dictionary or interpreter and
Xtry again.
X.SH SEE ALSO
Xcc(1), ccr(1), cpp(1), make(1)
X.SH BUGS
XSince preprocessor directives are not handled by C\-Refine, strange things 
Xcan happen if you use #ifdef or #if. This is especially the case if you
Xuse these directives to put large comments into your source files: if there
Xare any comments or string literals (double quotes) or char 
Xliterals (single quotes) beginning in that area that are not properly 
Xclosed within it, C\-Refine will run to nirvana searching for their end and 
Xgive you lots of wrong error and warning messages.
XWatch out for apostrophes (e.g. in "don't") especially!
X.LP
XThose people, who use such stupid macros as
X.nf
X   #define BEGIN {
X   #define END   }
X.fi
Xor similar craizy stuff, will have to change their habits or run the 
Xpreprocessor first in order to use C\-Refine.
X.LP
XWhen using a call to a value returning refinement as a parameter
Xto a macro, most preprocessors will complain the #line directive 
Xwhen numbering level 3 is being used. -n2 or -n1 can be used to
Xovercome this problem although this may be a bit unsatisfactory.
X.LP
XThe output of C\-Refine may be code that exceeds certain compiler limits of
Xyour C or C++ compiler. Since the body of every procedural refinement is
Xenclosed in a block and the body of every value returning refinement is
Xenclosed in parentheses, the block nesting limits or expression complexity 
Xlimits of your compiler may be reached when you make very heavy use of
Xnested refinements.
X.LP
XSome compilers may handle the #line directive improperly, yielding wrongly
Xtagged error messages. Bad luck.
X.LP
XProbably C\-Refine will also work with Objective\-C,
Xbut I am not absolutely sure about that. Perhaps somebody will give 
Xme some feedback on this issue ?
X.LP
XThere should be a mode to use C\-Refine for Lisp also.
X.LP
XAnd for several other languages, too.
X.LP
XC\-Refine reacts poor on some types of syntactic errors.
X.LP
XC-Refine will not work good if your filenames contain certain strange
Xcharacters (e.g. double quotes).
X.LP
XIn C++, when a "leave" has to jump across a variable initialization, some 
Xcompilers will complain, that the goto is illegal. This is not true, 
Xbecause the goto jumps to (or even beyond) the very end of the block 
Xwhere that variable is in
X[precisely: the jump is to an empty statement, which is the last statement
Xin the block], but these compilers do not recognize that fact.
X.LP
XYou must have C\-Refine in order to be able to use refinements.
XThis is actually not a bug in C\-Refine but in your compiler.
X.LP
XAlthough much easier than without, programming is still difficult
Xeven with C\-Refine.
XThis is a bug in you. Contact darwin@nirvana.edu or 
Xroot@headquarter.heaven.gov for complaints.
X.SH VERSION
XThis manpage is for C\-Refine Version 3.0 (internally named Version 17)
X.SH AUTHOR
X.nf
XLutz Prechelt  (prechelt@ira.uka.de)
XInstitut fuer Programmstrukturen und Datenorganisation
XUniversitaet Karlsruhe
XD-7500 Karlsruhe
XGermany
X
X.fi
END_OF_FILE
if test 18721 -ne `wc -c <'crefine/crefine.1'`; then
    echo shar: \"'crefine/crefine.1'\" unpacked with wrong size!
fi
# end of 'crefine/crefine.1'
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Frank Kaefer # fkk@stasys.sta.sub.org # Starnberg, Germany
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads