Path: csiph.com!weretis.net!feeder8.news.weretis.net!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: Programming exercise/challenge
Date: Thu, 10 Dec 2020 01:49:58 -0800
Organization: A noiseless patient Spider
Lines: 189
Message-ID: <86wnxq2do9.fsf@linuxsc.com>
References: <86wnxwkyol.fsf@linuxsc.com> <871rg2rffu.fsf@bsb.me.uk> <86v9dehts2.fsf@linuxsc.com> <87360hq0si.fsf@bsb.me.uk>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: reader02.eternal-september.org; posting-host="e123793f93e194ce9596f9b3807e7692"; logging-data="2088"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+hhMe/KAr/93+Ta7TrJRBko0QE7/mLotc="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:7FGx6+zg+3Jlw2EnDcXztkgJuAU= sha1:CMGzRk7vPMgu2WLLj2bNUeXMBX4=
Xref: csiph.com comp.lang.c:157185
Ben Bacarisse writes:
> Tim Rentsch writes:
[...]
>>> Haskell has two big advantages for this exercise: pattern matched
>>> cases and lazy evaluation. [..explanation..]
>>
>> Also one not mentioned: 'input <- getContents'. An analogous
>> functionality in C would read the contents of a file into a
>> character array, which would make the C program easier.
>
> I don't think its analogous at all! 'input' <- getContents does
> no IO. Input is fetched only as needed to perform computations on
> 'input' and processed data will be considered garbage.
The point I am trying to make here is not about IO but about data
structuring. I understand that Haskell has lazy eval and agree
that there are advantages that accrue from that. Here though I
think the important property is that getContents returns a "data
structure" that is convenient to process in Haskell, specifically
in the context of what an uncommenting program wants to do. An
analogous data structure in C (not counting the lazy evaluation
part, which I've already acknowledged) is a character array.
Let's look at some C code that takes advantage of its primary
data structure for handling strings.
** SPOILER ALERT **
The program below is a comment remover where backslant-newline
sequences have also been eliminated in the output. Stop reading
now if you don't want to see the code yet.
** SPOILER ALERT **
Granted, the code below isn't a nice as your Haskell version, but
I think it isn't too bad. How does it strike you?
/* remove comments after pre-combining physical lines into logical lines */
#include
#include
#include
typedef const char *String;
static int decomment_stdin_all_good( void );
static void splice_lines( char * );
static int decomment_okay( String );
static String show_literal( String );
static String show_string( String );
static String handle_slant( String );
static String skip_over_literal( String );
static String skip_over_string( String );
static String skip_comment_tail( String );
static char * contents_of_file( FILE * );
static String skip_to( String, String );
int
main(){
return
! decomment_stdin_all_good()
? fputs( " [not good] ", stderr ), EXIT_FAILURE
: 0;
}
int
decomment_stdin_all_good(){
char *in = contents_of_file( stdin );
return in ? splice_lines( in ), decomment_okay( in ) : 0;
}
void
splice_lines( char *s ){
char c, *p = s;
const char *q = s;
while( c = *p++ = *q++ ){
if( c == '\\' && 0[q] == '\n' ) p--, q++;
}
}
/* process spliced input, removing comments */
int
decomment_okay( String s ){
while( s && *s ){
String p = skip_to( s, "\"'/" );
printf( "%.*s", (int){ p-s }, s );
/**/ if( *p == '\'' ) s = show_literal( p );
else if( *p == '"' ) s = show_string( p );
else if( *p == '/' ) s = handle_slant( p );
else s = p;
}
return s ? 1 : 0;
}
String
show_literal( String s ){
String p = skip_over_literal( s+1 );
return printf( "%.*s", (int){p-s}, s ), p ;
}
String
skip_over_literal( String s ){
String p = skip_to( s, "\n'\\" );
return *p == '\n' || !*p ? p
: *p++ == '\'' ? p
: *p == '\n' || !*p ? p
: skip_over_literal( p+1 );
}
String
show_string( String s ){
String p = skip_over_string( s+1 );
return printf( "%.*s", (int){p-s}, s ), p;
}
String
skip_over_string( String s ){
String p = skip_to( s, "\n\"\\" );
return *p == '\n' || !*p ? p
: *p++ == '"' ? p
: *p == '\n' || !*p ? p
: skip_over_string( p+1 );
}
String
handle_slant( String s ){
return 1[s] == '*' ? putchar( ' ' ), skip_comment_tail( s+2 )
: 1[s] != '/' ? putchar( '/' ), s+1
: skip_to( s+1, "\n" );
}
String
skip_comment_tail( String s ){
String p = strstr( s, "*/" );
return p ? p+2 : strchr( s, 0 );
}
/*** utility functions ***/
char *
contents_of_file( FILE *f ){
typedef unsigned long Index, Extent;
char *r = malloc( 1 );
Index k = 0;
Extent n = 1;
int c;
if( !r ) return r;
r[k] = 0;
while( c = getc( f ), c != EOF ){
if( k+1 >= n ){
Extent n1 = n + n/4 + 1024;
char *r1 = realloc( r, n1 );
if( !r1 ) return free( r ), r = 0;
r = r1, n = n1;
}
r[k++] = c, r[k] = 0;
}
return r;
}
inline String
skip_to( String s, String choices ){
return s + strcspn( s, choices );
}