|
|
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.