|
|
1.1 ! root 1: #include <stdio.h> ! 2: #include <ctype.h> ! 3: #include <setjmp.h> ! 4: #include "bc.h" ! 5: #include "yy.h" ! 6: ! 7: /* ! 8: * The jump buffer lexenv is used to hold the environment in ! 9: * yylex that will be returned to if there is some lexical ! 10: * error. ! 11: */ ! 12: ! 13: static jmp_buf lexenv; ! 14: ! 15: ! 16: /* ! 17: * Lexerror issues the appropriate error message on stderr and ! 18: * then longjumps back to lex which return ERROR. ! 19: */ ! 20: ! 21: lexerror(str) ! 22: char *str; ! 23: { ! 24: gerror("%r", &str); ! 25: longjmp(lexenv, TRUE); ! 26: } ! 27: ! 28: /* ! 29: * This buffer is used for strings, words, and shell commands. ! 30: */ ! 31: static char buff[MAXSTRING]; ! 32: ! 33: /* ! 34: * Yylex is the lexical analyzer for bc. ! 35: */ ! 36: ! 37: yylex() ! 38: { ! 39: register int ch; ! 40: register int nexteq; ! 41: register FILE *inf = infile; ! 42: static int newline = TRUE; /* TRUE iff at start of line */ ! 43: char *getword(); ! 44: char *getqs(); ! 45: ! 46: Again: ! 47: if (setjmp(lexenv)) ! 48: return ERROR; ! 49: ch = getc(inf); ! 50: if (newline && ch == '!') { ! 51: shell(); ! 52: goto Again; ! 53: } ! 54: while (ch == '\t' || ch == ' ') ! 55: ch = getc(inf); ! 56: if (inline != 0 && newline == TRUE) ! 57: inline += 1; ! 58: if (ch == '\n' || ch == EOF) { ! 59: newline = TRUE; ! 60: return (ch); ! 61: } else ! 62: newline = FALSE; ! 63: if ( ! isascii(ch)) ! 64: lexerror("Illegal character: %d", ch); ! 65: if (isalpha(ch)) ! 66: return (token(getword(ch))); ! 67: if (isdigit(ch)) { ! 68: if (digit(ch) < ibase) { ! 69: yylval.lvalue = getnum(ch); ! 70: return (NUMBER); ! 71: } ! 72: lexerror("Illegal digit: %c", ch); ! 73: } ! 74: if (ch == '.') { ! 75: ch = getc(inf); ! 76: ungetc(ch, inf); ! 77: if (digit(ch) < ibase) { ! 78: yylval.lvalue = getnum('.'); ! 79: return (NUMBER); ! 80: } ! 81: return (DOT); ! 82: } ! 83: nexteq = next('='); ! 84: switch (ch) { ! 85: case '+': return (nexteq ? ADDAB : (next('+') ? INCR : ch)); ! 86: case '-': return (nexteq ? SUBAB : (next('-') ? DECR : ch)); ! 87: case '*': return (nexteq ? MULAB : ch); ! 88: case '%': return (nexteq ? REMAB : ch); ! 89: case '^': return (nexteq ? EXPAB : ch); ! 90: case '/': ! 91: if (!nexteq && next('*')) { ! 92: do { ! 93: ch = getc(inf); ! 94: } while (ch != '*' || !next('/')); ! 95: goto Again; ! 96: } ! 97: return (nexteq ? DIVAB : ch); ! 98: case '=': return (nexteq ? EQP : ch); ! 99: case '<': return (nexteq ? LEP : LTP); ! 100: case '>': return (nexteq ? GEP : GTP); ! 101: case '!': return (nexteq ? NEP : ch); ! 102: case '"': ! 103: yylval.svalue = getqs(); ! 104: return(STRING); ! 105: default: ! 106: if (nexteq) ! 107: ungetc('=', inf); ! 108: return(ch); ! 109: } ! 110: } ! 111: ! 112: /* ! 113: * Next returns TRUE iff the next character on input is "testc". ! 114: * If the next character is not "testc" then it is pushed back ! 115: * for later consumption. ! 116: */ ! 117: ! 118: int ! 119: next(testc) ! 120: char testc; ! 121: { ! 122: register int ch; ! 123: register int result; ! 124: ! 125: ch = getc(infile); ! 126: if (! (result = ch == testc)) ! 127: ungetc(ch, infile); ! 128: return(result); ! 129: } ! 130: ! 131: /* ! 132: * Getqs reads in a quoted string. It assumes that the initial ! 133: * double quote has already been read in and it returns a pointer ! 134: * to an allocated area where the string has been copyied. ! 135: */ ! 136: ! 137: char * ! 138: getqs() ! 139: { ! 140: register char *ptr; ! 141: register int ch; ! 142: ! 143: ptr = buff; ! 144: while ((ch = getc(infile)) != '"') { ! 145: if (ch == EOF || ch == '\n') ! 146: lexerror("Unexpected end of quoted string"); ! 147: if (ptr < &buff[MAXSTRING]) ! 148: *ptr++ = ch; ! 149: } ! 150: if (ptr >= &buff[MAXSTRING]) ! 151: lexerror("String too long"); ! 152: *ptr = '\0'; ! 153: ptr = (char *)mpalc(1 + ptr - buff); ! 154: strcpy(ptr, buff); ! 155: return (ptr); ! 156: } ! 157: ! 158: /* ! 159: * Token looks up the string pointed to by "word" in the ! 160: * list of keywords. If the word is found, then it returns ! 161: * the corresponding value. If not, then it makes sure that ! 162: * the string is in the string table, sets yylval to a pointer to ! 163: * the string table entry and returns IDENTIFIER. ! 164: */ ! 165: ! 166: int ! 167: token(word) ! 168: char *word; ! 169: { ! 170: static struct keyword { ! 171: char *key; ! 172: int keyval; ! 173: } keywords[] = { ! 174: "auto", AUTO, "break", BREAK, "continue", CONTINUE, ! 175: "define", DEFINE, "do", DO, "else", ELSE, ! 176: "for", FOR, "ibase", IBASE, "if", IF, ! 177: "length", LENGTH_, "obase", OBASE, "quit", QUIT, ! 178: "return", RETURN_, "scale", SCALE_, "sqrt", SQRT_, ! 179: "while", WHILE ! 180: }; ! 181: register struct keyword *probe; ! 182: register struct keyword *fwa = keywords; ! 183: register struct keyword *lwa = &keywords[nel(keywords) - 1]; ! 184: int cmp; ! 185: dicent *lookword(); ! 186: ! 187: while (fwa <= lwa) { ! 188: probe = fwa + (lwa - fwa) / 2; ! 189: cmp = strcmp(word, probe->key); ! 190: if (cmp > 0) ! 191: fwa = probe + 1; ! 192: else if (cmp < 0) ! 193: lwa = probe - 1; ! 194: else ! 195: return (probe->keyval); ! 196: } ! 197: yylval.dvalue = lookword(word); ! 198: return (IDENTIFIER); ! 199: } ! 200: ! 201: /* ! 202: * Lookword looks up the string str in the string table dictionary. ! 203: * If it is not already there, then it adds it and initializes the ! 204: * type fields to indicate it as undefined. ! 205: * It returns the pointer to the dictionary entry for the string. ! 206: */ ! 207: ! 208: dicent * ! 209: lookword(str) ! 210: char *str; ! 211: { ! 212: register dicent **father, ! 213: *probe; ! 214: register int rel; ! 215: ! 216: father = &dictionary; ! 217: while ( (probe = *father) != NULL) { ! 218: rel = strcmp(probe->word, str); ! 219: if (rel == 0) ! 220: return (probe); ! 221: father = (rel < 0 ? &probe->left : &probe->right); ! 222: } ! 223: probe = (dicent *)mpalc((sizeof *probe) + strlen(str) + 1); ! 224: probe->left = probe->right = NULL; ! 225: probe->globalt = probe->localt = UNDEFINED; ! 226: strcpy(probe->word, str); ! 227: *father = probe; ! 228: return (probe); ! 229: } ! 230: ! 231: /* ! 232: * Getword reads in a word (alphanumeric sequence) which starts ! 233: * with "ch". It returns a pointer to the string read in. ! 234: * Note that the pointer is to a static area and hence ! 235: * the result must be copyied if it is to be used after another ! 236: * call to getword. ! 237: */ ! 238: ! 239: char * ! 240: getword(ch) ! 241: register char ch; ! 242: { ! 243: register char *chp = &buff[0]; ! 244: ! 245: do { ! 246: if (chp < &buff[MAXWORD]) ! 247: *chp++ = ch; ! 248: ch = getc(infile); ! 249: } while (isascii(ch) && isalnum(ch)); ! 250: ungetc(ch, infile); ! 251: if (chp >= &buff[MAXWORD]) ! 252: lexerror("Identifier too long"); ! 253: *chp = '\0'; ! 254: return (buff); ! 255: } ! 256: ! 257: /* ! 258: * Shell reads in a line from the standard input and forks a shell ! 259: * to execute it. ! 260: */ ! 261: ! 262: shell() ! 263: { ! 264: register char *ptr; ! 265: register int ch; ! 266: ! 267: ptr = buff; ! 268: while ((ch = getc(infile)) != '\n' && ch != EOF) ! 269: if (ptr < &buff[MAXSTRING]) ! 270: *ptr++ = ch; ! 271: if (ptr >= &buff[MAXSTRING]) { ! 272: fprintf(stderr, "! line too long\n"); ! 273: return; ! 274: } ! 275: *ptr = '\0'; ! 276: fflush(infile); ! 277: if (system(buff) == NOSHELL) ! 278: fprintf(stderr, "bc: shell couldn't execute\n"); ! 279: printf("!\n"); ! 280: } ! 281:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.