Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C as a scripting language

1 view
Skip to first unread message

jacob navia

unread,
Mar 26, 2009, 4:18:09 PM3/26/09
to
Common widsom says that python, ruby or similar are good for scripting,
but C is not the right tool for it.

Here is a small "benchmark" that shows that C can be used as a
scripting language in the same way as, for instance, ruby.

Setup
-----

The task to be solved is as follows:

In the current directory you have a bunch of .c files.
For each file in that directory you should start the C
compiler, compile the file, and if the compile works,
link it and then run it. You should gather some statistics
about how many runs were done, and how many compilation
errors or run time errors were discovered, printing them
at the end.

Here is a solution using the "ruby" language:
--------------------------------------------------------------
#/usr/bin/ruby -w
class Array
alias :append :push
end

def run_and_collect(file_list)
comp_counter = 0
run_counter = 0
count_all_compilations = 0
failed_compilations = 0
count_all_runs = 0
failed_runs = 0
failed_run_progs = []
successfull_runs = []
failed_compilation_runs = []

file_list.each {|file|
ret_val = system("../lcc -O -DNO_LABEL_VALUES -c -nw -g2
#{file} -o a.obj && gcc a.obj lcclibc_asm.s -o a -lm")
count_all_compilations += 1
if (ret_val == false)
puts("failed compilation: #{file}")
failed_compilations += 1
failed_compilation_runs.append(file)
else
ret_val = true
ret_val = system("./a")
run_counter+= 1
if (ret_val == false)
puts("failed run: #{file}");
failed_runs += 1
failed_run_progs.append(file + " ")
successfull_runs.append(file)
end
end
}
puts("Compilations: #{count_all_compilations}, failed:
#{failed_compilations}\n
Runs: #{run_counter}, failed: #{failed_runs}\n
#{failed_run_progs} \n")
end

run_and_collect(ARGV)
---------------------------------------------------------------------
Now the C solution:
--------------------------------------------------------------------
#define MAXTESTS 1000
#include <stdio.h>
#include <string.h>
void ShowFailures(char *tab[],int);
int main(int argc,char *argv[])
{
FILE *f;
char buf[512],cmd[1024], tmpbuf[512];
int r, tests=0,CompilationFailures=0, LinkFailures=0, RunFailures=0;
char *CFailures[MAXTESTS],*LFailures[MAXTESTS],
*RFailures[MAXTESTS];

f = popen("ls *.c","r");
while (fgets(buf,sizeof(buf),f)) {
char *p = strchr(buf,'\n');
if (p) *p=0;
tests++;
sprintf(cmd,"../lcc -g2 -nw %s",buf);
p = strchr(buf,'.');
if (p) *p=0;
r = system(cmd);
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);
} else {
sprintf(cmd,"gcc %s.o lcclibc_asm.s -lm");
r = system(cmd);
if (r) {
printf("Link of %s.o failed\n",buf);
LFailures[LinkFailures++] = strdup(buf);
} else {
r = system("./a.out");
if (r) {
printf("Execution of %s failed\n",buf);
RFailures[RunFailures++] = strdup(buf);
}
}
}
}
pclose(f);
printf("\n********************************\n%d"
"tests\n********************************\n",tests);
if (CompilationFailures) {
printf("Compilation Failures: (%d)\n",CompilationFailures);
ShowFailures(CFailures,CompilationFailures);
}
if (LinkFailures) {
printf("Link failures: (%d)\n",LinkFailures);
ShowFailures(LFailures,LinkFailures);
}
if (RunFailures) {
printf("Run failures (%d)\n",RunFailures);
ShowFailures(RFailures,RunFailures);
}
}

void ShowFailures(char *tab[],int n)
{
for (int i=0; i<n; i++) { printf("%s ",tab[i]); } printf("\n");
}
----------------------------------------------------------------------------

Both programs use identical algorithms:
(1) The list of *.c files will be established. Ruby uses a list, C uses
a pipe connected to another process that sends a line at a time.
(2) For each file the compiler is called, then the linker and the
resulting program. Statistics are gathered.
(3) A printout at the end of the run lists the failures.

The length in source code of both programs is very similar.

The running time of both programs is identical.

I wrote the C program, and a friend wrote the ruby program. It was
for testing the Unix version of lcc-win, i.e. both programs are
used in a "production" setting.

I think that both languages are perfectly equivalent in this example.

The next example I will post is web programming.

Thanks for your attention.

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32

toby

unread,
Apr 19, 2009, 11:20:57 PM4/19/09
to
On Mar 26, 4:18 pm, jacob navia <ja...@nospam.org> wrote:
> Common widsom says that python, ruby or similar are good for scripting,
> but C is not the right tool for it.

Common wisdom says that bash is the right tool for operating system
kernels, database systems, prime sieves, and so on - but it can also
be abused for day-to-day scripting tasks as well!


#!/bin/bash

ALL_COMP=0
declare -a FAIL_COMP
ALL_RUNS=0
declare -a FAIL_RUNS

while [ $1 ] ; do
let ++ALL_COMP
if cc $1 ; then
let ++ALL_RUNS
if ! ./a.out ; then FAIL_RUNS[${#FAIL_RUNS[*]}]=$1 ;
fi
else
FAIL_COMP[${#FAIL_COMP[*]}]=$1
fi
shift
done

echo Compilations: $ALL_COMP, failed: ${#FAIL_COMP[*]}
echo ${FAIL_COMP[*]}
echo
echo Runs: $ALL_RUNS, failed: ${#FAIL_RUNS[*]}
echo ${FAIL_RUNS[*]}

0 new messages