* better
[mascara-docs.git] / lang / C / the.ansi.c.programming.language / notes.accompany.ansi.c / homework / PS6a.html
blob37c41fe1b3d2e80b551d3a8b7d99a55f6d94985b
1 <!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">
2 <html>
3 <head>
4 <link rev="owner" href="mailto:scs@eskimo.com">
5 <link rev="made" href="mailto:scs@eskimo.com">
6 <title>Assignment #6 Answers</title>
7 </head>
8 <body>
9 <H1>Assignment #6 Answers</H1>
15 <B>Intermediate C Programming
16 <br>
17 <br>
18 UW Experimental College
19 </B><br>
20 <br>
21 <B>Assignment #6 ANSWERS
22 </B><br>
23 <br>
24 <p>Exercise 2.
25 <I>Modify <TT>io.c</TT> to recognize a new <TT>entrypoint</TT> line
26 in the data file.
27 </I><p>Here is the code I added to <TT>io.c</TT>.
28 Rather than calling <TT>findroom</TT> right away,
29 and face the possibility of the room not being defined yet,
30 I chose to just stash the name of the room away
31 (as a string),
32 and then try looking it up after the data file had been
33 completely read.
34 I added this declaration at the beginning of
35 <TT>parsedatafile</TT>:
36 <pre>
37 char *entryroom = NULL;
38 </pre>
39 I added this case to the main <TT>if</TT>/<TT>else</TT> chain
40 in <TT>parsedatafile</TT>:
41 <pre>
42 else if(strcmp(av[0], "entrypoint") == 0)
44 struct room *roomp;
45 if(ac &lt; 2)
47 fprintf(stderr, "missing entry room name\n");
48 continue;
50 /* don't bother to look up yet; just save name */
51 entryroom = chkstrdup(av[1]);
53 </pre>
54 I added this code at the end
55 of <TT>parsedatafile</TT>:
56 <pre>
57 if(entryroom != NULL)
59 struct room *roomp = findroom(entryroom);
60 if(roomp != NULL)
61 setentryroom(roomp);
62 else fprintf(stderr, "can't find entry room %s\n", entryroom);
64 </pre>
65 Finally, I added the new <TT>setentryroom</TT> function in <TT>rooms.c</TT>:
66 <pre>
67 void
68 setentryroom(struct room *roomp)
70 entryroom = roomp;
72 </pre>
73 <p>Exercise 3.
74 <I>Think about what it would take
75 to use the <TT>cmdtab</TT> structure,
76 and the <TT>findcmd</TT> function,
77 to streamline the code that processes lines in the data file.
78 </I><p>It would initially seem straightforward to take each case in the
79 <TT>if</TT>/<TT>else</TT> chain,
80 break it out to a separate function,
81 build a table
82 (an array of <TT>struct cmdtab</TT>)
83 linking the first words on lines in the data file
84 to the new functions for parsing those lines,
85 and finally call <TT>findcmd</TT>
86 (after reading each line)
87 to decide which function to call.
88 <p>The first problem you might face, though,
89 would be breaking up the old <TT>parsedatafile</TT> function.
90 It contains a number of local variables
91 (especially <TT>currentroom</TT> and <TT>currentobject</TT>)
92 which several of the parsing cases need access to.
93 Once you broke those parsing cases out into separate functions,
94 they'd need access to the (formerly local) variables somehow.
95 You'd probably have to make them global,
96 although you could restrict them to the source file <TT>io.c</TT>
97 by declaring them <TT>static</TT>.
98 <p>The next problem you'd face would be deciding which information
99 to pass to the broken-out functions.
100 Most of them use the <TT>av</TT> array to inspect the various
101 arguments and other words which appeared on the line they're parsing,
102 but for at least one way I wrote the long description reading code,
103 it needed to use the original
104 copy of the complete data file input line
105 (that is, the <TT>line</TT> array),
106 the copy that hadn't been
107 broken apart by <TT>getwords</TT>.
108 The obvious information to pass to each parsing function is
109 the <TT>ac</TT> count and the <TT>av</TT> array
110 (which are, not coincidentally,
111 quite similar to the <TT>argc</TT> and <TT>argv</TT> with which
112 <TT>main</TT> is traditionally called).
113 Would you have to pass along the unbroken <TT>line</TT> to all functions,
114 for the benefit of just the one or two that needed it?
115 (Remember, all the functions must accept the same argument list,
116 because one function call, using the function pointer in the
117 <TT>func</TT> field of the matching <TT>struct cmdtab</TT>
118 entry, will be calling all of them.)
119 <p>Finally, once you decided what information to pass to each
120 individual line parsing function,
121 you'd discover (if you've got strict prototype checking turned on
122 in your compiler, and if you used <TT>cmdtab.c</TT> and
123 <TT>cmdtab.h</TT> as they appeared in last week's handout),
124 that the compiler doesn't want you to create an array of
125 <TT>struct cmdtab</TT> with the <TT>func</TT> fields pointing
126 at your shiny new functions,
127 because the <TT>func</TT> field
128 (again, as it appeared in last week's handout),
129 is specifically a pointer to a function accepting
130 a <TT>struct actor *</TT>,
131 a <TT>struct object *</TT>,
132 and a <TT>struct sentence *</TT>,
133 which is almost certainly <em>not</em>
134 the set of data
135 you chose to pass to each data file parsing function.
136 You'd either have to revert the declaration of the <TT>func</TT>
137 field to
138 <pre>
139 int (*func)();
140 </pre>
141 (as it was on the disk)
142 and turn off strict prototype checking,
143 or write a second whole version of <TT>struct cmdtab</TT> and
144 a second whole version of <TT>findcmd</TT> that used
145 <TT>func</TT> fields with a different prototype,
146 or play some
147 (fairly ugly)
148 games with function pointer casts.
149 <hr>
150 <hr>
152 This page by <a href="http://www.eskimo.com/~scs/">Steve Summit</a>
153 // <a href="copyright.html">Copyright</a> 1995-9
154 // <a href="mailto:scs@eskimo.com">mail feedback</a>
155 </p>
156 </body>
157 </html>