Annotation of coherent/d/bin/bc/lex.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.