/* @(#)lex.c 1.9 89/12/11 * * Lexical routines used by the popi program. * * Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs. * This version is based on the code in his Prentice Hall book, * "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7, * which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. * * Permission is given to distribute these extensions, as long as these * introductory messages are not removed, and no monies are exchanged. * * No responsibility is taken for any errors or inaccuracies inherent * either to the comments or the code of this program, but if reported * (see README file) then an attempt will be made to fix them. */ #include #include #include #include "popi.h" /* prototypes for local functions */ int Getch P((void)); int getnumber P((int)); int getstring P((int)); int follow P((int, int, int)); int CharPos = 0, /* Current character pos on input line */ OldPos = 0, /* previous character pos on input line */ TokPos = 0; /* position of the beginning of the current token */ char ErrBuf[256]; double lexfract; double hypot(); static int Getch() { int c; c = disp_getchar(); OldPos = CharPos; if (c == '\t') CharPos = (CharPos - 1) % 8 + 8; else if (c == '\n') CharPos = 0; else ++CharPos; DEBUG((Debug, "Getch() => '%c'\n", c)); if (LogStr) PUTC(c, LogStr); return c; } /* Skip to the end of the line */ void Skip() { while (lat != '\n' && lat != EOF) lat = Getch(); lat = '\n'; } void error(errtype) int errtype; { DEBUG((Debug, "error: type %d, pos %d msg '%s'\n", errtype, TokPos, ErrBuf)); if (!noerr) /* Already printed a message */ return; disp_error(errtype, TokPos); Skip(); noerr = FALSE; /* an error has occurred */ if (LogStr) FPRINTF(LogStr, "Error: %s\n", ErrBuf); } static int getnumber(first) int first; { int c; lexval = first - '0'; lexfract = 0.0; while (isdigit(c = Getch())) lexval = 10 * lexval + c - '0'; /* Some of the special routines use floating values */ if (c == '.') { double div = 10.0; while (isdigit(c = Getch())) { lexfract += (c - '0') / div; div *= 10.0; } } pushback(c); return VALUE; } static int getstring(first) int first; { int c = first; char *str = text; do { *str++ = (char) c; c = Getch(); } while (isalpha(c) || c == '_' || isdigit(c)); *str = '\0'; pushback(c); if (strcmp(text, "new") == 0) return NEW; else if (strcmp(text, "sin") == 0) return SIN; else if (strcmp(text, "cos") == 0) return COS; else if (strcmp(text, "atan") == 0) return ATAN; else if (strcmp(text, "hypot") == 0) return HYPOT; else if (strcmp(text, "abs") == 0) return ABS; else if (strcmp(text, "log") == 0) return LOG; else if (strcmp(text, "sqrt") == 0) return SQRT; else if (strcmp(text, "rand") == 0) return RAND; for (c = 0; c < nsrc; c++) if (src[c].str && strcmp(src[c].str, text) == 0) { lexval = c - 1; return INAME; } if (strlen(text) > 1) return NAME; return first; } static int follow(tok, ifyes, ifno) int tok, ifyes, ifno; { int c; if ((c = Getch()) == tok) return ifyes; pushback(c); return ifno; } /* * Set the global lookahead token "lat". */ void lex() { DEBUG((Debug, "lex():\n")); do /* ignore white space */ lat = Getch(); while (lat == ' ' || lat == '\t'); TokPos = CharPos; if (isdigit(lat)) lat = getnumber(lat); else if (isalpha(lat) || lat == '_') lat = getstring(lat); switch (lat) { case EOF: lat = 'q'; break; case '*': lat = follow('*', POW, lat); break; case '>': lat = follow('=', GE, lat); lat = follow('>', RSHIFT, lat); break; case '<': lat = follow('=', LE, lat); lat = follow('<', LSHIFT, lat); break; case '!': lat = follow('=', NE, lat); break; case '=': lat = follow('=', EQ, lat); break; case '|': lat = follow('|', OR, lat); break; case '&': lat = follow('&', AND, lat); break; case 'Z': lat = VALUE; lexval = Zmax; break; case 'Y': lat = VALUE; lexval = Ysize - 1; break; case 'X': lat = VALUE; lexval = Xsize - 1; break; case 'R': lat = VALUE; lexval = (int) hypot(Xsize / 2.0, Ysize / 2.0); break; case 'A': lat = VALUE; lexval = 360; break; case '"': { char *str; str = text; while ((lat = Getch()) != EOF && lat != '\n' && lat != '"') *str++ = (char) lat; *str = '\0'; if (lat != '"') { SPRINTF(ErrBuf, "Expected matching '\"'"); error(ERR_PARSE); return; } } lat = FNAME; break; case ';': /* comment to end of line */ Skip(); lat = '\n'; break; default: break; } if (Debug) { if (lat < 127 && isprint(lat)) DEBUG((Debug, "lex() => '%c' (%d)\n", lat, lat)); else DEBUG((Debug, "lex() => (%d)\n", lat)); } } void pushback(c) int c; { DEBUG((Debug, "pushback('%c')\n", c)); disp_ungetc(c); CharPos = OldPos; }