Thread View: de.comp.sources.unix
1 messages
1 total messages
Started by Frank Kaefer
Thu, 06 Aug 1992 21:10
v01i012: Crefine - C language extension, Part04/06
Author: Frank Kaefer
Date: Thu, 06 Aug 1992 21:10
Date: Thu, 06 Aug 1992 21:10
1341 lines
48928 bytes
48928 bytes
Submitted-by: prechelt@ira.uka.de (Lutz Prechelt)
Posting-number: Volume 1, Issue 12
Archive-name: crefine/part04
#! /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 4 (of 6)."
# Contents: crefine/cr_getln.c crefine/crefine.man
# Wrapped by fkk@stasys on Thu Aug 6 22:49:35 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'crefine/cr_getln.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'crefine/cr_getln.c'\"
else
echo shar: Extracting \"'crefine/cr_getln.c'\" \(20195 characters\)
sed "s/^X//" >'crefine/cr_getln.c' <<'END_OF_FILE'
X
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 (Level 1) */
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 if (just_was == normal_end_of_line) {
X { /* read_line (Level 1) */
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 (Level 1) */
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 }
X else { /* continued line */
X l->indent = old_indent;
X l->line_no = line_no;
X }
X { /* handle_line (Level 1) */
X three_witches = l->indent == 0 && level > 0 && scanner == normal_scanner;
X if (three_witches && (int)*act == refinementsymbol)
X { /* handle_refinement_declaration (Level 2) */
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 else {
X { /* check_column_0 (Level 2) */
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 if (just_was != refinementsymbol_found &&
X just_was != leave_keyword_found)
X event = (*scanner) (l);
X { /* handle_event (Level 2) */
X if (event == refinementsymbol_found || event == leave_keyword_found)
X { /* handle_refinementcall_or_leave (Level 3) */
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 (Level 4) */
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 just_was = (*act == 0 || *act == '\n') ? normal_end_of_line :
X continueing_end_of_line;
X }
X else
X just_was = event;
X }
X else
X just_was = normal_end_of_line;
X }
X if (option_small || event == normal_end_of_line)
X { /* delete_trailing_blanks (Level 2) */
X while (*(s-1) == ' ') /* remove trailing blanks */
X s--;
X }
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 (Level 2) */
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 && (
X l->type == refcall_line || l->type == refcallr_line)
X && !option_small)
X warning (Wmuch_indent, NULL, line_no, 3);
X }
X assert (!(l->type == refdecl_line && semicolon_count != 0));
X *semicolons += semicolon_count;
X }
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 (Level 1) */
X while (*act == ' ') /* suppress leading blanks */
X act++;
X }
X { /* copy_legal_chars (Level 1) */
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 (Level 1) */
X while (*(s-1) == ' ' && s > old_s) /* suppress trailing blanks */
X s--;
X }
X assert (*(s-1) != ' ');
X assert (*old_s != ' ');
X assert (s - old_s >= 0);
X { /* change_inner_blanks_to_underlines (Level 1) */
X for (start++; start < s; start++) /* change inner blanks to underlines */
X if (*start == ' ')
X *start = '_';
X#undef is_legal
X }
X if (s - old_s == 0)
X error (Erefname_missing, act, line_no);
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 (Level 1) */
X if (!option_small) {
X push (ch); push ('*');
X }
X act++;
X scanner = comment_scanner;
X return ((*scanner) (l));
X }
X else if (*act == '/' && option_cplusplus)
X { /* handle_doubleslash_style_comment (Level 1) */
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 else /* No --> normal */
X push (ch);
X break;
X case dq :
X { /* handle_text_denoter (Level 1) */
X push (ch);
X scanner = text_scanner;
X lines_in_denoter = 0;
X return ((*scanner) (l));
X }
X case q :
X { /* handle_char_denoter (Level 1) */
X push (ch);
X scanner = char_scanner;
X lines_in_denoter = 0;
X return ((*scanner) (l));
X }
X case '#' :
X { /* handle_preprocessor_directive (Level 1) */
X push (ch);
X scanner = preprocessor_scanner;
X return ((*scanner) (l));
X }
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 (Level 1) */
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 else
X push (ch);
X }
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 (Level 1) */
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 /* no break ! */
X default : if (!option_small)
X push (ch);
X }
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 :
X { /* end_of_stringdenoter (Level 1) */
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 case '\\': push (ch);
X if (*act == dq || *act == '\\') {
X push (*act);
X act++;
X }
X break;
X default : push (ch);
X }
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 :
X { /* end_of_chardenoter (Level 1) */
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 case '\\': push (ch);
X if (*act == q || *act == '\\') {
X push (*act);
X act++;
X }
X break;
X default : push (ch);
X }
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 (Level 1) */
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 :
X goto skip_whitespace_1;
X }
X ch = *(act++);
X }
Xskip_whitespace_1: ;
X }
X { /* try_to_read_line_command (Level 1) */
X /* precondition: ch = <first nonwhitespace character after '#' >
X postcondition: ch = <first char not belonging to line command>
X */
X { /* read_the_command_token (Level 2) */
X /* ch = <first nonwhitespace character after '#' > */
X if (strncmp ("line", act, 4)) {
X if (!isdigit (ch))
X goto try_to_read_line_command_1;
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 goto try_to_read_line_command_1;
X }
X }
X { /* skip_whitespace (Level 2) */
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 :
X goto skip_whitespace_2;
X }
X ch = *(act++);
X }
Xskip_whitespace_2: ;
X }
X { /* read_the_line_number (Level 2) */
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 { /* skip_whitespace (Level 2) */
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 :
X goto skip_whitespace_3;
X }
X ch = *(act++);
X }
Xskip_whitespace_3: ;
X }
X { /* read_the_filename (Level 2) */
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 :
X { /* terminate_name_in (Level 3) */
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 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 :
X { /* terminate_name_in (Level 3) */
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 goto read_the_filename_1;
X default : push (ch);
X *(current_letter++) = ch;
X }
X ch = *(act++);
X }
Xread_the_filename_1: ;
X }
Xtry_to_read_line_command_1: ;
X }
X { /* copy_rest_of_line (Level 1) */
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 20195 -ne `wc -c <'crefine/cr_getln.c'`; then
echo shar: \"'crefine/cr_getln.c'\" unpacked with wrong size!
fi
# end of 'crefine/cr_getln.c'
fi
if test -f 'crefine/crefine.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'crefine/crefine.man'\"
else
echo shar: Extracting \"'crefine/crefine.man'\" \(23665 characters\)
sed "s/^X//" >'crefine/crefine.man' <<'END_OF_FILE'
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
XNAME
X crefine - refinement preprocessor for C and C++
X
XSYNOPSIS
X crefine [ options ] inputfile ...
X
XDESCRIPTION
X crefine (C-Refine) (spoken like 'see refine') is a prepro-
X cessor that adds a new language construct to C and C++: the
X refinement. crefine massages source code files to produce
X plain C output from C input with refinements or plain C++
X from C++ with refinements and so on. The syntax of refine-
X ments is described in the USAGE section. The name of the
X output file, if not given explicitly with option -o, is
X derived from the name of the input file by removing its last
X character, if that is an r (which is the filename convention
X for C-Refine). Stdin and stdout can be referenced as '-'
X Error messages go to the standard output. The startup mes-
X sage, if not suppressed, goes to standard error.
X
X C-Refine does not act in any way upon the directives for the
X C preprocessor (except #line). This especially means that
X include files have to be processed separately. Usually, this
X will not be necessary, since they do not typically contain
X anything that C-Refine should work on. A second consequence
X is, that it is possible for C-Refine to give error messages
X on correct programs, because it does not see the effects of
X running the preprocessor. In these cases you either have to
X change your source code or run the C preprocessor before
X C-Refine. In the latter case, C-Refine will correctly pro-
X cess the #line directives that the preprocessor inserts into
X your code in its output and thus give you messages with the
X correct line numbers.
X
XOPTIONS
X -a anyway. Normally, if any error was detected by
X C-Refine, the output file will automatically be
X deleted. This option says not to do so.
X
X -c comment refinement names in the output. Any inserted
X refinement body in the output is titled by a comment
X giving the refinement name and the refinement nesting
X level.
X
X -i indent the #line directives in the resulting output to
X the appropriate indentation level as indicated by the
X nesting of refinements. Not an especially important
X option, but since this is a true UNIX program, it is
X present anyway.
X
X -l list all refinement names. The names of all processed
X refinements are listed to the standard output along
X
X
X
XSun Release 4.1 Last change: 12 June 1992 1
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
X with their line numbers. I do not know exactly what
X this option may be good for, but I believe someday
X somebody will need it.
X
X -m<ch>
X message language. Originally, C-Refine was written by a
X typical german programmer in the typical german pro-
X grammer schizophrenia situation: as a german the native
X tongue is german, as a programmer the native tongue is
X english. So both languages were supported for the error
X messages. Use -mg for German and -me for English
X (which is the default). Even worse, since I believe
X the whole data processing world is much too serious, I
X liked to have a somewhat humorous version either. Use
X -mG for german humorous messages, and -mE for english
X humorous messages.
X
X -n<num>
X numbering with #line commands. By default, every inser-
X tion of a refinement body is accompanied by a #line
X preprocessor directive in the output. This is the
X default numbering level 3. By giving a smaller number
X just after the option character n , the amount of #line
X directives used can be reduced (level 2 or 1) or set to
X zero (level 0). What is best depends on the behavior of
X your local C or C++ compiler. Just try it out, begin-
X ning with the default level 3.
X
X -o<string>
X set name of output file explicitly. Normally, the name
X of the output file is the name of the input file with
X an 'r' stripped off of the end (and stdout when input
X is stdin). This can be overridden with this option.
X
X -p plus. The C++ mode. The only difference between C mode
X and C++ mode for C-Refine is, that in C++ mode the C++
X doubleslash comment convention is obeyed, while in C
X mode it is not. This is possible because C-Refine knows
X very little about the actual syntax of these two
X languages. So in most cases, this difference makes no
X difference at all.
X
X -v verbose mode. Makes C-Refine display a startup message.
X
X -r<ch>
X refinement symbol. Select what character shall be
X recognized as the refinement symbol in the input file.
X The character to chose must be given on the command
X line after the option character r. This is the
X backquote (ASCII code 95) by default. Since there are
X only two printable ASCII characters that are unused in
X the syntax of C (the backquote, code 96, and the dollar
X
X
X
XSun Release 4.1 Last change: 12 June 1992 2
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
X or currency sign, code 36) there is very little choice
X on a machine with 7 bit character set. This choice is
X further restricted because on some systems (such as
X VMS) the dollar sign is acutally being allowed and used
X for identifiers. Some more possiblilities arise when
X having an 8 bit character set, such as the IBM interna-
X tional character set (proposed symbol there is the lit-
X tle double right angle bracket, code 175, which really
X looks nice), but take into account that any change in
X refinement symbol is bad for the portability of your
X source files. Note that some characters have to be
X quoted in the shell.
X
X -R<num>
X refinement symbol. Same as before, but the new symbol
X is given by its character code instead of by itself.
X
X -s strip. Produces smaller output by stripping of all
X indentation, whether present in the input or generated
X by C-Refine, and all comments. This is on by default.
X To switch it off, use the syntax -s-
X
X -w<num>
X warning level. C-Refine is able to give various warn-
X ings about your source code. These can be suppressed in
X three stages. The default warning level is 3 (all warn-
X ings). You can chose any level from 0 (no warnings) to
X 3 by giving the appropriate number after the option
X character w on the command line.
X
X -B<num>
X buffer. Select the size of the source code buffer (in
X bytes) in which C-Refine holds the code for a function
X while processing it. The default is 150000 bytes.
X
X -E<num>
X errors. Select the maximum number of errors that may
X occur in the input before C-Refine stops processing
X prematurely. The default is 20.
X
X -L<num>
X lines. Select the maximum number of source code lines
X per single function that C-Refine is able to hold. The
X default is 2500.
X
X -M<num>
X maximum number of characters per line. The default is
X 500.
X
X -N<num>
X number of refinements per function. Selects the max-
X imum number of refinement declarations that may be
X
X
X
XSun Release 4.1 Last change: 12 June 1992 3
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
X present within any single function. The default is 200.
X
X -P<num>
X interval of progress display. For the homo ludens in
X the programmer or people with incredibly overloaded
X machines. After every <num> lines of processing
X C-Refine echoes the current line number to stdout. The
X default is 0, which means that this function is
X suppressed.
X
X -T<num>
X tab size. Select the number of spaces to which a TAB
X character expands. C-Refine expands all TAB characters
X at the beginning of a line, i.e. those that act as
X indentation. Other TABs are left untouched. The default
X is 1.
X
X -W<num>
X warnings. Select the maximum number of warnings that
X may occur before C-Refine stops processing prematurely.
X The default is 30.
X
X -- indicate 'end of options'. You may use a dash as the
X input filename (to use C-Refine as a filter from stan-
X dard input to standard output), but it can be recog-
X nized only after you have used a double dash to indi-
X cate that it is not an option.
X
XUSAGE
X There are three new syntactic elements with C-Refine: the
X refinement definition, the refinement call and the leave
X construct. The purpose of refinements is to support the
X Top-Down style of programming (a) within a function and (b)
X in both, thinking and writing. Essentially, refinements are
X just parameterless macros with long descriptive names.
X Refinements are in any case local to a function. They may be
X called before they are declared; declaration and definition
X of a refinement are one. The syntax of refinements as
X defined by C-Refine is not format free, but lays signifi-
X cance upon whether a special symbol (the refinement symbol)
X is occuring in column 0 or somewhere else.
X
X Along with the new language constructs are some layout res-
X trictions for the program text being defined. This is neces-
X sary, because (a) the syntax of the refinement constructs
X breaks basic syntactic rules of C and (b) the C-Refine
X preprocessor relies on some simple formatting rules, so its
X algorithms can be kept simple and the whole thing small,
X portable, robust, reliable, and fast.
X
X Here are the (very informal) descriptions of the syntax and
X semantics of the language elements introduced by C-Refine:
X
X
X
XSun Release 4.1 Last change: 12 June 1992 4
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
X refinement names
X A refinement name is just a normal C identifier, with
X one important addition: blanks are allowed within (!)
X it (i.e. anywhere after the first nonblank character of
X the name and before the last nonblank one); they are
X equivalent to underscores. The end of a refinement name
X is always detected by the appearence of a special sym-
X bol, typically a semicolon, a colon or an operator. A
X refinement name must, however, be on a single line.
X
X refinement calls
X A refinement call consists of the refinement symbol,
X immediately followed by a refinement name. The refine-
X ment symbol must not be in colums 0 of the source line.
X Refinement calls are principally allowed anywhere
X within a function. The called refinement must be
X defined in that function, although the definition may
X (and usually will) appear later than the call. The
X semantics of a refinement call is as follows: A pro-
X cedural refinement (i.e. one that contains at least one
X semicolon in its body) is inserted instead of its call,
X surrounded by a pair of curly braces. This insertion is
X recursively applied to nested refinements. A valued
X refinement (i.e. one that contains just an expression
X and no semicolon in its body) is inserted instead of
X its call, surrounded by a pair of parentheses. This
X insertion is recursively applied to nested valued
X refinements. So procedural refinements can be called
X anywhere where a block statement is legal. Valued
X refinements can be called anywhere where a parenthesed
X expression is legal. An illegal form of refinement
X call will be detected by C-Refine.
X
X refinement definitions
X a refinement definition consists of the refinement sym-
X bol, immediately followed by a refinement name, fol-
X lowed by a colon. The refinement symbol must be in
X column 0 of the source line. Refinement definitions are
X allowed only on block nesting level 1, i.e. in the
X outermost block of a function. The body of a refine-
X ment is examined to decide what type of refinement it
X is: All refinements that contain one or more semicolons
X in their body, that are not part of a comment, charac-
X ter denoter or string denoter, are called procedural
X refinements, since they contain statements. All other
X refinements are called valued refinements, since they
X only contain an expression and thus return a value.
X Illegal syntax of a refinement declaration and the
X declaration of refinements that are never used will be
X detected by C-Refine.
X
X leave
X
X
X
XSun Release 4.1 Last change: 12 June 1992 5
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
X The leave construct may be used from within any pro-
X cedural refinement at any place where a statement is
X legal. It consists of the keyword leave followed by the
X refinement symbol, followed by a refinement name ref.
X The semantics of this construct is, that a goto state-
X ment is inserted instead of the leave construct, that
X jumps to a point right after the last statement of the
X refinement ref. For this to be legal ref must be
X present in the current static nesting of refinement
X calls. This means that not only the current refinement
X can be left with leave, but any number of refinements
X that are statically nested at that point of your code.
X Illegal use of the leave construct is detected by
X C-Refine.
X
X As by now, I assume, almost any understanding that may
X initially have been there, will probably have vanished.
X I will try to get it back to you by means of the fol-
X lowing example. This is a (very simple-minded) version
X of the Sieve of Eratosthenes. It should not be thought
X that I believe the refinement technique to be espe-
X cially well suited to this problem, but this was the
X smallest 'real' problem I could think of to demonstrate
X at least most of what the possibilities of C-Refine
X are. So here it is:
X
X #define MAX 10000
X #define PRIME 0
X #define NON_PRIME 1
X
X static int sieve[MAX+1];
X
X int 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
X
X
XSun Release 4.1 Last change: 12 June 1992 6
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
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 To make the self documentation aspect of C-Refine more
X clear, look at the following example: A function that
X tests, whether its parameters form a pythagorean tri-
X ple:
X bool 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
X
X
XSun Release 4.1 Last change: 12 June 1992 7
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
X `z is hypotenuse:
X z*z == x*x + y*y
X
X }
X This is good style: you write down just what you want
X to express and with an optimizing compiler such code
X will also be perfectly efficient. Try to imagine what
X this would have looked like, if it had all been in a
X single parenthesesed expression.
X
XFILES
X crefine the executable program
X filename.cr C-with-refinements input file.
X filename.c C output file.
X filename.ccr C++-with-refinements input file.
X filename.cc C++ output file.
X
XEXAMPLES
X crefine firsttest.cr
X process the input file firsttest.cr producing the out-
X put file firsttest.c
X
X crefine -p+ -q+ -o outfile -w 2 next.ccr
X process the C++-Refine inputfile next.ccr producing the
X output file outfile. The startup message is
X suppressed, C++ mode is selected and the warning level
X is reduced to 2.
X
X crefine -pqw2 -ooutfile next.ccr
X same as before.
X
X crefine -o outfile -p+a-l-qw2 next.ccr
X same as before.
X
X crefine -c -s- -n0 -T8 last.cr
X process the inputfile last.cr in order to get a read-
X able C source. Comments and indentation are not
X stripped, inserted refinement bodies are tagged by an
X additional comment giving the refinement name, all
X #line preprocessor directives are left out and leading
X tabs expand to 8 spaces.
X
X crefine -cs-n0T8 last.cr
X same as before.
X
XDIAGNOSTICS
X The warnings and error messages are intended to be self
X explanatory. If you do not understand one of them anyway:
X chose a different language for the messages (see option -m),
X get yourself a dictionary or interpreter and try again.
X
X
X
X
X
XSun Release 4.1 Last change: 12 June 1992 8
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
XSEE ALSO
X cc(1), ccr(1), cpp(1), make(1)
X
XBUGS
X Since preprocessor directives are not handled by C-Refine,
X strange things can happen if you use #ifdef or #if. This is
X especially the case if you use these directives to put large
X comments into your source files: if there are any comments
X or string literals (double quotes) or char literals (single
X quotes) beginning in that area that are not properly closed
X within it, C-Refine will run to nirvana searching for their
X end and give you lots of wrong error and warning messages.
X Watch out for apostrophes (e.g. in "don't") especially!
X
X Those people, who use such stupid macros as
X #define BEGIN {
X #define END }
X or similar craizy stuff, will have to change their habits or
X run the preprocessor first in order to use C-Refine.
X
X When using a call to a value returning refinement as a
X parameter to a macro, most preprocessors will complain the
X #line directive when numbering level 3 is being used. -n2 or
X -n1 can be used to overcome this problem although this may
X be a bit unsatisfactory.
X
X The output of C-Refine may be code that exceeds certain com-
X piler limits of your C or C++ compiler. Since the body of
X every procedural refinement is enclosed in a block and the
X body of every value returning refinement is enclosed in
X parentheses, the block nesting limits or expression complex-
X ity limits of your compiler may be reached when you make
X very heavy use of nested refinements.
X
X Some compilers may handle the #line directive improperly,
X yielding wrongly tagged error messages. Bad luck.
X
X Probably C-Refine will also work with Objective-C, but I am
X not absolutely sure about that. Perhaps somebody will give
X me some feedback on this issue ?
X
X There should be a mode to use C-Refine for Lisp also.
X
X And for several other languages, too.
X
X C-Refine reacts poor on some types of syntactic errors.
X
X C-Refine will not work good if your filenames contain cer-
X tain strange characters (e.g. double quotes).
X
X In C++, when a "leave" has to jump across a variable ini-
X tialization, some compilers will complain, that the goto is
X
X
X
XSun Release 4.1 Last change: 12 June 1992 9
X
X
X
X
X
X
XCREFINE(1) USER COMMANDS CREFINE(1)
X
X
X
X illegal. This is not true, because the goto jumps to (or
X even beyond) the very end of the block where that variable
X is in [precisely: the jump is to an empty statement, which
X is the last statement in the block], but these compilers do
X not recognize that fact.
X
X You must have C-Refine in order to be able to use refine-
X ments. This is actually not a bug in C-Refine but in your
X compiler.
X
X Although much easier than without, programming is still dif-
X ficult even with C-Refine. This is a bug in you. Contact
X darwin@nirvana.edu or root@headquarter.heaven.gov for com-
X plaints.
X
XVERSION
X This manpage is for C-Refine Version 3.0 (internally named
X Version 17)
X
XAUTHOR
X Lutz Prechelt (prechelt@ira.uka.de)
X Institut fuer Programmstrukturen und Datenorganisation
X Universitaet Karlsruhe
X D-7500 Karlsruhe
X Germany
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XSun Release 4.1 Last change: 12 June 1992 10
X
X
X
END_OF_FILE
if test 23665 -ne `wc -c <'crefine/crefine.man'`; then
echo shar: \"'crefine/crefine.man'\" unpacked with wrong size!
fi
# end of 'crefine/crefine.man'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
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