|
|
1.1 root 1:
2: /*
3: *
4: * Simple scanner and recursive descent parser used to handle raster file
5: * editing expressions.
6: *
7: * These were the last routines I wrote and by the time I got done it was
8: * pretty clear that I should have written writevalue(), readvalue(), and
9: * getvalue() a little differently. Anyway things seem to work OK even
10: * though everything could have been better, so I'm not going to change
11: * things right now.
12: *
13: */
14:
15:
16: #include <stdio.h>
17: #include <ctype.h>
18:
19: #include "gen.h" /* general purpose definitions */
20: #include "rast.h" /* Imagen raster file definitions */
21: #include "buildrast.h" /* really just for Charinfor def */
22: #include "editrast.h" /* defs primarily used by scanner */
23:
24:
25: FILE *fpin; /* everything comes from this FILE */
26: char buf[50]; /* input buffer */
27:
28:
29: Tokens tokens[] = { /* tokens recognized by scanner */
30:
31: "=", ASSIGNOP,
32: "(", LPAREN,
33: ")", RPAREN,
34: "+", PLUS,
35: "-", MINUS,
36: "*", TIMES,
37: "/", DIVIDE,
38: "xref", XREF,
39: "yref", YREF,
40: "height", HEIGHT,
41: "width", WIDTH,
42: "chwidth", CHWIDTH,
43: "endedit", ENDEDIT,
44: "build", BUILD
45:
46: };
47:
48:
49: int lasttoken; /* code identifying last token read */
50:
51:
52: extern Charinfo charinfo[]; /* used as the symbol table - sort of */
53: extern first, last; /* valid entries are in this closed interval */
54:
55:
56: /*
57: *
58: * Everything's done in floating point, so all the routines that handle the
59: * parsing need to be declared as float.
60: *
61: */
62:
63:
64: float expr(), exprprime(), term(), termprime(), factor();
65:
66:
67: /*****************************************************************************/
68:
69:
70: edit(fp)
71:
72:
73: FILE *fp; /* reading stuff from this file */
74:
75:
76: {
77:
78:
79: char name[20]; /* of the character we're editing */
80: int lhs_index; /* location in charinfo[] */
81: int lhs_field; /* field we want to change */
82: int value; /* of the expression */
83:
84:
85: /*
86: *
87: * Called when we want to process editing expressions from file *fp.
88: *
89: */
90:
91:
92: fpin = fp; /* nexttoken() reads from fpin */
93:
94: nexttoken(); /* loop assumes we've read first token */
95:
96: while ( lasttoken != ENDEDIT && lasttoken != BUILD ) {
97:
98: if ( (lhs_field = lasttoken) != XREF && lhs_field != YREF && lhs_field != CHWIDTH )
99: error(FATAL, "illegal assignment");
100:
101: fscanf(fpin, "%s", name);
102: if ( (lhs_index = lookup(name)) == -1 )
103: error(FATAL, "can't find character %s", name);
104:
105: nexttoken(); /* better be an assignment operator */
106: if ( lasttoken != ASSIGNOP )
107: error(FATAL, "missing assignment operator");
108:
109: nexttoken(); /* first token in the expression */
110: value = expr() + .5;
111:
112: if ( lhs_field == XREF )
113: writevalue(value, G_XREF, charinfo[lhs_index].glydir + rst[G_XREF].offset);
114: else if ( lhs_field == YREF )
115: writevalue(value, G_YREF, charinfo[lhs_index].glydir + rst[G_YREF].offset);
116: else if ( lhs_field == CHWIDTH )
117: charinfo[lhs_index].chwidth = value;
118:
119: } /* End while */
120:
121: } /* End of edit */
122:
123:
124: /*****************************************************************************/
125:
126:
127: lookup(name)
128:
129:
130: char *name; /* find this guy in charinfo[] */
131:
132:
133: {
134:
135:
136: int i; /* loop index for lookups */
137:
138:
139: /*
140: *
141: * Looks for character *name in the charinfo[] array. If it's found its
142: * index is returned to the caller, otherwise -1 is returned. We need to
143: * know the values of first and last so we can properly restrict the search.
144: * They're must be declared and set in whatever files use these routines.
145: * For now it only includes buildrast.c, but we may want to make the editing
146: * stuff more general.
147: *
148: */
149:
150:
151: for ( i = first; i <= last; i++ )
152: if ( strcmp(name, charinfo[i].name) == 0 )
153: return(i);
154:
155: return(-1);
156:
157: } /* End of lookup */
158:
159:
160: /*****************************************************************************/
161:
162:
163: nexttoken()
164:
165:
166: {
167:
168:
169: int i; /* loop index for lookups in tokens[] */
170:
171:
172: /*
173: *
174: * Reads the input file *fpin looking for the next token. A code identifying
175: * it is saved in lasttoken and the actual token string is saved in buf[].
176: * If we reach EOF lasttoken will be set to ENDEDIT.
177: *
178: */
179:
180:
181: if ( fscanf(fpin, "%1s", buf) == EOF ) {
182: lasttoken = ENDEDIT;
183: return;
184: } /* End if */
185:
186: if ( isdigit(buf[0]) ) { /* must be a constant - integers only */
187: fscanf(fpin, "%[0-9]", &buf[1]);
188: lasttoken = CONSTANT;
189: return;
190: } /* End if */
191:
192: if ( isalpha(buf[0]) ) /* get the rest of the token */
193: fscanf(fpin, "%[a-zA-Z]", &buf[1]);
194:
195: for ( i = 0; i < sizeof(tokens); i++ )
196: if ( strcmp(buf, tokens[i].str) == 0 ) {
197: lasttoken = tokens[i].code;
198: return;
199: } /* End if */
200:
201: error(FATAL, "don't recognize token %s", buf);
202:
203: } /* End of nexttoken */
204:
205:
206: /*****************************************************************************/
207:
208:
209: float expr()
210:
211:
212: {
213:
214:
215: /*
216: *
217: * Handles the productions:
218: *
219: * EXPR -> TERM EXPR'
220: *
221: */
222:
223:
224: return(exprprime(term()));
225:
226: } /* End of expr */
227:
228:
229: /*****************************************************************************/
230:
231:
232: float exprprime(val)
233:
234:
235: float val; /* add stuff to this guy */
236:
237:
238: {
239:
240:
241: /*
242: *
243: * Handles the productions:
244: *
245: * EXPR' -> + TERM EXPR'
246: * EXPR' ->
247: *
248: */
249:
250:
251: if ( lasttoken == PLUS ) {
252: nexttoken();
253: return(exprprime(val + term()));
254: } else if ( lasttoken == MINUS ) {
255: nexttoken();
256: return(exprprime(val - term()));
257: } else return(val);
258:
259: } /* End of exprprime */
260:
261:
262: /*****************************************************************************/
263:
264:
265: float term()
266:
267:
268: {
269:
270:
271: /*
272: *
273: * Handles the production:
274: *
275: * TERM -> FACTOR TERM'
276: *
277: */
278:
279:
280: return(termprime(factor()));
281:
282: } /* End of term */
283:
284:
285: /*****************************************************************************/
286:
287:
288: float termprime(val)
289:
290:
291: float val; /* value up to this point */
292:
293:
294: {
295:
296:
297: /*
298: *
299: * Handles the productions:
300: *
301: * TERM' -> * FACTOR TERM'
302: * TERM' -> / FACTOR TERM'
303: * TERM' ->
304: *
305: */
306:
307:
308: if ( lasttoken == TIMES ) {
309: nexttoken();
310: return(termprime(val * factor()));
311: } else if ( lasttoken == DIVIDE ) {
312: nexttoken();
313: return(termprime(val / factor()));
314: } else return(val);
315:
316: } /* End of termprime */
317:
318:
319: /*****************************************************************************/
320:
321:
322: float factor()
323:
324:
325: {
326:
327:
328: float val; /* value of the factor */
329:
330:
331: /*
332: *
333: * Handles the productions:
334: *
335: * FACTOR -> ( EXPR )
336: * FACTOR -> - EXPR
337: * FACTOR -> CONSTANT
338: * FACTOR -> IDENT
339: *
340: */
341:
342:
343: if ( lasttoken == CONSTANT ) {
344: val = atoi(buf);
345: nexttoken();
346: } else if ( lasttoken == MINUS )
347: val = exprprime(0);
348: else if ( lasttoken == LPAREN ) {
349: nexttoken();
350: val = expr();
351: if ( lasttoken == RPAREN )
352: nexttoken();
353: else error(FATAL, "expression syntax error - missing right paren");
354: } else if ( lasttoken == XREF || lasttoken == YREF || lasttoken == HEIGHT || lasttoken == WIDTH || lasttoken == CHWIDTH ) {
355: val = charvalue(lasttoken);
356: nexttoken();
357: } else error(FATAL, "syntax error - don't recognize factor");
358:
359: return(val);
360:
361: } /* End of factor */
362:
363:
364: /*****************************************************************************/
365:
366:
367: charvalue(tok)
368:
369:
370: int tok; /* number of the last token */
371:
372:
373: {
374:
375:
376: char name[20]; /* name of the character to lookup */
377: int i; /* its index in charinfo[] */
378:
379:
380: /*
381: *
382: * Called when we want to get the value of XREF, YREF, HEIGHT, WIDTH, or
383: * CHWIDTH for a character. The guy we'll be looking up is the next string
384: * in the input file.
385: *
386: * It's really clear that things, especially readvalue(), could have been
387: * done better - sorry.
388: *
389: */
390:
391:
392: fscanf(fpin, "%s", name);
393: if ( (i = lookup(name)) == -1 )
394: error(FATAL, "can't find character %s", name);
395:
396: if ( tok == XREF )
397: return(readvalue(charinfo[i].glydir + rst[G_XREF].offset, rst[G_XREF].size, rst[G_XREF].type));
398: else if ( tok == YREF )
399: return(readvalue(charinfo[i].glydir + rst[G_YREF].offset, rst[G_YREF].size, rst[G_YREF].type));
400: else if ( tok == HEIGHT )
401: return(readvalue(charinfo[i].glydir + rst[G_HEIGHT].offset, rst[G_HEIGHT].size, rst[G_HEIGHT].type));
402: else if ( tok == WIDTH )
403: return(readvalue(charinfo[i].glydir + rst[G_WIDTH].offset, rst[G_WIDTH].size, rst[G_WIDTH].type));
404: else error(FATAL, "CHWIDTH not implemented yet");
405:
406: } /* End of charvalue */
407:
408:
409: /*****************************************************************************/
410:
411:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.