121622Sdist /*
238105Sbostic * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic * All rights reserved.
438105Sbostic *
5*42685Sbostic * %sccs.include.redist.c%
621622Sdist */
79679Slinton
821622Sdist #ifndef lint
9*42685Sbostic static char sccsid[] = "@(#)scanner.c 5.3 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
119679Slinton
129679Slinton /*
139679Slinton * Debugger scanner.
149679Slinton */
159679Slinton
169679Slinton #include "defs.h"
179679Slinton #include "scanner.h"
189679Slinton #include "main.h"
199679Slinton #include "keywords.h"
209679Slinton #include "tree.h"
219679Slinton #include "symbols.h"
229679Slinton #include "names.h"
239679Slinton #include "y.tab.h"
249679Slinton
259679Slinton #ifndef public
269679Slinton typedef int Token;
279679Slinton
2818232Slinton #define MAXLINESIZE 10240
299679Slinton
3018232Slinton #endif
319679Slinton
3216928Ssam public String initfile = ".dbxinit";
339679Slinton
3418232Slinton typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass;
3518232Slinton
3618232Slinton private Charclass class[256 + 1];
3718232Slinton private Charclass *lexclass = class + 1;
3818232Slinton
3918232Slinton #define isdigit(c) (lexclass[c] == NUM)
4018232Slinton #define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM)
4118232Slinton #define ishexdigit(c) ( \
4218232Slinton isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \
4318232Slinton )
4418232Slinton
4518232Slinton public boolean chkalias;
4618232Slinton public char scanner_linebuf[MAXLINESIZE];
4718232Slinton
4818232Slinton private File in;
4918232Slinton private char *curchar, *prevchar;
5018232Slinton
5118232Slinton #define MAXINCLDEPTH 10
5218232Slinton
5318232Slinton private struct {
5418232Slinton File savefile;
5518232Slinton Filename savefn;
5618232Slinton int savelineno;
5718232Slinton } inclinfo[MAXINCLDEPTH];
5818232Slinton
5918232Slinton private unsigned int curinclindex;
6018232Slinton
619679Slinton private Token getident();
629679Slinton private Token getnum();
639679Slinton private Token getstring();
6418232Slinton private Boolean eofinput();
6518232Slinton private char charcon();
669679Slinton
enterlexclass(class,s)6718232Slinton private enterlexclass(class, s)
6818232Slinton Charclass class;
6918232Slinton String s;
7018232Slinton {
7118232Slinton register char *p;
729679Slinton
7318232Slinton for (p = s; *p != '\0'; p++) {
7418232Slinton lexclass[*p] = class;
7518232Slinton }
7618232Slinton }
7718232Slinton
scanner_init()789679Slinton public scanner_init()
799679Slinton {
8018232Slinton register Integer i;
819679Slinton
8218232Slinton for (i = 0; i < 257; i++) {
8318232Slinton class[i] = OTHER;
8418232Slinton }
8518232Slinton enterlexclass(WHITE, " \t");
8618232Slinton enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz");
8718232Slinton enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$");
8818232Slinton enterlexclass(NUM, "0123456789");
8918232Slinton in = stdin;
9018232Slinton errfilename = nil;
9118232Slinton errlineno = 0;
9218232Slinton curchar = scanner_linebuf;
9318232Slinton scanner_linebuf[0] = '\0';
9418232Slinton chkalias = true;
959679Slinton }
969679Slinton
979679Slinton /*
989679Slinton * Read a single token.
9918232Slinton *
10018232Slinton * The input is line buffered. Tokens cannot cross line boundaries.
10118232Slinton *
1029679Slinton * There are two "modes" of operation: one as in a compiler,
10318232Slinton * and one for reading shell-like syntax. In the first mode
10418232Slinton * there is the additional choice of doing alias processing.
1059679Slinton */
10618232Slinton
10718232Slinton private Boolean shellmode;
10818232Slinton
yylex()1099679Slinton public Token yylex()
1109679Slinton {
11118232Slinton register int c;
11218232Slinton register char *p;
11318232Slinton register Token t;
11418232Slinton String line;
11518232Slinton integer n;
1169679Slinton
11718232Slinton p = curchar;
11818232Slinton if (*p == '\0') {
11918232Slinton do {
12018232Slinton if (isterm(in)) {
12118232Slinton printf("(%s) ", cmdname);
12218232Slinton }
12318232Slinton fflush(stdout);
12418232Slinton line = fgets(scanner_linebuf, MAXLINESIZE, in);
12518232Slinton } while (line == nil and not eofinput());
12618232Slinton if (line == nil) {
12718232Slinton c = EOF;
12818232Slinton } else {
12918232Slinton p = scanner_linebuf;
13018232Slinton while (lexclass[*p] == WHITE) {
13118232Slinton p++;
13218232Slinton }
13318232Slinton shellmode = false;
1349679Slinton }
13518232Slinton chkalias = true;
13618232Slinton } else {
13718232Slinton while (lexclass[*p] == WHITE) {
13818232Slinton p++;
1399679Slinton }
14018232Slinton }
14118232Slinton curchar = p;
14218232Slinton prevchar = curchar;
14318232Slinton c = *p;
14418232Slinton if (lexclass[c] == ALPHA) {
14518232Slinton t = getident(chkalias);
14618232Slinton } else if (lexclass[c] == NUM) {
14718232Slinton if (shellmode) {
14818232Slinton t = getident(chkalias);
14918232Slinton } else {
15018232Slinton t = getnum();
15112120Slinton }
15218232Slinton } else {
15318232Slinton ++curchar;
1549679Slinton switch (c) {
15518232Slinton case '\n':
1569679Slinton t = '\n';
15718232Slinton if (errlineno != 0) {
15818232Slinton errlineno++;
1599679Slinton }
1609679Slinton break;
1619679Slinton
16218232Slinton case '"':
16318232Slinton case '\'':
16416928Ssam t = getstring(c);
1659679Slinton break;
1669679Slinton
16718232Slinton case '.':
1689679Slinton if (shellmode) {
16918232Slinton --curchar;
17018232Slinton t = getident(chkalias);
17118232Slinton } else if (isdigit(*curchar)) {
17218232Slinton --curchar;
17318232Slinton t = getnum();
17418232Slinton } else {
17518232Slinton t = '.';
1769679Slinton }
1779679Slinton break;
1789679Slinton
17918232Slinton case '-':
18018232Slinton if (shellmode) {
18118232Slinton --curchar;
18218232Slinton t = getident(chkalias);
18318232Slinton } else if (*curchar == '>') {
18418232Slinton ++curchar;
18518232Slinton t = ARROW;
18618232Slinton } else {
18718232Slinton t = '-';
18818232Slinton }
1899679Slinton break;
1909679Slinton
19118232Slinton case '#':
19218232Slinton if (not isterm(in)) {
19318232Slinton *p = '\0';
19418232Slinton curchar = p;
19518232Slinton t = '\n';
19618232Slinton ++errlineno;
19718232Slinton } else {
19818232Slinton t = '#';
19918232Slinton }
2009679Slinton break;
2019679Slinton
20218232Slinton case '\\':
20318232Slinton if (*(p+1) == '\n') {
20418232Slinton n = MAXLINESIZE - (p - &scanner_linebuf[0]);
20518232Slinton if (n > 1) {
20618232Slinton if (fgets(p, n, in) == nil) {
20718232Slinton t = 0;
20818232Slinton } else {
20918232Slinton curchar = p;
21018232Slinton t = yylex();
21118232Slinton }
21218232Slinton } else {
21318232Slinton t = '\\';
21418232Slinton }
21518232Slinton } else {
21618232Slinton t = '\\';
2179679Slinton }
2189679Slinton break;
2199679Slinton
22018232Slinton case EOF:
2219679Slinton t = 0;
2229679Slinton break;
2239679Slinton
22418232Slinton default:
22518232Slinton if (shellmode and index("!&*<>()[]", c) == nil) {
22618232Slinton --curchar;
22718232Slinton t = getident(chkalias);
22818232Slinton } else {
22918232Slinton t = c;
23018232Slinton }
2319679Slinton break;
2329679Slinton }
23318232Slinton }
23418232Slinton chkalias = false;
23518232Slinton # ifdef LEXDEBUG
2369679Slinton if (lexdebug) {
23718232Slinton fprintf(stderr, "yylex returns ");
23818232Slinton print_token(stderr, t);
23918232Slinton fprintf(stderr, "\n");
2409679Slinton }
24118232Slinton # endif
24218232Slinton return t;
2439679Slinton }
2449679Slinton
2459679Slinton /*
24618232Slinton * Put the given string before the current character
24718232Slinton * in the current line, thus inserting it into the input stream.
2489679Slinton */
2499679Slinton
insertinput(s)25018232Slinton public insertinput (s)
25118232Slinton String s;
2529679Slinton {
25318232Slinton register char *p, *q;
25418232Slinton int need, avail, shift;
2559679Slinton
25618232Slinton q = s;
25718232Slinton need = strlen(q);
25818232Slinton avail = curchar - &scanner_linebuf[0];
25918232Slinton if (need <= avail) {
26018232Slinton curchar = &scanner_linebuf[avail - need];
26118232Slinton p = curchar;
26218232Slinton while (*q != '\0') {
26318232Slinton *p++ = *q++;
26416928Ssam }
26518232Slinton } else {
26618232Slinton p = curchar;
26718232Slinton while (*p != '\0') {
26818232Slinton ++p;
2699679Slinton }
27018232Slinton shift = need - avail;
27118232Slinton if (p + shift >= &scanner_linebuf[MAXLINESIZE]) {
27218232Slinton error("alias expansion too large");
2739679Slinton }
27418232Slinton for (;;) {
27518232Slinton *(p + shift) = *p;
27618232Slinton if (p == curchar) {
2779679Slinton break;
27818232Slinton }
27918232Slinton --p;
2809679Slinton }
28118232Slinton p = &scanner_linebuf[0];
28218232Slinton while (*q != '\0') {
28318232Slinton *p++ = *q++;
28418232Slinton }
28518232Slinton curchar = &scanner_linebuf[0];
28618232Slinton }
2879679Slinton }
2889679Slinton
2899679Slinton /*
29018232Slinton * Get the actuals for a macro call.
2919679Slinton */
2929679Slinton
movetochar(str,c)29318232Slinton private String movetochar (str, c)
29418232Slinton String str;
29518232Slinton char c;
2969679Slinton {
29718232Slinton register char *p;
2989679Slinton
29918232Slinton while (*p != c) {
30018232Slinton if (*p == '\0') {
30118232Slinton error("missing ')' in macro call");
30218232Slinton } else if (*p == ')') {
30318232Slinton error("not enough parameters in macro call");
30418232Slinton } else if (*p == ',') {
30518232Slinton error("too many parameters in macro call");
3069679Slinton }
30718232Slinton ++p;
30818232Slinton }
30918232Slinton return p;
3109679Slinton }
3119679Slinton
getactuals(n)31218232Slinton private String *getactuals (n)
31318232Slinton integer n;
3149679Slinton {
31518232Slinton String *a;
31618232Slinton register char *p;
31718232Slinton int i;
3189679Slinton
31918232Slinton a = newarr(String, n);
32018232Slinton p = curchar;
32118232Slinton while (*p != '(') {
32218232Slinton if (lexclass[*p] != WHITE) {
32318232Slinton error("missing actuals for macro");
3249679Slinton }
32518232Slinton ++p;
32618232Slinton }
32718232Slinton ++p;
32818232Slinton for (i = 0; i < n - 1; i++) {
32918232Slinton a[i] = p;
33018232Slinton p = movetochar(p, ',');
33118232Slinton *p = '\0';
33218232Slinton ++p;
33318232Slinton }
33418232Slinton a[n-1] = p;
33518232Slinton p = movetochar(p, ')');
33618232Slinton *p = '\0';
33718232Slinton curchar = p + 1;
33818232Slinton return a;
3399679Slinton }
3409679Slinton
3419679Slinton /*
34218232Slinton * Do command macro expansion, assuming curchar points to the beginning
34318232Slinton * of the actuals, and we are not in shell mode.
3449679Slinton */
34518232Slinton
expand(pl,str)34618232Slinton private expand (pl, str)
34718232Slinton List pl;
34818232Slinton String str;
3499679Slinton {
35018232Slinton char buf[4096], namebuf[100];
35118232Slinton register char *p, *q, *r;
35218232Slinton String *actual;
35318232Slinton Name n;
35418232Slinton integer i;
35518232Slinton boolean match;
3569679Slinton
35718232Slinton if (pl == nil) {
35818232Slinton insertinput(str);
35918232Slinton } else {
36018232Slinton actual = getactuals(list_size(pl));
36118232Slinton p = buf;
36218232Slinton q = str;
36318232Slinton while (*q != '\0') {
36418232Slinton if (p >= &buf[4096]) {
36518232Slinton error("alias expansion too large");
36618232Slinton }
36718232Slinton if (lexclass[*q] == ALPHA) {
36818232Slinton r = namebuf;
36918232Slinton do {
37018232Slinton *r++ = *q++;
37118232Slinton } while (isalnum(*q));
37218232Slinton *r = '\0';
37318232Slinton i = 0;
37418232Slinton match = false;
37518232Slinton foreach(Name, n, pl)
37618232Slinton if (streq(ident(n), namebuf)) {
37718232Slinton match = true;
37818232Slinton break;
37918232Slinton }
38018232Slinton ++i;
38118232Slinton endfor
38218232Slinton if (match) {
38318232Slinton r = actual[i];
38418232Slinton } else {
38518232Slinton r = namebuf;
38616928Ssam }
38718232Slinton while (*r != '\0') {
38818232Slinton *p++ = *r++;
38918232Slinton }
39018232Slinton } else {
39118232Slinton *p++ = *q++;
39218232Slinton }
3939679Slinton }
39418232Slinton *p = '\0';
39518232Slinton insertinput(buf);
39618232Slinton }
3979679Slinton }
3989679Slinton
3999679Slinton /*
40016928Ssam * Parser error handling.
4019679Slinton */
40218232Slinton
yyerror(s)40316928Ssam public yyerror(s)
4049679Slinton String s;
4059679Slinton {
40618232Slinton register char *p;
40718232Slinton register integer start;
4089679Slinton
40918232Slinton if (streq(s, "syntax error")) {
41018232Slinton beginerrmsg();
41118232Slinton p = prevchar;
41218232Slinton start = p - &scanner_linebuf[0];
41318232Slinton if (p > &scanner_linebuf[0]) {
41418232Slinton while (lexclass[*p] == WHITE and p > &scanner_linebuf[0]) {
41518232Slinton --p;
41618232Slinton }
4179679Slinton }
41818232Slinton fprintf(stderr, "%s", scanner_linebuf);
41918232Slinton if (start != 0) {
42018232Slinton fprintf(stderr, "%*c", start, ' ');
42118232Slinton }
42218232Slinton if (p == &scanner_linebuf[0]) {
42318232Slinton fprintf(stderr, "^ unrecognized command");
42418232Slinton } else {
42518232Slinton fprintf(stderr, "^ syntax error");
42618232Slinton }
42718232Slinton enderrmsg();
42818232Slinton } else {
42916928Ssam error(s);
43018232Slinton }
4319679Slinton }
4329679Slinton
4339679Slinton /*
43416928Ssam * Eat the current line.
43516928Ssam */
43616928Ssam
gobble()43718232Slinton public gobble ()
43816928Ssam {
43918232Slinton curchar = scanner_linebuf;
44018232Slinton scanner_linebuf[0] = '\0';
44116928Ssam }
44216928Ssam
44316928Ssam /*
44418232Slinton * Scan an identifier.
44518232Slinton *
44618232Slinton * If chkalias is true, check first to see if it's an alias.
44718232Slinton * Otherwise, check to see if it's a keyword.
4489679Slinton */
44918232Slinton
getident(chkalias)45018232Slinton private Token getident (chkalias)
45118232Slinton boolean chkalias;
4529679Slinton {
45318232Slinton char buf[1024];
45418232Slinton register char *p, *q;
45518232Slinton register Token t;
45618232Slinton List pl;
45718232Slinton String str;
4589679Slinton
45918232Slinton p = curchar;
46018232Slinton q = buf;
46118232Slinton if (shellmode) {
46218232Slinton do {
46318232Slinton *q++ = *p++;
46418232Slinton } while (index(" \t\n!&<>*[]()'\"", *p) == nil);
46518232Slinton } else {
46618232Slinton do {
46718232Slinton *q++ = *p++;
46818232Slinton } while (isalnum(*p));
46918232Slinton }
47018232Slinton curchar = p;
47118232Slinton *q = '\0';
47218232Slinton yylval.y_name = identname(buf, false);
47318232Slinton if (chkalias) {
47418232Slinton if (findalias(yylval.y_name, &pl, &str)) {
47518232Slinton expand(pl, str);
47618232Slinton while (lexclass[*curchar] == WHITE) {
47718232Slinton ++curchar;
47818232Slinton }
47918232Slinton if (pl == nil) {
48018232Slinton t = getident(false);
48118232Slinton } else {
48218232Slinton t = getident(true);
48318232Slinton }
48418232Slinton } else if (shellmode) {
48518232Slinton t = NAME;
48618232Slinton } else {
48718232Slinton t = findkeyword(yylval.y_name, NAME);
4889679Slinton }
48918232Slinton } else if (shellmode) {
49018232Slinton t = NAME;
49118232Slinton } else {
49218232Slinton t = findkeyword(yylval.y_name, NAME);
49318232Slinton }
49418232Slinton return t;
4959679Slinton }
4969679Slinton
49716928Ssam /*
49818232Slinton * Scan a number.
49916928Ssam */
50018232Slinton
getnum()50118232Slinton private Token getnum()
5029679Slinton {
50318232Slinton char buf[1024];
50418232Slinton register Char *p, *q;
50518232Slinton register Token t;
50618232Slinton Integer base;
5079679Slinton
50818232Slinton p = curchar;
50918232Slinton q = buf;
51018232Slinton if (*p == '0') {
51118232Slinton if (*(p+1) == 'x') {
51218232Slinton p += 2;
51318232Slinton base = 16;
51418232Slinton } else if (*(p+1) == 't') {
51518232Slinton base = 10;
51618232Slinton } else if (varIsSet("$hexin")) {
51718232Slinton base = 16;
51818232Slinton } else {
51918232Slinton base = 8;
52018232Slinton }
52118232Slinton } else if (varIsSet("$hexin")) {
52218232Slinton base = 16;
52318232Slinton } else if (varIsSet("$octin")) {
52418232Slinton base = 8;
52518232Slinton } else {
52618232Slinton base = 10;
52718232Slinton }
52818232Slinton if (base == 16) {
52918232Slinton do {
53018232Slinton *q++ = *p++;
53118232Slinton } while (ishexdigit(*p));
53218232Slinton } else {
53318232Slinton do {
53418232Slinton *q++ = *p++;
53518232Slinton } while (isdigit(*p));
53618232Slinton }
53718232Slinton if (*p == '.') {
53818232Slinton do {
53918232Slinton *q++ = *p++;
54018232Slinton } while (isdigit(*p));
54118232Slinton if (*p == 'e' or *p == 'E') {
54218232Slinton p++;
54318232Slinton if (*p == '+' or *p == '-' or isdigit(*p)) {
54418232Slinton *q++ = 'e';
54518232Slinton do {
54618232Slinton *q++ = *p++;
54718232Slinton } while (isdigit(*p));
54818232Slinton }
54918232Slinton }
55018232Slinton *q = '\0';
55118232Slinton yylval.y_real = atof(buf);
55218232Slinton t = REAL;
55318232Slinton } else {
55418232Slinton *q = '\0';
55518232Slinton switch (base) {
55618232Slinton case 10:
55718232Slinton yylval.y_int = atol(buf);
55818232Slinton break;
55918232Slinton
56018232Slinton case 8:
56118232Slinton yylval.y_int = octal(buf);
56218232Slinton break;
56318232Slinton
56418232Slinton case 16:
56518232Slinton yylval.y_int = hex(buf);
56618232Slinton break;
56718232Slinton
56818232Slinton default:
56918232Slinton badcaseval(base);
57018232Slinton }
57118232Slinton t = INT;
57218232Slinton }
57318232Slinton curchar = p;
57418232Slinton return t;
5759679Slinton }
5769679Slinton
5779679Slinton /*
57818232Slinton * Convert a string of octal digits to an integer.
5799679Slinton */
5809679Slinton
octal(s)58118232Slinton private int octal(s)
58218232Slinton String s;
5839679Slinton {
58418232Slinton register Char *p;
58518232Slinton register Integer n;
5869679Slinton
58718232Slinton n = 0;
58818232Slinton for (p = s; *p != '\0'; p++) {
58918232Slinton n = 8*n + (*p - '0');
59018232Slinton }
59118232Slinton return n;
5929679Slinton }
5939679Slinton
59418232Slinton /*
59518232Slinton * Convert a string of hexadecimal digits to an integer.
59618232Slinton */
59716928Ssam
hex(s)59818232Slinton private int hex(s)
59918232Slinton String s;
60016928Ssam {
60118232Slinton register Char *p;
60218232Slinton register Integer n;
60316928Ssam
60418232Slinton n = 0;
60518232Slinton for (p = s; *p != '\0'; p++) {
60618232Slinton n *= 16;
60718232Slinton if (*p >= 'a' and *p <= 'f') {
60818232Slinton n += (*p - 'a' + 10);
60918232Slinton } else if (*p >= 'A' and *p <= 'F') {
61018232Slinton n += (*p - 'A' + 10);
61118232Slinton } else {
61218232Slinton n += (*p - '0');
61318232Slinton }
61418232Slinton }
61518232Slinton return n;
61616928Ssam }
61716928Ssam
6189679Slinton /*
61918232Slinton * Scan a string.
6209679Slinton */
62118232Slinton
getstring(quote)62218232Slinton private Token getstring (quote)
62318232Slinton char quote;
62416928Ssam {
62518232Slinton register char *p, *q;
62618232Slinton char buf[MAXLINESIZE];
62718232Slinton boolean endofstring;
62818232Slinton Token t;
6299679Slinton
63018232Slinton p = curchar;
63118232Slinton q = buf;
63218232Slinton endofstring = false;
63318232Slinton while (not endofstring) {
63418232Slinton if (*p == '\\' and *(p+1) == '\n') {
63518232Slinton if (fgets(scanner_linebuf, MAXLINESIZE, in) == nil) {
63618232Slinton error("non-terminated string");
63718232Slinton }
63818232Slinton p = &scanner_linebuf[0] - 1;
63918232Slinton } else if (*p == '\n' or *p == '\0') {
64018232Slinton error("non-terminated string");
64118232Slinton endofstring = true;
64218232Slinton } else if (*p == quote) {
64318232Slinton endofstring = true;
64418232Slinton } else {
64518232Slinton curchar = p;
64618232Slinton *q++ = charcon(p);
64718232Slinton p = curchar;
64816928Ssam }
64918232Slinton p++;
65018232Slinton }
65118232Slinton curchar = p;
65218232Slinton *q = '\0';
65318232Slinton if (quote == '\'' and buf[1] == '\0') {
65418232Slinton yylval.y_char = buf[0];
65518232Slinton t = CHAR;
65618232Slinton } else {
65718232Slinton yylval.y_string = strdup(buf);
65818232Slinton t = STRING;
65918232Slinton }
66018232Slinton return t;
66116928Ssam }
66216928Ssam
66318232Slinton /*
66418232Slinton * Process a character constant.
66518232Slinton * Watch out for backslashes.
66618232Slinton */
66718232Slinton
charcon(s)66818232Slinton private char charcon (s)
66918232Slinton String s;
6709679Slinton {
67118232Slinton register char *p, *q;
67218232Slinton char c, buf[10];
67316928Ssam
67418232Slinton p = s;
67518232Slinton if (*p == '\\') {
67618232Slinton ++p;
67718232Slinton switch (*p) {
67818232Slinton case '\\':
67918232Slinton c = '\\';
68018232Slinton break;
68116928Ssam
68218232Slinton case 'n':
68318232Slinton c = '\n';
68416928Ssam break;
68516928Ssam
68618232Slinton case 'r':
68718232Slinton c = '\r';
68816928Ssam break;
68916928Ssam
69018232Slinton case 't':
69118232Slinton c = '\t';
69218232Slinton break;
6939679Slinton
69418232Slinton case '\'':
69518232Slinton case '"':
69618232Slinton c = *p;
69716928Ssam break;
69816928Ssam
69918232Slinton default:
70018232Slinton if (isdigit(*p)) {
70118232Slinton q = buf;
70218232Slinton do {
70318232Slinton *q++ = *p++;
70418232Slinton } while (isdigit(*p));
70518232Slinton *q = '\0';
70618232Slinton c = (char) octal(buf);
70718232Slinton }
70818232Slinton --p;
70916928Ssam break;
71016928Ssam }
71118232Slinton curchar = p;
71218232Slinton } else {
71318232Slinton c = *p;
71418232Slinton }
71518232Slinton return c;
71616928Ssam }
71716928Ssam
7189679Slinton /*
71918232Slinton * Input file management routines.
7209679Slinton */
72118232Slinton
setinput(filename)72218232Slinton public setinput(filename)
72318232Slinton Filename filename;
72416928Ssam {
72518232Slinton File f;
7269679Slinton
72718232Slinton f = fopen(filename, "r");
72818232Slinton if (f == nil) {
72918232Slinton error("can't open %s", filename);
73018232Slinton } else {
73118232Slinton if (curinclindex >= MAXINCLDEPTH) {
73218232Slinton error("unreasonable input nesting on \"%s\"", filename);
73316928Ssam }
73418232Slinton inclinfo[curinclindex].savefile = in;
73518232Slinton inclinfo[curinclindex].savefn = errfilename;
73618232Slinton inclinfo[curinclindex].savelineno = errlineno;
73718232Slinton curinclindex++;
73818232Slinton in = f;
73918232Slinton errfilename = filename;
74018232Slinton errlineno = 1;
74118232Slinton }
74216928Ssam }
74316928Ssam
eofinput()74418232Slinton private Boolean eofinput()
7459679Slinton {
74618232Slinton register Boolean b;
7479679Slinton
74818232Slinton if (curinclindex == 0) {
74918232Slinton if (isterm(in)) {
75018232Slinton putchar('\n');
75118232Slinton clearerr(in);
75218232Slinton b = false;
75318232Slinton } else {
75418232Slinton b = true;
75518232Slinton }
75618232Slinton } else {
75718232Slinton fclose(in);
75818232Slinton --curinclindex;
75918232Slinton in = inclinfo[curinclindex].savefile;
76018232Slinton errfilename = inclinfo[curinclindex].savefn;
76118232Slinton errlineno = inclinfo[curinclindex].savelineno;
76218232Slinton b = false;
76318232Slinton }
76418232Slinton return b;
7659679Slinton }
7669679Slinton
7679679Slinton /*
76818232Slinton * Pop the current input. Return whether successful.
7699679Slinton */
77018232Slinton
popinput()77118232Slinton public Boolean popinput()
77216928Ssam {
77318232Slinton Boolean b;
7749679Slinton
77518232Slinton if (curinclindex == 0) {
77618232Slinton b = false;
77718232Slinton } else {
77818232Slinton b = (Boolean) (not eofinput());
77918232Slinton }
78018232Slinton return b;
7819679Slinton }
7829679Slinton
7839679Slinton /*
78416928Ssam * Return whether we are currently reading from standard input.
7859679Slinton */
78618232Slinton
isstdin()78716928Ssam public Boolean isstdin()
78816928Ssam {
78918232Slinton return (Boolean) (in == stdin);
79018232Slinton }
7919679Slinton
79218232Slinton /*
79318232Slinton * Send the current line to the shell.
79418232Slinton */
79518232Slinton
shellline()79618232Slinton public shellline()
79718232Slinton {
79818232Slinton register char *p;
79918232Slinton
80018232Slinton p = curchar;
80118232Slinton while (*p != '\0' and (*p == '\n' or lexclass[*p] == WHITE)) {
80218232Slinton ++p;
80318232Slinton }
80418232Slinton shell(p);
80518232Slinton if (*p == '\0' and isterm(in)) {
80618232Slinton putchar('\n');
80718232Slinton }
80818232Slinton erecover();
80916928Ssam }
81016928Ssam
81118232Slinton /*
81218232Slinton * Read the rest of the current line in "shell mode".
81318232Slinton */
81418232Slinton
beginshellmode()81518232Slinton public beginshellmode()
8169679Slinton {
81718232Slinton shellmode = true;
81818232Slinton }
81916928Ssam
82018232Slinton /*
82118232Slinton * Print out a token for debugging.
82218232Slinton */
82318232Slinton
print_token(f,t)82418232Slinton public print_token(f, t)
82518232Slinton File f;
82618232Slinton Token t;
82718232Slinton {
82818232Slinton if (t == '\n') {
82918232Slinton fprintf(f, "char '\\n'");
83018232Slinton } else if (t == EOF) {
83118232Slinton fprintf(f, "EOF");
83218232Slinton } else if (t < 256) {
83318232Slinton fprintf(f, "char '%c'", t);
83418232Slinton } else {
83518232Slinton fprintf(f, "\"%s\"", keywdstring(t));
83618232Slinton }
8379679Slinton }
838