Previous | Table of Contents | Next |
Strictly speaking, Guile is an object library, not an executable. We built the interpreter used in the preceding examples by linking the following code against the Guile library libguile.a:
/* guile.c --- stand-alone Guile shell Jim Blandy <jimb@red-bean.com> --- December 1997 */ #include <libguile.h> void inner_main (void *dummy, int argc, char **argv) { scm_shell (argc, argv); } main (int argc, char **argv) { scm_boot_guile (argc, argv, inner_main, 0); }
All C code using Guile functions must #include the header file <libguile.h>, which provides prototypes and definitions for Guiles functions, macros, and constants. The programs main function invokes scm_boot_guile, which initializes Guile, makes a copy of the arguments for Scheme code to use, and then calls its third argument, inner_main. (It passes its fourth argument straight through to inner_main; this code does not use it.) When inner_main returns, Guile terminates the process with an exit status of zero. This initialization procedure is somewhat circuitous, but it allows Guile to use an automatic storage-management technique, which greatly simplifies the handling of Scheme values in C code; I discuss this in more detail later in the chapter.
The code shown here is rather short; the core of the interpreter comes from the library, and you need only write a stub routine to get things started. The last function invoked, scm_shell, takes care of interacting with the user or running a script file, as appropriate.
One of the most critical lessons of computer science is simply that notation matters. If this were not so, programmers would usually work directly in machine code because most higher-level languages (assembly language included) are merely pretty notations for machine code. Instead, programming languages provide a critical service when they allow the programmer to work in terms of concepts more relevant to the application and manage uninteresting details transparently.
The more a language implementation can assume about the application, the better the error checking and optimizations it can provide. For example, if we make a request in a database query language such as SQL, we would not be surprised if the database engine optimized the query to perform indexed searches first, thus narrowing the list of records to be scanned by less efficient means. However, we would be quite surprised if we expressed the same database query in C and the C compiler performed the same optimizations; the C compiler does not have enough information about which database columns are indexed, or indeed what a database column is, to recognize the value of the change. Because an SQL engine has more information than a C compiler about the application at hand, it can perform optimizations the lower-level notation obscures.
When a language is highly specialized for a given application, we call it a domain-specific language (see Chapter 3, Domain-Specific Languages, in Volume III of this Handbook); Guiles primary goal is to simplify the design and implementation of domain-specific languages.
Stachowiak and Badross SCWM uses Guile as the foundation for a language for managing windows under the X Window system. In typical use, SCWM looks like any other window manager: The user can move or resize windows by dragging their title bars or borders, iconify windows by clicking title bar buttons, choose actions from pop-up menus, and so on. However, SCWM uses Guile as a configuration language and allows the users to associate their own Scheme procedures with menu items, buttons, and keystrokes.
SCWM extends Guile Scheme with objects representing top-level windows, fonts, and menus (among other things) and provides functions to manipulate these objects. Here is a sample interaction ith SCWM:
At first, there is no window manager running. Start SCWM, and have it prompt for Scheme expressions to run. $ scwm -i What top-level windows are there? scwm> (list-windows) (#<window 12583501> #<window 8388621> #<window 12583671>) Which are iconified? scwm> (map iconified? (list-windows)) All but one. (#t #f #t) Get a list of the non-iconified windows. scwm> (list-windows #:except iconified?) (#<window 8388621>) Store the window in a variable. scwm> (define win (car (list-windows #:except iconified?))) What is its title? scwm> (window-title win) xterm
To help users write configurations and procedures that are somewhat independent of the screen size, SCWM provides the procedures %x and %y, which treat their argument as a percentage of the screen size and return the corresponding number of pixels. Using them, we can define a procedure that makes a window as tall as will fit on the screen and bind that procedure to a key:
Try out the %x and %y procedures. scwm> (%x 100) The screen is 1152 pixels wide 1152 scwm> (%y 100) and 900 pixels high. 900 This procedure makes a window as tall as will fit. scwm> (define (full-height win) (let ((x (car (window-position win))) (width (car (window-size win)))) (move-to x 0 win) (resize-to width (%y 100) win))) Apply our new procedure to the xterm window. scwm> (full-height win) The xterm window is now full-height. #t Bind the function to the F1 key. scwm> (bind-key window F1 (lambda () ;; get-window returns the window in which ;; the user pressed the key. (full-height (get-window)))) scwm>
Previous | Table of Contents | Next |