|make(rp) |insert(../monk/monk.mac) |comment(VOL2HEADER)|set_counter(page 325-1)|set_string(page_headers "'''")|set_string(even_headers "'The C Interpreter: A Tutorial for Cin Version 0.18''\f(NIcin\fP'")|set_string(odd_headers "'\f(NIcin\fP''The C Interpreter: A Tutorial for Cin Version 0.18'")|set_string(even_footers "_\\nP__UNIX Papers_")|set_string(odd_footers "'Research Tenth Edition''\\nP'") |environment(computeroutput; verbatim on, file.information, line.spacing 1, fill off, size -1, space -1, font cw, blank.lines -1, tab.stops "\w' 'u 2u*\w' 'u 3u*\w' 'u 4u*\w' 'u 5u*\w' 'u 6u*\w' 'u 7u*\w' 'u 8u*\w' 'u 9u*\w' 'u 10u*\w' 'u 11u*\w' 'u"; tab.stops, blank.lines -1, SPACE) |author(name "T. J. Kowalski", initials TJK, location MH, department 11229, extension x2771, room 2C-568) |document(number 11229-880606-07TMS, file_case 25952, work_program 311401-2199) |author(name "H. H. Goguen", initials HHG, location MH, department 11229, extension x2771, room 2C-568) |document(number 11229-880606-07TMS, file_case 25952, work_program 311401-2199) |author(name "J. J. Puttress", initials JJP, location MH, department 11229, extension x7290, room 2C-577) |document(number 11229-880606-07TMS, file_case 25952, work_program 311401-2199) |date(June 6, 1988) |title(The C Interpreter: A Tutorial for Cin Version 0.18) |begin(abstract) The C interpreter, |i(cin), is the core of an interactive programming environment for the C programming language. We believe that by providing integrated facilities to create, edit, browse, execute, and debug programs, this environment should enhance the productivity of C programmers at |s(AT&T) and improve the quality of their code. Furthermore, we feel that |i(cin) provides an easy-to-use instructional environment. |p This memorandum is a tutorial guide to help users get started. Although it does not cover everything, it provides enough information for most users' daily needs. Topics discussed include creating simple programs, testing individual functions and expressions, inspecting and modifying variables, using program views, and setting breakpoints. |end(abstract) |titlebox |style(two_column) |unnumbered_section(Introduction) Interactive programming environments are common for |s(LISP), |reference(Teitelman Masinter Interlisp Programming Environment) |reference(Sandewall Programming in an Interactive Environment 1978) |s(PASCAL), |reference(Delisle Menicosy Schwartz Viewing a Programming Environment) |reference(Reiss Graphical Program Development with PECAN) |reference(Brown Sedgewick A System for Algorithm Animation) |s(PL/C), |reference(Archer Conway COPE: A Cooperative Programming Environment) |reference(Teitelbaum Reps The Cornell Program Synthesizer 1981) and Smalltalk. |reference(Goldberg Robson Smalltalk-80: The Language and Its Implementation) |reference(Tesler The Smalltalk Environment) Some work has been done on various pieces of a C program environment, including syntax directed editors, |reference(Horgan Moore Techniques for Improving Language-Based Editors) interpreters, |reference(Saber-C 1988) |reference(Feuer si - An Interpreter for the C Language) |reference(Ostby A C interpreter) debuggers,|reference(Adams Muchnick Dbxtool A Window-Based Symbolic Debugger) |reference(Cargill The Feel of Pi) and browsers. |reference(Steffen Interactive Examination of a C Program with Cscope) |p |i(Cin) is a C interpreter: an interactive program for creating, testing, modifying, and debugging a C program, using directions provided by a user at a terminal. The program can be a single function in a single file, or a large collection of files and functions as in System 75. |reference(System 75: Project Development Environment 1985) |i(Cin) is part of the Integrated C Programming Environment, |cw(cens), currently being developed by Department 11229. It implements correct full C, enables rapid prototyping, permits extensive error checking, facilitates incremental update, manages multiple software views, and provides a programmable command language. |p This tutorial is meant to simplify learning |i(cin). We suggest that you read this document, simultaneously using |i(cin) to follow the examples, then read the manual page in the appendix while continuing to experiment with |i(cin). Furthermore, we strongly recommend completing the exercises. They both reinforce material covered in the text and explore material not thoroughly discussed. |p This is an introduction and a tutorial. For that reason, no attempt is made to cover more than a part of the facilities that |i(cin) offers (although this fraction includes the most useful and frequently needed parts). Explanations of the C language and the |s(UNIX)|sp(registered) system are beyond the scope of this paper. We assume that you know how to log on to a |s(UNIX) system and how to express algorithms in C. Information on both the |s(UNIX) system and C is readily available from a variety of sources. |reference(Kernighan Pike Prentice-Hall) |reference(Kernighan Ritchie Prentice-Hall) |section(Getting Started) We'll assume you have logged in to a |s(UNIX) system and have just received the shell prompt, e.g. ``$''. The easiest way to start |i(cin) is to type |begin(computeroutput) |i($ )cin -i |i(cin>) |end(computeroutput) You are now ready to go |sp(Em dash) |i(cin) is waiting for your instructions. |i(Cin) shows this by echoing a |begin(computeroutput) |i(cin>) |end(computeroutput) to your terminal. Throughout this tutorial, responses from |i(cin) are in |i(italics). |p This section shows how to use the interactive mode of |i(cin), that is, a mode where we can enter and execute programs interactively. Later we'll talk about changing and debugging programs. As our first problem, let's leap the hurdle of creating, compiling, loading, and running a program that prints ``hello, world'' on our terminal. Though this is a painful task when we use the normal editor, compiler, loader, and shell to run the program, it's easy in |i(cin). |p When |i(cin) is started with the |cw(-i) option, it is like working with a blank piece of paper |sp(Em dash) there is no program or data present. They must be supplied by the person using |i(cin). The program, with its data, can be entered interactively or read into |i(cin) from a file. We will start by typing in a program and return shortly to the reading of files. |p First a bit of terminology. In |i(cin) jargon, the program currently worked on is said to be ``kept in the current |cw(view)''. Think of the |cw(view) as a work space, if you like, or simply as the information that you are going to be using. The |cw(view) is like a piece of paper, on which we will write things, then change some of them, and finally file the whole thing away for another day. |p The user tells |i(cin) what to do to the |cw(view) by typing C expressions and declarations. C expressions are executed immediately, while declarations are stored in the |cw(view). When an expression is executed, |i(cin) uses both local and global variables. |p Now we're ready to solve our problem. The easiest way is to write a C expression that calls the |cw(printf) library routine. |begin(computeroutput) |i(cin>) printf("hello, world|sp(\)n"); |i(hello, world cin>) |end(computeroutput) |p Another way to solve our problem is to write a declaration for a |cw(main) function and call it using a C expression. |begin(computeroutput) |i(cin>) void main() { printf("hello, world|sp(\)n"); } |i(cin>) main(); |i(hello, world cin>) |end(computeroutput) |p We draw your attention to the |cw(void main) declaration. When you're in |i(cin)'s interactive mode, you need to declare a return type for each function. This allows |i(cin)'s interactive mode to tell the difference between an expression calling |cw(main) and a declaration of |cw(main). Don't panic! You don't have to change all your C programs. This is only true when typing directly to interactive mode. The normal default declaration, |cw(int), still applies when files are read in. We could have designed |i(cin) to work like the C interpreters referenced in the introduction, which require you to type a special character to enter and leave a command mode, but we felt that declaring a return type was more consistent with C syntax. |p You also saw that |i(cin) prompts only for a C expression or a declaration. Thus, there are no prompts for the function body of |cw(main). This silence is preferred by experienced users, but sometimes disturbs beginners. |p Finally finished with our problem, we'd like to return to our shell. Exit |i(cin) by typing |begin(computeroutput) |i(cin>) cin_quit(); |i($) |end(computeroutput) or by typing the end-of-file character (hold the |s(CTRL) key down and press |cw(d)). |section(I Seemed To Have Confused It) If you didn't get a ``hello, world'', then |i(cin) is confused by the directions it got. Let's look at some possible problems that may have occurred and how to correct them. |p One possibility is |begin(computeroutput) |i($) cin -i |i(cin: not found) |i($) |end(computeroutput) The C interpreter, |i(cin), is not available on your system in the directories specified by your |s(PATH) shell variable. Please contact your system administrator. If your system has |s(EXPTOOLS), the administrator can get |i(cin) from Alan Hastings. Otherwise, your administrator can ask for |i(cin) by sending mail to |cw(research!frodo), including his/her name, department number, telephone number, location, and room number. |p Another possibility is |begin(computeroutput) |i($) cin -i |i(cin>) printff("hello, world|sp(\)n"); |i(interactive mode: 1: warning: 'printff' undefined breakpoint in function 'cin_system' at line 1 of file 'interactive mode' cin>) |end(computeroutput) |cw(printf) was misspelled. Whenever |i(cin) encounters an undefined function or variable, it recursively calls a breakpoint function, |cw(cin_system), which places you in |i(cin)'s interactive mode waiting for input. The simplest corrective action is to return and ignore the problem. We can do this by typing |begin(computeroutput) |i(cin>) cin_return(); |i[interactive mode: 2: warning: call of undefined function (returning 0L) cin>] |end(computeroutput) or by typing the end-of-file character. This acts as if you decided to define a function, |cw(printff), that returns a |cw(long) zero. A future release of |i(cin) will allow you to modify the prompt to show the number of recursive calls to |cw(cin_system). Later we'll talk about additional corrective actions and other predefined |cw(cin_) functions and variables. |p Yet another possibility is |begin(computeroutput) |i($) cin -i |i(cin>) printf("hello, world|sp(\)n") |end(computeroutput) Neither ``hello, world'', nor the |cw(|i(cin>)) prompt appears. You probably forgot to type the last semicolon (|cw(;)). Even experienced users forget the terminating semicolon (|cw(;)) sometimes. If |i(cin) seems to be ignoring you, |begin(computeroutput) |i($) cin -i |i(cin>) printf("hello, world|sp(\)n); |i(interactive mode: 1: newline in string) |end(computeroutput) type an extra line with just a semicolon (|cw(;)) on it, or in some rare cases |begin(computeroutput) |i($) cin -i |i(cin>) void main() { printf("hello, world|sp(\)n); } |i(interactive mode: 3: newline in string interactive mode: 4: syntax error in parameter list of function call) |end(computeroutput) an extra line with just a semicolon (|cw(;)) followed by an extra line with just a closing curly brace (|cw(})) on it. Isn't error recovery wonderful! The next release of |i(cin) will be more friendlier. |p Throughout the rest of the tutorial, we will assume that our typing is perfect. We use the |cw(samuel)|reference(Puttress 1986 browser) editor to remember C statements and declarations in a scratch pad, sending them to |i(cin) whenever we are happy with the syntax. However, you can also remember and send C statements and declarations with |cw(sam), |cw(jim), |cw(emacs), or |cw(inedit). |subsection(Exercise 1) Enter |i(cin) and use the formula |e<degree~ F ~=~ ( 9 / 5 ) ~*~ degree~ C ~+~ 32> to create a conversion table from centigrade or Celsius temperatures to Fahrenheit for 20|sp(degree) C to 30|sp(degree) C. Do this exercise in two different ways: |begin(number_list) |item Write a C expression that calls the |cw(printf) library routine. |item Declare a |cw(main) function and run it in |i(cin). |end(number_list) |section(Writing A Small Program) Our next problem is to write a few routines to print algebraic expression trees. Let's start by declaring the template |cw(node) for our tree. |begin(computeroutput) |i(cin>) struct node { struct node *left; struct node *right; char *value; int type; }; |i(cin>) |end(computeroutput) |p The |cw(left) and |cw(right) fields are pointers to other |cw(node)s. The |cw(value) field holds a character string representing the operator, variable, or constant associated with the node. The |cw(type) field shows the kind of operator, variable, or constant held in |cw(value) field. The allowable types are: |begin(computeroutput) |i(cin>) #define ADD 1 #define SUB 2 #define MUL 3 #define DIV 4 #define EXPT 5 #define UMINUS 6 #define CONST 7 #define VAR 8 |end(computeroutput) |p We'd like to pause and talk about prompts once again. You're probably puzzled why there was only one |i(cin>) for the above set of pre-processor statements. Well, in the 0.18 release |i(cin) prompts only for a C expression or a declaration, and C pre-processor statements are a little different. We think this is a botch and will change it in the next release, but until then it's a feature.|dagnote(Features are bugs that are not yet fixed.) |p Now that we have a data structure, let's write a |cw(prt) routine to display the tree in the format normally used for an equation. This requires an in-order walk; in other words |sp(Em dash) go left as far as you can, print the node, then go right as far as you can. |begin(computeroutput) |i(cin>) void prt(n) struct node *n; { switch(n->type) { default: prt(n->left); printf("%s ", n->value); prt(n->right); break; case UMINUS: printf("%s ", n->value); prt(n->right); break; case CONST: case VAR: printf("%s ", n->value); break; } } |i(cin>) |end(computeroutput) |p A powerful feature of |i(cin) enables a routine to be tested as soon it is written. This way you can make sure it does what you want before incorporating it into a large program. |i(Cin) also takes care of allocating and deallocating data structures for testing. |p Let's test the |cw(prt) function. First we'll include the standard I/O header file so we can turn off output buffering. |begin(computeroutput) |i(cin>) #include <stdio.h> |i(cin>) setbuf(stdout, NULL); |i(cin>) setbuf(stderr, NULL); |i(cin>) |end(computeroutput) Next we let |i(cin) allocate storage space for a sample node, |cw(a1), and set it to hold a constant, |cw(CONST), with a value of |cw(17). Finally, we call |cw(prt) and see it print |cw(17). |begin(computeroutput) |i(cin>) struct node a1; |i(cin>) a1.type = CONST; |i(cin>) a1.value = "17"; |i(cin>) prt(&a1); |i(17 cin>) |end(computeroutput) For constants, |cw(left) and |cw(right) are unused. |p It's likely that we'll want to save our work for later use. A simple and easy way to do this is to save an image of our program and data definitions as an executable file. Let's do this by calling the predefined function |cw(cin_dump) with the name of a file, |cw(./saved). |begin(computeroutput) |i(cin>) cin_dump("./saved"); |i(cin>) cin_quit(); |i($) |end(computeroutput) Any time afterwards we can invoke our saved executable and use the program and data definitions we have just entered. |begin(computeroutput) |i($) ./saved |i(cin>) prt(&a1); |i(17 cin>) |end(computeroutput) This feature is useful for customizing our |i(cin) environment, but in the 0.18 release of |i(cin) there is no way to print out the definition of a given function. We plan to enhance |i(cin) to do this in the future, but for now we recommend using an editor to keep your functions in files. |p Thus, we need to learn how to load source or object files into |i(cin). We'll assume you've returned to your shell, placed the definition for |cw(node) and its |cw(#define)s in |cw(node.h), and placed |cw(#include "node.h") along with the definition for |cw(prt) in |cw(prt.c). |p Now let's go back to |i(cin) and load in the |cw(prt) function. |begin(computeroutput) |i($) cin -i |i(cin>) cin_load("prt.c"); |i(cin>) |end(computeroutput) |p When |i(cin) loaded |cw(prt.c), it placed the structure definition for |cw(node), the |cw(#define)s, and the definition for |cw(prt) in a |cw(view) called |cw(prt.c). A |cw(view) is the internal representation of a C source file |sp(Em dash) |cw(#define)s, static variables and functions, and global declarations. Outside |i(cin), the functions and data of a C program are packaged in a file; inside |i(cin) they are contained in a |cw(view). Earlier, when we typed declarations directly into the interpreter, they were placed into a default |cw(view) called ``interactive mode''. To use the declarations, we need to be in the |cw(view) where they are stored. So if we are sure we defined something, but |i(cin) can't find it, we have probably gotten into the wrong |cw(view). We can see what |cw(view)s are available by using the predefined function |cw(cin_views), and we can change our |cw(view) by using |cw(cin_view). |begin(computeroutput) |i(cin>) cin_views(); |i( prt.c |sp(*) interactive mode cin>) cin_view("prt.c"); |i(cin>) cin_views(); |i( |sp(*) prt.c interactive mode cin>) |end(computeroutput) |p We have just seen that |cw(cin_views) marks our current |cw(view) with an asterisk (|cw(*)). Do not confuse the ``interactive mode'' session, which is entered by typing |cw(cin -i), with the default interactive mode |cw(view). In interactive mode, you may access any |cw(view) and enter C expressions or declarations in the context of that |cw(view). The interactive mode |cw(view) is simply the default |cw(view), used for storing C declarations not associated with an external file. |p Let's use the declaration of |cw(struct node) and the |cw(#define) for |cw(CONST) in the current or |cw(prt.c) |cw(view) to initialize a |cw(struct node a1). |begin(computeroutput) |i(cin>) struct node a1; |i(cin>) a1.type = CONST; |i(cin>) a1.value = "17"; |i(cin>) |end(computeroutput) |p Although we said our typing would be prefect,|dagnote(as you can see it's not) let's see what happens if we make the common mistake of passing a structure instead of a pointer to the structure. |begin(computeroutput) |i(cin>) prt(a1); |i(prt.c: 7: null pointer access breakpoint in function 'prt' at line 7 of file 'prt.c' cin>) |end(computeroutput) |p At this point we can escape to our shell and print a numbered listing of |cw(prt.c). |begin(computeroutput) |i(cin>) system("pr -n -t prt.c"); |i[ 1 #include "node.h" 2 3 void 4 prt(n) 5 struct node |sp(*)n; 6 { 7 switch(n|cw(->)type) { 8 9 default: 10 prt(n|cw(->)left); 11 printf("%s ", n|cw(->)value); 12 prt(n|cw(->)right); 13 break; 14 15 case UMINUS: 16 printf("%s ", n|cw(->)value); 17 prt(n|cw(->)right); 18 break; 19 20 case CONST: 21 case VAR: 22 printf("%s ", n|cw(->)value); 23 break; 24 25 } 26 } cin>] |end(computeroutput) |p By a quick process of elimination, we realize that |cw(n) must be our problem, because line 7 only has one pointer variable. When you are in a |i(cin) breakpoint function, |i(cin) computes the value of expressions in the current execution context |sp(Em dash) an expression is evaluated just as though it were placed in the program source at the current point of execution. Thus, we can check to see if |cw(n) is zero by printing its value. |begin(computeroutput) |i(cin>) printf("%d|sp(\)n", n); |i(0) |i(cin>) |end(computeroutput) |p If we failed to notice our ``passing a structure instead of a pointer to the structure'' typo, we might think that |cw(prt) got into trouble because it called itself. We can check this by using the predefined function |cw(cin_where). |begin(computeroutput) |i(cin>) cin_where(); |i{cin_system() [prt.c:1] prt(n = 0x0) [prt.c:7] cin_system() [interactive mode:32] cin>} |end(computeroutput) This tells us that we are currently in |i(cin)'s breakpoint function, |cw(cin_system), looking at a call of |cw(prt) that was made from interactive mode. Because there are not two calls to |cw(prt), we are assured it didn't recursively call itself. |p As you can see from the reference to line number 32, the authors need to struggle further with what line numbers should mean in interactive mode. In particular, |cw(cin_where) and |cw(cin_break), discussed later, don't seem to use sensible line numbers for functions defined in interactive mode. |p Let's fix the problem with |cw(n) by modifying its value to be |cw(&a1) and allowing the program to continue. |begin(computeroutput) |i(cin>) n = &a1; |i(cin>) cin_return(); |i(17 cin>) |end(computeroutput) Most debuggers don't permit you to continue after a serious error. Whenever possible, |i(cin) allows you to recover from an error once you've taken corrective action. If we don't want to take corrective action, we can remove all calls of |i(cin)'s breakpoint function by calling |cw(exit). |begin(computeroutput) |i(cin>) exit(0); |i(cin>) |end(computeroutput) Sometimes there is no way to fix the problem and all we can do is |cw(cin_quit). |p Now let's define a function that creates a node, placing the function in |cw(create.c). We can enter our favorite editor by |begin(computeroutput) |i(cin>) system("${EDITOR-/bin/ed} foo.c"); |i(?foo.c) |end(computeroutput) and printing out our file |begin(computeroutput) |i(cin>) system("pr -n -t create.c"); |i[ 1 #include <stdio.h> 2 #include "node.h" 3 4 struct node |sp(*) 5 create(left, right, type, value) 6 struct node |sp(*)left, |sp(*)right; 7 char |sp(*)value; 8 { 9 struct node |sp(*)n; 10 struct node |sp(*)memory(); 11 12 if (n = memory( 13 sizeof(struct node))) { 14 n|cw(->)left = left; 15 n|cw(->)right = right; 16 n|cw(->)type = type; 17 n|cw(->)value = value; 18 return(n); 19 } 20 21 fprintf(stderr, 22 "No memory to create a node|sp(\)n"); 23 exit(1); 24 } cin>] cin_load("create.c"); |i[create.c: 8: warning: function 'create' has implicit return and 'return e;' (line 18) cin>] |end(computeroutput) |p The error message warns us that the function |cw(create), which is declared starting on line 8, ends without returning a value. This is fine, because the function |cw(exit) would never let us get to the end of the routine. |p Now let's change our |cw(view) to the |cw(create.c) declarations, make a few nodes, and print the expression tree for |cw[2 * (17 - x)]. We can represent the expression tree graphically as |begin(here) |begin(picture) scale=100 box invis ht 96 wid 144 with .sw at 0,0 "\fR\s10\&|sp(-) (t1)\f1\s0" at 122,42 "\fR\s10\&x (t3)\f1\s0" at 160,-10 "\fR\s10\&17 (t2)\f1\s0" at 80,-10 line from 104,40 to 144,0 line from 104,40 to 64,0 "\fR\s10\&2 (t5)\f1\s0" at 24,26 "\fR\s10\&|sp(*) (t4)\f1\s0" at 80,86 line from 64,80 to 104,40 line from 64,80 to 24,40 |end(picture) |end(here) where the labels in parentheses are the variable names for the |cw(struct node) pointers and the other symbols are the |cw(value)s for the |cw(node)s. |begin(computeroutput) |i(cin>) cin_view("create.c"); |i(cin>) struct node *t1, *t2, *t3; |i(cin>) t3 = create((struct node *)0, (struct node *)0, VAR, "x"); |i(create.c: 12: warning: 'memory' undefined breakpoint in function 'create' at line 12 of file 'create.c' cin>) |end(computeroutput) |p A common programming practice is to leave ``stubs'', or functions to be defined at a later date. |i(Cin) will stop when it encounters functions or variables that are not defined, permitting you to define them. Here |i(cin) has stopped because it can't find a definition for |cw(memory). |begin(computeroutput) |i(cin>) struct node * memory(n) unsigned n; { struct node *malloc(); return malloc(n); } |i(cin>) cin_return(); |i(cin>) t2 = create((struct node *)0, (struct node *)0, CONST, "17"); |i(cin>) t1 = create(t2, t3, ADD, "+"); |i(cin>) struct node *t4, *t5; |i(cin>) t5 = create((struct node *)0, (struct node *)0, CONST, "2"); |i(cin>) t4 = create(t5, t1, MUL, "*"); |i(cin>) prt(t4); |i(2 |sp(*) 17 + x cin>) |end(computeroutput) We'd like to emphasize that declarations can be mixed with C expressions in interactive mode. |subsection(Exercise 2) Use |i(cin) and your favorite editor to enhance the |cw(prt) function by adding parentheses to the output that show the nesting levels; e.g., |cw<prt(t4)> should output |cw<( 2 * ( 17 + x ) )>. |section(Debugging With Breakpoints) We've already seen that any legal C expression can be used when |i(cin) enters the breakpoint function, but we haven't seen how to force |i(cin) to enter a breakpoint function. The easiest way is to use your editor and insert calls to the predefined function |cw(cin_system) into your program. |begin(computeroutput) 1 hello() 2 { 3 int i; 4 i = 17; 5 printf("hello, %d", i); 6 cin_system(); 7 printf("world %d times|sp(\)n", i); 8 } |end(computeroutput) |p So if we were to load in |cw(hello.c) and run it: |begin(computeroutput) cin> |i($) cin -i |i(cin>) cin_load("hello.c"); |i(cin>) hello(); |i(breakpoint in function 'hello' at line 6 of file 'hello.c' hello, 17cin>) i = 3; |i(cin>) cin_return(); |i(world 3 times cin>) |end(computeroutput) We'd be able to change the value of |cw(i), or anything else, for that matter, to whatever we want. This is like placing |cw(printf)'s in our code that allow us to print or modify anything. |p We can obtain a less permanent breakpoint using the predefined function |cw(cin_break), and remove it using |cw(cin_unbreak). Let's return to the original |cw(prt) routine contained in |cw(prt.c), assert a breakpoint on line 7, and run it with |cw(t4). Because we've already debugged |cw(create) and |cw(memory), we can use the C compiler to create object files for them, continuing to debug |cw(prt) in source form. By mixing object files with source files, we get the speed of compiled code for functions that are debugged, combined with the error checking of interpreted code for functions we are testing. |begin(computeroutput) |i($) cc -O -c create.c memory.c |i(create.c: memory.c: $) cin -i prt.c create.o memory.o |i(cin>) cin_view("prt.c"); |i(cin>) struct node *t1, *t2, *t3; |i(cin>) struct node *create(); |i(cin>) #include <stdio.h> |i(cin>) t3 = create((struct node *)0, (struct node *)0, VAR, "x"); |i(cin>) t2 = create((struct node *)0, (struct node *)0, CONST, "17"); |i(cin>) t1 = create(t2, t3, ADD, "+"); |i(cin>) struct node *t4, *t5; |i(cin>) t5 = create((struct node *)0, (struct node *)0, CONST, "2"); |i(cin>) t4 = create(t5, t1, MUL, "*"); |i(cin>) |end(computeroutput) |p |cw(Cin_break) and |cw(cin_unbreak) both require us to be in the |cw(view) where the function is defined and restrict us to functions that are being interpreted. We plan to enhance |i(cin) to remove these restrictions in the future. |begin(computeroutput) |i(cin>) cin_break("prt", 7); |i(breakpoint in function prt at line 7 cin>) prt(t4); |i(breakpoint in function 'prt' at line 7 of file 'prt.c' cin>) cin_return(); |i(breakpoint in function 'prt' at line 7 of file 'prt.c' cin>) cin_return(); |i(breakpoint in function 'prt' at line 7 of file 'prt.c' 2 |sp(*) cin>) cin_where(); |i{cin_system() [prt.c:1] prt(n = 0x9382C) [prt.c:7] prt(n = 0x93854) [prt.c:12] cin_system() [stdio.h:50] cin>} cin_unbreak("prt", 7); |i(breakpoint removed from line 7 in prt cin>) cin_return(); |i(17 + x cin>) cin_quit(); |i($) |end(computeroutput) We plan to enhance |i(cin) by adding another argument to |cw(cin_break). This argument will be a string that is executed when the breakpoint function is entered. This will let us set breakpoints that remove themselves, print interesting things, or even set other breakpoints. |section(Program Equals Data) A common trick of interpreters, especially in the |s(LISP) world, is to use the same representation for data handled by a program and the program text itself. |p As our last programming task in this tutorial, let's write a simple desk calculator. To accomplish this, we need to read a string from the user, wrap it in a |cw(printf) C expression, and pass it to the predefined function |cw(cin_eval). |begin(computeroutput) |i($) cin -i -lm |i(cin>) #include <stdio.h> |i(cin>) #include <math.h> |i(cin>) char buf[1024], buf2[1024]; |i(cin>) while(gets(buf) != NULL) { sprintf(buf2, "printf(|sp(\)"%%g|sp(\)|sp(\)n|sp(\)",(double)(%s));", buf); cin_eval(buf2); } sqrt(2.0) * sqrt(2.0) |i(2) |end(computeroutput) In writing the |cw(printf) expression shown above, the trickiest part was ensuring that the argument would be appropriate to the |cw(g) format. That's what the |cw<(double)> accomplished. This example is also plagued with getting the right number of |sp(\)s and |cw(%)s. |subsection(Exercise 3) Enhance the desk calculator C expression to remember the last value as |cw(t) and make it into a shell file that can be easily executed. |section(Bugs) |center(You find 'em. We squash 'em!) |p The interactive mode is new with the 0.18 release of |i(cin). It's hard to anticipate all the errors you may encounter, and because of this we need your help to improve our tool. Thus, we welcome bug reports sent to research!frodo. Please include a short program along with the terminal input and output that creates the |i(cin) problem. |section(Summary Of Predefined Functions) Several pre-defined functions are provided for the user, where |i(name), |i(string), |i(file), |i(line), |i(func), |i(func_mod), and |i(func_ref) are declared as: |begin(computeroutput) char *|i(name), *|i(string), *|i(file); int |i(line); long (*|i(func))(), (*|i(func_mod))(), (*|i(func_ref))(); |end(computeroutput) |blank_space(-1) |begin(computeroutput) void cin_bind(|i(name), |i(func)) |end(computeroutput) |blank_space(-1) Set an alias of |i(name) for the function |i(func). |begin(computeroutput) int cin_break(|i(name), |i(line)) |end(computeroutput) |blank_space(-1) Set a breakpoint in function |i(name) at line number |i(line) in the current |cw(view). Returns 0 if breakpoint cannot be set. |begin(computeroutput) int cin_dump(|i(name)) |end(computeroutput) |blank_space(-1) Create an |cw(a.out) and place it in the file |i(name). Returns 0 if |i(name) cannot be created. |begin(computeroutput) int cin_eval(|i(string)) |end(computeroutput) |blank_space(-1) Execute the C statement |i(string) as if it were present in the program where the |cw(cin_eval) is located. Returns 0 if |i(string) could not be parsed. |begin(computeroutput) int cin_load(|i(file)) |end(computeroutput) |blank_space(-1) Load |i(file) into a new |cw(view), using the standard file-naming conventions for |i(cc)(1). Returns 0 if |i(file) can not be loaded. |begin(computeroutput) void cin_return() |end(computeroutput) |blank_space(-1) Return from a breakpoint. |begin(computeroutput) int cin_spy(|i(name), |i(func_mod), |i(func_ref)) |end(computeroutput) |blank_space(-1) Call the function |i(func_mod) whenever the variable |i(name) is modified. Call the function |i(func_ref) whenever the variable |i(name) is referenced. Either |i(func_mod) or |i(func_ref) can be |cw<(long (*)())0>. Returns 0 if there are no spies active. |begin(computeroutput) void cin_system() |end(computeroutput) |blank_space(-1) Enter ``interactive mode''. |begin(computeroutput) int cin_unbreak(|i(name), |i(line)) |end(computeroutput) |blank_space(-1) Remove a breakpoint in function |i(name) at line number |i(line) in the current |cw(view). Returns 0 if the breakpoint was not set. |begin(computeroutput) int cin_view(|i(name)) |end(computeroutput) |blank_space(-1) Change the current |cw(view) to |i(name). Returns 0 if the |cw(view) was not found. |begin(computeroutput) void cin_views() |end(computeroutput) |blank_space(-1) Print the available |cw(view)s. The current |cw(view) is marked with an asterisk (|cw(*)). |begin(computeroutput) void cin_whatis(|i(name)) |end(computeroutput) |blank_space(-1) Print the type of the variable |i(name). |begin(computeroutput) void cin_where() |end(computeroutput) |blank_space(-1) Print the trace of subroutine calls. |begin(computeroutput) void cin_quit() |end(computeroutput) |blank_space(-1) Exit |i(cin). |section(Summary Of Predefined Variables) Several predefined variables are provided for the user. |begin(computeroutput) extern char *cin_libpath |end(computeroutput) |blank_space(-1) A colon (|cw(:)) -separated list of libraries to search for undefined routines (defaults to libraries specified on the command line and ``|cw(-lc)''). |begin(computeroutput) extern char *cin_prompt |end(computeroutput) |blank_space(-1) The ``interactive mode'' prompt (default ``|cw(cin>) ''). |section(Answers) |subsection(Answer 1) |blank_space(-1) |begin(computeroutput) |i($) cin -i |i(cin>) int i; |i(cin>) for (i = 20; i <= 30; ++i) printf("%d %g|sp(\)n", i, 9. / 5. * i + 32.); |i(20 68 21 69.8 22 71.6 23 73.4 24 75.2 25 77 26 78.8 27 80.6 28 82.4 29 84.2 30 86 cin>) void main() { int i; for (i = 20; i <= 30; ++i) printf("%d %g|sp(\)n", i, 9. / 5. * i + 32.); } |i(cin>) main(); |i(20 68 21 69.8 22 71.6 23 73.4 24 75.2 25 77 26 78.8 27 80.6 28 82.4 29 84.2 30 86 cin>) cin_quit(); |i($) |end(computeroutput) |blank_space(-1) |subsection(Answer 2) |blank_space(-1) |begin(computeroutput) void prt(n) struct node *n; { switch(n->type) { default: printf("( "); prt(n->left); printf("%s ", n->value); prt(n->right); printf(") "); break; case UMINUS: printf("%s ", n->value); prt(n->right); break; case CONST: case VAR: printf("%s ", n->value); break; } } |end(computeroutput) |blank_space(-1) |subsection(Answer 3) |blank_space(-1) |begin(computeroutput) (echo 'extern char *cin_prompt; cin_prompt=""; #include <stdio.h> #include <math.h> char buf[1024], buf2[1024]; double t; while(gets(buf) != NULL) { sprintf(buf2, "printf(|sp(\)"%%g|sp(\)|sp(\)n|sp(\)",t=(double)(%s));", buf); cin_eval(buf2); }'; cat ) | cin -i |end(computeroutput) |blank_space(-1) |section(Acknowledgements) We thank Brian Kernighan for permission to draw inspiration and borrow phrases from his editor tutorial. We also thank Sumit Bandyopadhyay, Bill Carpenter, Paul De Bra, Alan Hastings, Jonathan Helfman, Andrew Hume, Leonard Kasday, Brian Kernighan, Tom Kirk, David Korn, Lisa Kowalski, Richard Maus, Lawrence Mayka, Doug McIlroy, Marcel Meth, Eric Muehrcke, Jishnu Mukerji, Rob Murray, Sharon Peeters, Mike Riley, Larry Satz, Judy Schmidt, Timothy Schroeder, Jonathan Shapiro, Joe Steffen, Andy Tripp, Tom Walsh, William Wetzel, and Myron Wish for useful comments on previous versions of this paper. |comment< |style(one_column) |signature(MH-11229-TJK/HHG/JJP-tjk/hhg/jjp) > |comment< |notation(Att. References) |other > |reference_placement |keywords(Rapid Prototyping, Incremental Update, C Programming) |comment< |mercury(cmp, elc) |att(is_release yes) |distribute_complete_memo(Executive Directors 112 Directors 112 Department Heads 1122 Sumit Bandyopadhyay Bill Carpenter Paul De Bra Alan Hastings Jonathan Helfman Yean-Ming Huang Andrew Hume Leonard Kasday Brian Kernighan Tom Kirk David Korn Lisa Kowalski Richard Maus Lawrence Mayka Doug McIlroy Marcel Meth Eric Muerhcke Jishnu Mukerji Rob Murray Sharon Peeters Mike Riley Larry Satz Judy Schmidt Timothy Schroeder Jonathan Shapiro Joe Steffen Andy Tripp Tom Walsh William Wetzel) |distribute_cover_sheet(A. A. Penzias 1122 MTS Miguel Abdo Tom Beattie Jim Burnash Tom Cargill John Carter Craig Cleaveland Don deCourcelle Helen Diamantidis Laura Eaves Faiq Fazal Tom Foregger Carol Franklin Narain Gehani Richard Greer John Gregg Jim Grenier Inars Gruntals Roy Harkness Kurt Haserodt Alan Hewett Viet Hoang James Holmes Mike Hudson Douglas Johnston Jon Kaplowitz Kevin Kinnear Peter Kirslis Balachander Krishnamurthy Ajoy Kumar David Lubinsky Robert Lyons John Malleo-Roach Pat McGowan Al McPherson Douglas Miller Datta Miruke John Mocenigo Dave Neal Eric Olson Joseph Patterson Virginia Piccininni Thomas Pisciotta David Potter Demetri Prountzos Benjamin Reytblat Ernie Rice James Rowland Ed Schan William Schell Carl Seaquist Steve Shepherd John Sherman Tyrone Shiu Les Shupe David Smull G. Mark Stewart Art Storm Rich Struse Mark Swartz Rick Thomas Tim Thompson Peter Ting Gregg Vesonder Yu-Lien Yen John Young Avi Zahavi) |add_totals(other 4) |cover_sheet >