Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Using Gambit-C Scheme to Create Small, Efficient Native Applications : Page 3

When you need to build small, native standalone applications, Gambit-C Scheme provides a high-level dynamic language with good runtime and memory performance, as well as good deployment options.




Application Security Testing: An Integral Part of DevOps

The "Hello Command Line" Example

The previous section explained how to define functions in Scheme. This section demonstrates how to access command-line arguments and generate a test standalone executable. The following code snippet uses the function print-arg-list, which contains at least two surprises if this is your first time using Scheme:
  1. The function calls itself recursively (as did the function fact you saw in the last section) to implement a loop over a list of argument values.
  2. It uses another function that is defined inside its definition.

(define (print-arg-list arg-list) (define (print-arg arg) ; define the inner utility function print-arg (display "Next command-line-argument: ") (display (car arg-list)) (newline)) ;; this is the start of the function print-arg-list: (if (pair? arg-list) ; check that arg-list is a list with at least one argument (let () (print-arg (car arg-list)) (print-arg-list (cdr arg-list))))) ; make a recursive call

The only reason that I split out the separate inner function print-arg was to show you an example of nested functions. Nesting function definitions like this is a good technique when a small utility function is used by only one other function. The inner function is not visible outside the scope of the outer function. Using a nested function makes sense when it is used more than once in an outer function definition.

When I am interactively coding, I write and debug small functions as I write them to catch mistakes earlier. In the case of nested functions, I usually write and debug them before copying them into the definition of another function that uses them.

You can test the function print-arg-list using gsi:

> (print-arg-list '("-i" "input.dat" "-o" "output.dat" 1 2 3)) Next command-line-argument: -i Next command-line-argument: input.dat Next command-line-argument: -o Next command-line-argument: output.dat Next command-line-argument: 1 Next command-line-argument: 2 Next command-line-argument: 3 >

You have seen that top-level Scheme expressions typed in gsi are evaluated immediately:

> (display "Hello\n") Hello >

If you put top-level Scheme expressions in a Scheme source file and compile it to a native application, then these top-level expressions are also immediately executed when the application runs.

The gsc compiler generates a separate C file ending with _.c. The generated .c files contain a main C function. For the "Hello Command Line Arguments" test program, I use the print-arg-list function and the following expression:

(let* ((args (command-line)) (in-file (member "-i" args)) (out-file (member "-o" args)) (arg-hash-table (make-table))) ;; let's start by printing the command line arguments: (print-arg-list args) ;; check to see if an argument is "-help": (if (member "-help" args) (print-help)) ;; now print out input and output file names, if they are supplied: (if (and in-file (> (length in-file) 1)) (let () (display "Input file: ") (display (cadr in-file)) (newline))) (if (and out-file (> (length out-file) 1)) (let () (display "Output file: ") (display (cadr out-file)) (newline))))

This expression uses the built-in Gambit-C specific function command-line, which returns command-line arguments as a list of strings. It also uses the Scheme function member, which takes two arguments: an expression and a list of expressions. The expression searches the list for an element equal to the first argument.

Here are some examples of member:

> (define test-list '(1 2 3 4 5 "cat" 3.14159 100 101)) > (member 3 test-list) (3 4 5 "cat" 3.14159 100 101) > (member "cat" test-list) ("cat" 3.14159 100 101) > (member "not in list" test-list) #f >

Note that member returns a sub-list starting with the matching list element. The function length returns the number of elements in a list:

> (length test-list) 9

An example program you will develop later requires you to process command arguments.

Creating an Executable File

When creating standalone executables, be aware that the Gambit-C gsc compiler compiles Scheme code to C; the generated C code is compiled and linked against the Gambit-C libraries. The location of these files is different for OS X, Linux, and Windows. When I started writing this article, using version 4.4.4 of Gambit-C, compiling and linking Scheme code into a native executable took several steps and was platform dependent because you had to know the location of the include files and library files for Gambit-C. With the release of Version 4.5.0, the compiler has a new option, -exe, that removes the platform dependencies and allows you to compile to C, compile the generated C code, and link it all with one command.

The code directory hello-command-line-args in the source code download contains both the source file hello-command-line.scm and a makefile. Here is a listing of the makefile:

clean: rm -f *~ rm -f */*~ rm -f \#* rm -f */\#* rm -f *.c rm -f hello-command-line app: gsc -exe hello-command-line.scm

The make target clean removes all files from the working directory except for the Scheme source file and the makefile. The make target app builds a standalone executable with no other dependencies. Here is an attempt at running the hello command-line executable:

markw$ ./hello -help Next command-line-argument: ./hello Next command-line-argument: -help Hello Command Line (native) command line arguments: -help -- to print help message -i -- to define the input file name -o -- to specify the output file name markw$ ./hello "this is a test" 1 2 3 Next command-line-argument: ./hello Next command-line-argument: this is a test Next command-line-argument: 1 Next command-line-argument: 2 Next command-line-argument: 3 markw$ ./hello -i input.dat -o output.dat Next command-line-argument: ./hello Next command-line-argument: -i Next command-line-argument: input.dat Next command-line-argument: -o Next command-line-argument: output.dat Input file: input.dat Input file: output.dat

The next section demonstrates another example that processes input text files.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date