Annotation of 42BSD/ucb/dbx/scanner.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) 1982 Regents of the University of California */
                      2: 
                      3: static char sccsid[] = "@(#)scanner.c 1.8 8/5/83";
                      4: 
                      5: /*
                      6:  * Debugger scanner.
                      7:  */
                      8: 
                      9: #include "defs.h"
                     10: #include "scanner.h"
                     11: #include "main.h"
                     12: #include "keywords.h"
                     13: #include "tree.h"
                     14: #include "symbols.h"
                     15: #include "names.h"
                     16: #include "y.tab.h"
                     17: 
                     18: #ifndef public
                     19: typedef int Token;
                     20: #endif
                     21: 
                     22: public String initfile = ".dbxinit";
                     23: 
                     24: typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass;
                     25: 
                     26: private Charclass class[256 + 1];
                     27: private Charclass *lexclass = class + 1;
                     28: 
                     29: #define isdigit(c) (lexclass[c] == NUM)
                     30: #define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM)
                     31: #define ishexdigit(c) ( \
                     32:     isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \
                     33: )
                     34: 
                     35: #define MAXLINESIZE 1024
                     36: 
                     37: private File in;
                     38: private Char linebuf[MAXLINESIZE];
                     39: private Char *curchar;
                     40: 
                     41: #define MAXINCLDEPTH 10
                     42: 
                     43: private struct {
                     44:     File savefile;
                     45:     Filename savefn;
                     46:     int savelineno;
                     47: } inclinfo[MAXINCLDEPTH];
                     48: 
                     49: private unsigned int curinclindex;
                     50: 
                     51: private Token getident();
                     52: private Token getnum();
                     53: private Token getstring();
                     54: private Boolean eofinput();
                     55: private Char charcon();
                     56: private Char charlookup();
                     57: 
                     58: private enterlexclass(class, s)
                     59: Charclass class;
                     60: String s;
                     61: {
                     62:     register char *p;
                     63: 
                     64:     for (p = s; *p != '\0'; p++) {
                     65:        lexclass[*p] = class;
                     66:     }
                     67: }
                     68: 
                     69: public scanner_init()
                     70: {
                     71:     register Integer i;
                     72: 
                     73:     for (i = 0; i < 257; i++) {
                     74:        class[i] = OTHER;
                     75:     }
                     76:     enterlexclass(WHITE, " \t");
                     77:     enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz");
                     78:     enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$");
                     79:     enterlexclass(NUM, "0123456789");
                     80:     in = stdin;
                     81:     errfilename = nil;
                     82:     errlineno = 0;
                     83:     curchar = linebuf;
                     84:     linebuf[0] = '\0';
                     85: }
                     86: 
                     87: /*
                     88:  * Read a single token.
                     89:  *
                     90:  * Input is line buffered.
                     91:  *
                     92:  * There are two "modes" of operation:  one as in a compiler,
                     93:  * and one for reading shell-like syntax.
                     94:  */
                     95: 
                     96: private Boolean shellmode;
                     97: 
                     98: public Token yylex()
                     99: {
                    100:     register int c;
                    101:     register char *p;
                    102:     register Token t;
                    103:     String line;
                    104: 
                    105:     p = curchar;
                    106:     if (*p == '\0') {
                    107:        do {
                    108:            if (isterm(in)) {
                    109:                printf("(%s) ", cmdname);
                    110:                fflush(stdout);
                    111:            }
                    112:            line = fgets(linebuf, MAXLINESIZE, in);
                    113:        } while (line == nil and not eofinput());
                    114:        if (line == nil) {
                    115:            c = EOF;
                    116:        } else {
                    117:            p = linebuf;
                    118:            while (lexclass[*p] == WHITE) {
                    119:                p++;
                    120:            }
                    121:            shellmode = false;
                    122:        }
                    123:     } else {
                    124:        while (lexclass[*p] == WHITE) {
                    125:            p++;
                    126:        }
                    127:     }
                    128:     curchar = p;
                    129:     c = *p;
                    130:     if (lexclass[c] == ALPHA) {
                    131:        t = getident();
                    132:     } else if (lexclass[c] == NUM) {
                    133:        if (shellmode) {
                    134:            t = getident();
                    135:        } else {
                    136:            t = getnum();
                    137:        }
                    138:     } else {
                    139:        ++curchar;
                    140:        switch (c) {
                    141:            case '\n':
                    142:                t = '\n';
                    143:                if (errlineno != 0) {
                    144:                    errlineno++;
                    145:                }
                    146:                break;
                    147: 
                    148:            case '"':
                    149:            case '\'':
                    150:                t = getstring();
                    151:                break;
                    152: 
                    153:            case '.':
                    154:                if (shellmode) {
                    155:                    --curchar;
                    156:                    t = getident();
                    157:                } else if (isdigit(*curchar)) {
                    158:                    --curchar;
                    159:                    t = getnum();
                    160:                } else {
                    161:                    t = '.';
                    162:                }
                    163:                break;
                    164: 
                    165:            case '<':
                    166:                if (not shellmode and *curchar == '<') {
                    167:                    ++curchar;
                    168:                    t = LFORMER;
                    169:                } else {
                    170:                    t = '<';
                    171:                }
                    172:                break;
                    173: 
                    174:            case '>':
                    175:                if (not shellmode and *curchar == '>') {
                    176:                    ++curchar;
                    177:                    t = RFORMER;
                    178:                } else {
                    179:                    t = '>';
                    180:                }
                    181:                break;
                    182: 
                    183:            case '#':
                    184:                if (*curchar == '^') {
                    185:                    ++curchar;
                    186:                    t = ABSTRACTION;
                    187:                } else {
                    188:                    t = '#';
                    189:                }
                    190:                break;
                    191: 
                    192:            case '-':
                    193:                if (shellmode) {
                    194:                    --curchar;
                    195:                    t = getident();
                    196:                } else if (*curchar == '>') {
                    197:                    ++curchar;
                    198:                    t = ARROW;
                    199:                } else {
                    200:                    t = '-';
                    201:                }
                    202:                break;
                    203: 
                    204:            case EOF:
                    205:                t = 0;
                    206:                break;
                    207: 
                    208:            default:
                    209:                if (shellmode and index("!&*()[]", c) == nil) {
                    210:                    --curchar;
                    211:                    t = getident();
                    212:                } else {
                    213:                    t = c;
                    214:                }
                    215:                break;
                    216:        }
                    217:     }
                    218: #   ifdef LEXDEBUG
                    219:        if (lexdebug) {
                    220:            fprintf(stderr, "yylex returns ");
                    221:            print_token(stderr, t);
                    222:            fprintf(stderr, "\n");
                    223:        }
                    224: #   endif
                    225:     return t;
                    226: }
                    227: 
                    228: /*
                    229:  * Parser error handling.
                    230:  */
                    231: 
                    232: public yyerror(s)
                    233: String s;
                    234: {
                    235:     register Char *p, *tokenbegin, *tokenend;
                    236:     register Integer len;
                    237: 
                    238:     if (streq(s, "syntax error")) {
                    239:        beginerrmsg();
                    240:        tokenend = curchar - 1;
                    241:        tokenbegin = tokenend;
                    242:        while (lexclass[*tokenbegin] != WHITE and tokenbegin > &linebuf[0]) {
                    243:            --tokenbegin;
                    244:        }
                    245:        len = tokenend - tokenbegin + 1;
                    246:        p = tokenbegin;
                    247:        if (p > &linebuf[0]) {
                    248:            while (lexclass[*p] == WHITE and p > &linebuf[0]) {
                    249:                --p;
                    250:            }
                    251:        }
                    252:        if (p == &linebuf[0]) {
                    253:            fprintf(stderr, "unrecognized command \"%.*s\"", len, tokenbegin);
                    254:        } else {
                    255:            fprintf(stderr, "syntax error");
                    256:            if (len != 0) {
                    257:                fprintf(stderr, " on \"%.*s\"", len, tokenbegin);
                    258:            }
                    259:        }
                    260:        enderrmsg();
                    261:     } else {
                    262:        error(s);
                    263:     }
                    264: }
                    265: 
                    266: /*
                    267:  * Eat the current line.
                    268:  */
                    269: 
                    270: public gobble()
                    271: {
                    272:     curchar = linebuf;
                    273:     linebuf[0] = '\0';
                    274: }
                    275: 
                    276: /*
                    277:  * Scan an identifier and check to see if it's a keyword.
                    278:  */
                    279: 
                    280: private Token getident()
                    281: {
                    282:     char buf[256];
                    283:     register Char *p, *q;
                    284:     register Token t;
                    285: 
                    286:     p = curchar;
                    287:     q = buf;
                    288:     if (shellmode) {
                    289:        do {
                    290:            *q++ = *p++;
                    291:        } while (index(" \t\n!&<>*[]()", *p) == nil);
                    292:     } else {
                    293:        do {
                    294:            *q++ = *p++;
                    295:        } while (isalnum(*p));
                    296:     }
                    297:     curchar = p;
                    298:     *q = '\0';
                    299:     yylval.y_name = identname(buf, false);
                    300:     if (not shellmode) {
                    301:        t = findkeyword(yylval.y_name);
                    302:        if (t == nil) {
                    303:            t = NAME;
                    304:        }
                    305:     } else {
                    306:        t = NAME;
                    307:     }
                    308:     return t;
                    309: }
                    310: 
                    311: /*
                    312:  * Scan a number.
                    313:  */
                    314: 
                    315: private Token getnum()
                    316: {
                    317:     char buf[256];
                    318:     register Char *p, *q;
                    319:     register Token t;
                    320:     Integer base;
                    321: 
                    322:     p = curchar;
                    323:     q = buf;
                    324:     if (*p == '0') {
                    325:        if (*(p+1) == 'x') {
                    326:            p += 2;
                    327:            base = 16;
                    328:        } else {
                    329:            base = 8;
                    330:        }
                    331:     } else {
                    332:        base = 10;
                    333:     }
                    334:     if (base == 16) {
                    335:        do {
                    336:            *q++ = *p++;
                    337:        } while (ishexdigit(*p));
                    338:     } else {
                    339:        do {
                    340:            *q++ = *p++;
                    341:        } while (isdigit(*p));
                    342:     }
                    343:     if (*p == '.') {
                    344:        do {
                    345:            *q++ = *p++;
                    346:        } while (isdigit(*p));
                    347:        if (*p == 'e' or *p == 'E') {
                    348:            p++;
                    349:            if (*p == '+' or *p == '-' or isdigit(*p)) {
                    350:                *q++ = 'e';
                    351:                do {
                    352:                    *q++ = *p++;
                    353:                } while (isdigit(*p));
                    354:            }
                    355:        }
                    356:        *q = '\0';
                    357:        yylval.y_real = atof(buf);
                    358:        t = REAL;
                    359:     } else {
                    360:        *q = '\0';
                    361:        switch (base) {
                    362:            case 10:
                    363:                yylval.y_int = atol(buf);
                    364:                break;
                    365: 
                    366:            case 8:
                    367:                yylval.y_int = octal(buf);
                    368:                break;
                    369: 
                    370:            case 16:
                    371:                yylval.y_int = hex(buf);
                    372:                break;
                    373: 
                    374:            default:
                    375:                badcaseval(base);
                    376:        }
                    377:        t = INT;
                    378:     }
                    379:     curchar = p;
                    380:     return t;
                    381: }
                    382: 
                    383: /*
                    384:  * Convert a string of octal digits to an integer.
                    385:  */
                    386: 
                    387: private int octal(s)
                    388: String s;
                    389: {
                    390:     register Char *p;
                    391:     register Integer n;
                    392: 
                    393:     n = 0;
                    394:     for (p = s; *p != '\0'; p++) {
                    395:        n = 8*n + (*p - '0');
                    396:     }
                    397:     return n;
                    398: }
                    399: 
                    400: /*
                    401:  * Convert a string of hexadecimal digits to an integer.
                    402:  */
                    403: 
                    404: private int hex(s)
                    405: String s;
                    406: {
                    407:     register Char *p;
                    408:     register Integer n;
                    409: 
                    410:     n = 0;
                    411:     for (p = s; *p != '\0'; p++) {
                    412:        n *= 16;
                    413:        if (*p >= 'a' and *p <= 'f') {
                    414:            n += (*p - 'a' + 10);
                    415:        } else if (*p >= 'A' and *p <= 'F') {
                    416:            n += (*p - 'A' + 10);
                    417:        } else {
                    418:            n += (*p - '0');
                    419:        }
                    420:     }
                    421:     return n;
                    422: }
                    423: 
                    424: /*
                    425:  * Scan a string.
                    426:  */
                    427: 
                    428: private Token getstring()
                    429: {
                    430:     char buf[256];
                    431:     register Char *p, *q;
                    432:     Boolean endofstring;
                    433: 
                    434:     p = curchar;
                    435:     q = buf;
                    436:     endofstring = false;
                    437:     while (not endofstring) {
                    438:        if (*p == '\n' or *p == '\0') {
                    439:            error("non-terminated string");
                    440:            endofstring = true;
                    441:        } else if (*p == '"' or *p == '\'') {
                    442:            if (*(p+1) != *p) {
                    443:                endofstring = true;
                    444:            } else {
                    445:                *q++ = *p;
                    446:            }
                    447:        } else {
                    448:            curchar = p;
                    449:            *q++ = charcon(p);
                    450:            p = curchar;
                    451:        }
                    452:        p++;
                    453:     }
                    454:     curchar = p;
                    455:     *q = '\0';
                    456:     yylval.y_string = strdup(buf);
                    457:     return STRING;
                    458: }
                    459: 
                    460: /*
                    461:  * Process a character constant.
                    462:  * Watch out for backslashes.
                    463:  */
                    464: 
                    465: private Char charcon(p)
                    466: char *p;
                    467: {
                    468:     char c, buf[10], *q;
                    469: 
                    470:     if (*p == '\\') {
                    471:        ++p;
                    472:        if (*p != '\\') {
                    473:            q = buf;
                    474:            do {
                    475:                *q++ = *p++;
                    476:            } while (*p != '\\' and *p != '\'' and *p != '\n' and *p != '\0');
                    477:            *q = '\0';
                    478:            if (isdigit(buf[0])) {
                    479:                c = (Char) octal(buf);
                    480:            } else {
                    481:                c = charlookup(buf);
                    482:            }
                    483:            curchar = p - 1;
                    484:        } else {
                    485:            c = '\\';
                    486:        }
                    487:     } else {
                    488:        c = *p;
                    489:     }
                    490:     return c;
                    491: }
                    492: 
                    493: /*
                    494:  * Do a lookup for a ASCII character name.
                    495:  */
                    496: 
                    497: private String ascii[] = {
                    498:     "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
                    499:     "BS",  "HT",  "NL",  "VT",  "NP",  "CR",  "SO",  "SI",
                    500:     "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
                    501:     "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US",
                    502:     "SP", nil
                    503: };
                    504: 
                    505: private char charlookup(s)
                    506: String s;
                    507: {
                    508:     register int i;
                    509: 
                    510:     for (i = 0; ascii[i] != NULL; i++) {
                    511:        if (streq(s, ascii[i])) {
                    512:            return i;
                    513:        }
                    514:     }
                    515:     if (streq(s, "DEL")) {
                    516:        return 0177;
                    517:     }
                    518:     error("unknown ascii name \"%s\"", s);
                    519:     return '?';
                    520: }
                    521: 
                    522: /*
                    523:  * Input file management routines.
                    524:  */
                    525: 
                    526: public setinput(filename)
                    527: Filename filename;
                    528: {
                    529:     File f;
                    530: 
                    531:     f = fopen(filename, "r");
                    532:     if (f == nil) {
                    533:        error("can't open %s", filename);
                    534:     } else {
                    535:        if (curinclindex >= MAXINCLDEPTH) {
                    536:            error("unreasonable input nesting on \"%s\"", filename);
                    537:        }
                    538:        inclinfo[curinclindex].savefile = in;
                    539:        inclinfo[curinclindex].savefn = errfilename;
                    540:        inclinfo[curinclindex].savelineno = errlineno;
                    541:        curinclindex++;
                    542:        in = f;
                    543:        errfilename = filename;
                    544:        errlineno = 1;
                    545:     }
                    546: }
                    547: 
                    548: private Boolean eofinput()
                    549: {
                    550:     register Boolean b;
                    551: 
                    552:     if (curinclindex == 0) {
                    553:        if (isterm(in)) {
                    554:            putchar('\n');
                    555:            clearerr(in);
                    556:            b = false;
                    557:        } else {
                    558:            b = true;
                    559:        }
                    560:     } else {
                    561:        fclose(in);
                    562:        --curinclindex;
                    563:        in = inclinfo[curinclindex].savefile;
                    564:        errfilename = inclinfo[curinclindex].savefn;
                    565:        errlineno = inclinfo[curinclindex].savelineno;
                    566:        b = false;
                    567:     }
                    568:     return b;
                    569: }
                    570: 
                    571: /*
                    572:  * Pop the current input.  Return whether successful.
                    573:  */
                    574: 
                    575: public Boolean popinput()
                    576: {
                    577:     Boolean b;
                    578: 
                    579:     if (curinclindex == 0) {
                    580:        b = false;
                    581:     } else {
                    582:        b = (Boolean) (not eofinput());
                    583:     }
                    584:     return b;
                    585: }
                    586: 
                    587: /*
                    588:  * Return whether we are currently reading from standard input.
                    589:  */
                    590: 
                    591: public Boolean isstdin()
                    592: {
                    593:     return (Boolean) (in == stdin);
                    594: }
                    595: 
                    596: /*
                    597:  * Send the current line to the shell.
                    598:  */
                    599: 
                    600: public shellline()
                    601: {
                    602:     register char *p;
                    603: 
                    604:     p = curchar;
                    605:     while (*p != '\0' and (*p == '\n' or lexclass[*p] == WHITE)) {
                    606:        ++p;
                    607:     }
                    608:     shell(p);
                    609:     if (*p == '\0' and isterm(in)) {
                    610:        putchar('\n');
                    611:     }
                    612:     erecover();
                    613: }
                    614: 
                    615: /*
                    616:  * Read the rest of the current line in "shell mode".
                    617:  */
                    618: 
                    619: public beginshellmode()
                    620: {
                    621:     shellmode = true;
                    622: }
                    623: 
                    624: /*
                    625:  * Print out a token for debugging.
                    626:  */
                    627: 
                    628: public print_token(f, t)
                    629: File f;
                    630: Token t;
                    631: {
                    632:     if (t == '\n') {
                    633:        fprintf(f, "char '\\n'");
                    634:     } else if (t == EOF) {
                    635:        fprintf(f, "EOF");
                    636:     } else if (t < 256) {
                    637:        fprintf(f, "char '%c'", t);
                    638:     } else {
                    639:        fprintf(f, "\"%s\"", keywdstring(t));
                    640:     }
                    641: }

unix.superglobalmegacorp.com

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