Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: Programming exercise/challenge
Date: Wed, 30 Dec 2020 09:40:30 -0800
Organization: A noiseless patient Spider
Lines: 284
Message-ID: <86a6tvur8x.fsf@linuxsc.com>
References: <86wnxwkyol.fsf@linuxsc.com> <5fcbb652$0$16505$e4fe514c@textnews.kpn.nl>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: reader02.eternal-september.org; posting-host="bad9f3398650fdf0e991b5310f5ac4d7"; logging-data="10180"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/77Ul5ZUcHS4VcM8JPpjuNUxxhG/o+oXE="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:szxwD8Lj4AGQ5pbDcopBaUepADw= sha1:8RK/JzzRNLEcXl4vfVVagfw3cvU=
Xref: csiph.com comp.lang.c:157908
Sjouke Burry writes:
> On 05.12.20 17:25, Tim Rentsch wrote:
>
>> Prompted by some recent discussion regarding 'goto' statements and
>> state machines, I would like to propose a programming exercise.
>> (It is perhaps a bit too large to be called an exercise, but not so
>> difficult that it deserves the label of challenge. On the other
>> hand there are some constraints so maybe challenge is apropos. In
>> any case somewhere in between those two bounds.)
>>
>> Short problem statement: a C program to remove comments from C
>> source input. [...]
>
> If you show yours , maybe some of us will show theirs........
If you have been waiting for me, here it is.
This program is basically the same as the one I wrote just before
posting the exercise statement, not counting some cosmetic
cleanup and a change so comments would be replaced by a single
blank.
/* uncomment.c - remove comments from C source files */
#include
#include
typedef unsigned long Count;
typedef enum {
ALL_GOOD = 0,
UNTERMINATED_CHARACTER_LITERAL,
UNTERMINATED_STRING,
UNTERMINATED_COMMENT,
} Status;
typedef Status Reader_f( Count );
static Status restart( int );
static Reader_f
start,
sl, slbs,
slsl, slslbs,
slst, slstst, slststbs,
sq, sqbs, sqbsbs, sqbs__,
dq, dqbs, dqbsbs, dqbs__;
static Count show_sl_lcs_bs( Count );
static Count show_sl_lcs( Count );
static Count show_lcs( Count );
static int next( void );
static int outc( int );
enum {
SQ = '\'',
DQ = '\"',
SL = '/',
STAR = '*',
BS = '\\',
NL = '\n',
SP = ' ',
};
/* main */
int
main(){
return start(0) == ALL_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
/* top level */
Status
restart( int c ){
return ungetc( c, stdin ), start( 0 );
}
Status
start( Count n ){
int c = getchar();
return c == SL ? sl( 0 )
: c == DQ ? outc( c ), dq( 0 )
: c == SQ ? outc( c ), sq( 0 )
: c != EOF ? outc( c ), start( 0 )
:/* c == EOF */ ALL_GOOD;
}
/* slant character - top level */
Status
sl( Count n ){
int c = getchar();
return c == SL ? slsl( 0 )
: c == STAR ? slst( 0 )
: c == EOF ? show_sl_lcs( n ), ALL_GOOD
: c != BS ? show_sl_lcs( n ), restart( c )
:/* c == BS */ slbs( n );
}
Status
slbs( Count n ){
int c = getchar();
return c == EOF ? show_sl_lcs_bs( n ), ALL_GOOD
: c != NL ? show_sl_lcs_bs( n ), restart( c )
:/* c == NL */ sl( n+1 );
}
/* slant character helper functions - show counted line splices */
Count
show_sl_lcs_bs( Count n ){
return show_sl_lcs( n ), outc( BS ), 0;
}
Count
show_sl_lcs( Count n ){
return outc( SL ), show_lcs( n );
}
Count
show_lcs( Count n ){
return n > 0 ? outc( BS ), outc( NL ), show_lcs( n-1 ) : 0;
}
/* new style C comment - 'slsl' */
Status
slsl( Count n ){
int c = getchar();
return c == NL ? outc( c ), start( 0 )
: c == BS ? slslbs( n )
: c == EOF ? outc( NL ), ALL_GOOD
: slsl( 0 );
}
Status
slslbs( Count n ){
int c = getchar();
return c == NL ? slsl( 0 )
: c == EOF ? outc( NL ), ALL_GOOD
: c == BS ? slslbs( 0 )
: slsl( 0 );
}
/* old style C comment - 'slst' */
Status
slst( Count n ){
int c = getchar();
return c == EOF ? outc( NL ), UNTERMINATED_COMMENT
: c == NL ? slst( 0 )
: c == STAR ? slstst( 0 )
: slst( 0 );
}
Status
slstst( Count n ){
int c = getchar();
return c == EOF ? UNTERMINATED_COMMENT
: c == NL ? slst( 0 )
: c == SL ? outc( SP ), start( 0 )
: c == STAR ? slstst( 0 )
: c == BS ? slststbs( 0 )
: slst( 0 );
}
Status
slststbs( Count n ){
int c = getchar();
return c == EOF ? UNTERMINATED_COMMENT
: c == NL ? slstst( 0 )
: c == STAR ? slstst( 0 )
: slst( 0 );
}
/* character literals - 'sq' */
Status
sq( Count n ){
int c = next();
return c == SQ ? start( 0 )
: c == NL ? UNTERMINATED_CHARACTER_LITERAL
: c == EOF ? UNTERMINATED_CHARACTER_LITERAL
: c == BS ? sqbs( 0 )
: sq( 0 );
}
Status
sqbs( Count n ){
int c = next();
return c == NL ? sq( 0 )
: c == EOF ? UNTERMINATED_CHARACTER_LITERAL
: c == BS ? sqbsbs( 0 )
: sq( 0 );
}
Status
sqbsbs( Count n ){
int c = next();
return c == NL ? sqbs__( 0 )
: c == EOF ? UNTERMINATED_CHARACTER_LITERAL
: c == SQ ? start( 0 )
: c == BS ? sqbs( 0 )
: sq( 0 );
}
Status
sqbs__( Count n ){
int c = next();
return c == NL ? UNTERMINATED_CHARACTER_LITERAL
: c == EOF ? UNTERMINATED_CHARACTER_LITERAL
: c == BS ? sqbsbs( 0 )
: sq( 0 );
}
/* string literals - 'dq' */
Status
dq( Count n ){
int c = next();
return c == DQ ? start( 0 )
: c == NL ? UNTERMINATED_STRING
: c == EOF ? UNTERMINATED_STRING
: c == BS ? dqbs( 0 )
: dq( 0 );
}
Status
dqbs( Count n ){
int c = next();
return c == NL ? dq( 0 )
: c == EOF ? UNTERMINATED_STRING
: c == BS ? dqbsbs( 0 )
: dq( 0 );
}
Status
dqbsbs( Count n ){
int c = next();
return c == NL ? dqbs__( 0 )
: c == EOF ? UNTERMINATED_STRING
: c == DQ ? start( 0 )
: c == BS ? dqbs( 0 )
: dq( 0 );
}
Status
dqbs__( Count n ){
int c = next();
return c == NL ? UNTERMINATED_STRING
: c == EOF ? UNTERMINATED_STRING
: c == BS ? dqbsbs( 0 )
: dq( 0 );
}
/* character input */
int
next(){
return outc( getchar() );
}
/* output */
int
outc( int c ){
return c != EOF ? putchar( c ), c : c;
}