BSD 4_3 release
[unix-history] / usr / src / ucb / dbx / scanner.c
index 30dc17f..0858e94 100644 (file)
@@ -1,6 +1,14 @@
-/* Copyright (c) 1982 Regents of the University of California */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)scanner.c  5.1 (Berkeley) 5/31/85";
+#endif not lint
 
 
-static char sccsid[] = "@(#)scanner.c 1.8 8/5/83";
+static char rcsid[] = "$Header: scanner.c,v 1.5 84/12/26 10:42:05 linton Exp $";
 
 /*
  * Debugger scanner.
 
 /*
  * Debugger scanner.
@@ -17,6 +25,9 @@ static char sccsid[] = "@(#)scanner.c 1.8 8/5/83";
 
 #ifndef public
 typedef int Token;
 
 #ifndef public
 typedef int Token;
+
+#define MAXLINESIZE 10240
+
 #endif
 
 public String initfile = ".dbxinit";
 #endif
 
 public String initfile = ".dbxinit";
@@ -32,11 +43,11 @@ private Charclass *lexclass = class + 1;
     isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \
 )
 
     isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \
 )
 
-#define MAXLINESIZE 1024
+public boolean chkalias;
+public char scanner_linebuf[MAXLINESIZE];
 
 private File in;
 
 private File in;
-private Char linebuf[MAXLINESIZE];
-private Char *curchar;
+private char *curchar, *prevchar;
 
 #define MAXINCLDEPTH 10
 
 
 #define MAXINCLDEPTH 10
 
@@ -52,8 +63,7 @@ private Token getident();
 private Token getnum();
 private Token getstring();
 private Boolean eofinput();
 private Token getnum();
 private Token getstring();
 private Boolean eofinput();
-private Char charcon();
-private Char charlookup();
+private char charcon();
 
 private enterlexclass(class, s)
 Charclass class;
 
 private enterlexclass(class, s)
 Charclass class;
@@ -80,17 +90,19 @@ public scanner_init()
     in = stdin;
     errfilename = nil;
     errlineno = 0;
     in = stdin;
     errfilename = nil;
     errlineno = 0;
-    curchar = linebuf;
-    linebuf[0] = '\0';
+    curchar = scanner_linebuf;
+    scanner_linebuf[0] = '\0';
+    chkalias = true;
 }
 
 /*
  * Read a single token.
  *
 }
 
 /*
  * Read a single token.
  *
- * Input is line buffered.
+ * The input is line buffered.  Tokens cannot cross line boundaries.
  *
  * There are two "modes" of operation:  one as in a compiler,
  *
  * There are two "modes" of operation:  one as in a compiler,
- * and one for reading shell-like syntax.
+ * and one for reading shell-like syntax.  In the first mode
+ * there is the additional choice of doing alias processing.
  */
 
 private Boolean shellmode;
  */
 
 private Boolean shellmode;
@@ -101,37 +113,40 @@ public Token yylex()
     register char *p;
     register Token t;
     String line;
     register char *p;
     register Token t;
     String line;
+    integer n;
 
     p = curchar;
     if (*p == '\0') {
        do {
            if (isterm(in)) {
                printf("(%s) ", cmdname);
 
     p = curchar;
     if (*p == '\0') {
        do {
            if (isterm(in)) {
                printf("(%s) ", cmdname);
-               fflush(stdout);
            }
            }
-           line = fgets(linebuf, MAXLINESIZE, in);
+           fflush(stdout);
+           line = fgets(scanner_linebuf, MAXLINESIZE, in);
        } while (line == nil and not eofinput());
        if (line == nil) {
            c = EOF;
        } else {
        } while (line == nil and not eofinput());
        if (line == nil) {
            c = EOF;
        } else {
-           p = linebuf;
+           p = scanner_linebuf;
            while (lexclass[*p] == WHITE) {
                p++;
            }
            shellmode = false;
        }
            while (lexclass[*p] == WHITE) {
                p++;
            }
            shellmode = false;
        }
+       chkalias = true;
     } else {
        while (lexclass[*p] == WHITE) {
            p++;
        }
     }
     curchar = p;
     } else {
        while (lexclass[*p] == WHITE) {
            p++;
        }
     }
     curchar = p;
+    prevchar = curchar;
     c = *p;
     if (lexclass[c] == ALPHA) {
     c = *p;
     if (lexclass[c] == ALPHA) {
-       t = getident();
+       t = getident(chkalias);
     } else if (lexclass[c] == NUM) {
        if (shellmode) {
     } else if (lexclass[c] == NUM) {
        if (shellmode) {
-           t = getident();
+           t = getident(chkalias);
        } else {
            t = getnum();
        }
        } else {
            t = getnum();
        }
@@ -147,13 +162,13 @@ public Token yylex()
 
            case '"':
            case '\'':
 
            case '"':
            case '\'':
-               t = getstring();
+               t = getstring(c);
                break;
 
            case '.':
                if (shellmode) {
                    --curchar;
                break;
 
            case '.':
                if (shellmode) {
                    --curchar;
-                   t = getident();
+                   t = getident(chkalias);
                } else if (isdigit(*curchar)) {
                    --curchar;
                    t = getnum();
                } else if (isdigit(*curchar)) {
                    --curchar;
                    t = getnum();
@@ -162,42 +177,44 @@ public Token yylex()
                }
                break;
 
                }
                break;
 
-           case '<':
-               if (not shellmode and *curchar == '<') {
-                   ++curchar;
-                   t = LFORMER;
-               } else {
-                   t = '<';
-               }
-               break;
-
-           case '>':
-               if (not shellmode and *curchar == '>') {
+           case '-':
+               if (shellmode) {
+                   --curchar;
+                   t = getident(chkalias);
+               } else if (*curchar == '>') {
                    ++curchar;
                    ++curchar;
-                   t = RFORMER;
+                   t = ARROW;
                } else {
                } else {
-                   t = '>';
+                   t = '-';
                }
                break;
 
            case '#':
                }
                break;
 
            case '#':
-               if (*curchar == '^') {
-                   ++curchar;
-                   t = ABSTRACTION;
+               if (not isterm(in)) {
+                   *p = '\0';
+                   curchar = p;
+                   t = '\n';
+                   ++errlineno;
                } else {
                    t = '#';
                }
                break;
 
                } else {
                    t = '#';
                }
                break;
 
-           case '-':
-               if (shellmode) {
-                   --curchar;
-                   t = getident();
-               } else if (*curchar == '>') {
-                   ++curchar;
-                   t = ARROW;
+           case '\\':
+               if (*(p+1) == '\n') {
+                   n = MAXLINESIZE - (p - &scanner_linebuf[0]);
+                   if (n > 1) {
+                       if (fgets(p, n, in) == nil) {
+                           t = 0;
+                       } else {
+                           curchar = p;
+                           t = yylex();
+                       }
+                   } else {
+                       t = '\\';
+                   }
                } else {
                } else {
-                   t = '-';
+                   t = '\\';
                }
                break;
 
                }
                break;
 
@@ -206,15 +223,16 @@ public Token yylex()
                break;
 
            default:
                break;
 
            default:
-               if (shellmode and index("!&*()[]", c) == nil) {
+               if (shellmode and index("!&*<>()[]", c) == nil) {
                    --curchar;
                    --curchar;
-                   t = getident();
+                   t = getident(chkalias);
                } else {
                    t = c;
                }
                break;
        }
     }
                } else {
                    t = c;
                }
                break;
        }
     }
+    chkalias = false;
 #   ifdef LEXDEBUG
        if (lexdebug) {
            fprintf(stderr, "yylex returns ");
 #   ifdef LEXDEBUG
        if (lexdebug) {
            fprintf(stderr, "yylex returns ");
@@ -225,6 +243,160 @@ public Token yylex()
     return t;
 }
 
     return t;
 }
 
+/*
+ * Put the given string before the current character
+ * in the current line, thus inserting it into the input stream.
+ */
+
+public insertinput (s)
+String s;
+{
+    register char *p, *q;
+    int need, avail, shift;
+
+    q = s;
+    need = strlen(q);
+    avail = curchar - &scanner_linebuf[0];
+    if (need <= avail) {
+       curchar = &scanner_linebuf[avail - need];
+       p = curchar;
+       while (*q != '\0') {
+           *p++ = *q++;
+       }
+    } else {
+       p = curchar;
+       while (*p != '\0') {
+           ++p;
+       }
+       shift = need - avail;
+       if (p + shift >= &scanner_linebuf[MAXLINESIZE]) {
+           error("alias expansion too large");
+       }
+       for (;;) {
+           *(p + shift) = *p;
+           if (p == curchar) {
+               break;
+           }
+           --p;
+       }
+       p = &scanner_linebuf[0];
+       while (*q != '\0') {
+           *p++ = *q++;
+       }
+       curchar = &scanner_linebuf[0];
+    }
+}
+
+/*
+ * Get the actuals for a macro call.
+ */
+
+private String movetochar (str, c)
+String str;
+char c;
+{
+    register char *p;
+
+    while (*p != c) {
+       if (*p == '\0') {
+           error("missing ')' in macro call");
+       } else if (*p == ')') {
+           error("not enough parameters in macro call");
+       } else if (*p == ',') {
+           error("too many parameters in macro call");
+       }
+       ++p;
+    }
+    return p;
+}
+
+private String *getactuals (n)
+integer n;
+{
+    String *a;
+    register char *p;
+    int i;
+
+    a = newarr(String, n);
+    p = curchar;
+    while (*p != '(') {
+       if (lexclass[*p] != WHITE) {
+           error("missing actuals for macro");
+       }
+       ++p;
+    }
+    ++p;
+    for (i = 0; i < n - 1; i++) {
+       a[i] = p;
+       p = movetochar(p, ',');
+       *p = '\0';
+       ++p;
+    }
+    a[n-1] = p;
+    p = movetochar(p, ')');
+    *p = '\0';
+    curchar = p + 1;
+    return a;
+}
+
+/*
+ * Do command macro expansion, assuming curchar points to the beginning
+ * of the actuals, and we are not in shell mode.
+ */
+
+private expand (pl, str)
+List pl;
+String str;
+{
+    char buf[4096], namebuf[100];
+    register char *p, *q, *r;
+    String *actual;
+    Name n;
+    integer i;
+    boolean match;
+
+    if (pl == nil) {
+       insertinput(str);
+    } else {
+       actual = getactuals(list_size(pl));
+       p = buf;
+       q = str;
+       while (*q != '\0') {
+           if (p >= &buf[4096]) {
+               error("alias expansion too large");
+           }
+           if (lexclass[*q] == ALPHA) {
+               r = namebuf;
+               do {
+                   *r++ = *q++;
+               } while (isalnum(*q));
+               *r = '\0';
+               i = 0;
+               match = false;
+               foreach(Name, n, pl)
+                   if (streq(ident(n), namebuf)) {
+                       match = true;
+                       break;
+                   }
+                   ++i;
+               endfor
+               if (match) {
+                   r = actual[i];
+               } else {
+                   r = namebuf;
+               }
+               while (*r != '\0') {
+                   *p++ = *r++;
+               }
+           } else {
+               *p++ = *q++;
+           }
+       }
+       *p = '\0';
+       insertinput(buf);
+    }
+}
+
 /*
  * Parser error handling.
  */
 /*
  * Parser error handling.
  */
@@ -232,30 +404,26 @@ public Token yylex()
 public yyerror(s)
 String s;
 {
 public yyerror(s)
 String s;
 {
-    register Char *p, *tokenbegin, *tokenend;
-    register Integer len;
+    register char *p;
+    register integer start;
 
     if (streq(s, "syntax error")) {
        beginerrmsg();
 
     if (streq(s, "syntax error")) {
        beginerrmsg();
-       tokenend = curchar - 1;
-       tokenbegin = tokenend;
-       while (lexclass[*tokenbegin] != WHITE and tokenbegin > &linebuf[0]) {
-           --tokenbegin;
-       }
-       len = tokenend - tokenbegin + 1;
-       p = tokenbegin;
-       if (p > &linebuf[0]) {
-           while (lexclass[*p] == WHITE and p > &linebuf[0]) {
+       p = prevchar;
+       start = p - &scanner_linebuf[0];
+       if (p > &scanner_linebuf[0]) {
+           while (lexclass[*p] == WHITE and p > &scanner_linebuf[0]) {
                --p;
            }
        }
                --p;
            }
        }
-       if (p == &linebuf[0]) {
-           fprintf(stderr, "unrecognized command \"%.*s\"", len, tokenbegin);
+       fprintf(stderr, "%s", scanner_linebuf);
+       if (start != 0) {
+           fprintf(stderr, "%*c", start, ' ');
+       }
+       if (p == &scanner_linebuf[0]) {
+           fprintf(stderr, "^ unrecognized command");
        } else {
        } else {
-           fprintf(stderr, "syntax error");
-           if (len != 0) {
-               fprintf(stderr, " on \"%.*s\"", len, tokenbegin);
-           }
+           fprintf(stderr, "^ syntax error");
        }
        enderrmsg();
     } else {
        }
        enderrmsg();
     } else {
@@ -267,28 +435,34 @@ String s;
  * Eat the current line.
  */
 
  * Eat the current line.
  */
 
-public gobble()
+public gobble ()
 {
 {
-    curchar = linebuf;
-    linebuf[0] = '\0';
+    curchar = scanner_linebuf;
+    scanner_linebuf[0] = '\0';
 }
 
 /*
 }
 
 /*
- * Scan an identifier and check to see if it's a keyword.
+ * Scan an identifier.
+ *
+ * If chkalias is true, check first to see if it's an alias.
+ * Otherwise, check to see if it's a keyword.
  */
 
  */
 
-private Token getident()
+private Token getident (chkalias)
+boolean chkalias;
 {
 {
-    char buf[256];
-    register Char *p, *q;
+    char buf[1024];
+    register char *p, *q;
     register Token t;
     register Token t;
+    List pl;
+    String str;
 
     p = curchar;
     q = buf;
     if (shellmode) {
        do {
            *q++ = *p++;
 
     p = curchar;
     q = buf;
     if (shellmode) {
        do {
            *q++ = *p++;
-       } while (index(" \t\n!&<>*[]()", *p) == nil);
+       } while (index(" \t\n!&<>*[]()'\"", *p) == nil);
     } else {
        do {
            *q++ = *p++;
     } else {
        do {
            *q++ = *p++;
@@ -297,13 +471,26 @@ private Token getident()
     curchar = p;
     *q = '\0';
     yylval.y_name = identname(buf, false);
     curchar = p;
     *q = '\0';
     yylval.y_name = identname(buf, false);
-    if (not shellmode) {
-       t = findkeyword(yylval.y_name);
-       if (t == nil) {
+    if (chkalias) {
+       if (findalias(yylval.y_name, &pl, &str)) {
+           expand(pl, str);
+           while (lexclass[*curchar] == WHITE) {
+               ++curchar;
+           }
+           if (pl == nil) {
+               t = getident(false);
+           } else {
+               t = getident(true);
+           }
+       } else if (shellmode) {
            t = NAME;
            t = NAME;
+       } else {
+           t = findkeyword(yylval.y_name, NAME);
        }
        }
-    } else {
+    } else if (shellmode) {
        t = NAME;
        t = NAME;
+    } else {
+       t = findkeyword(yylval.y_name, NAME);
     }
     return t;
 }
     }
     return t;
 }
@@ -314,7 +501,7 @@ private Token getident()
 
 private Token getnum()
 {
 
 private Token getnum()
 {
-    char buf[256];
+    char buf[1024];
     register Char *p, *q;
     register Token t;
     Integer base;
     register Char *p, *q;
     register Token t;
     Integer base;
@@ -325,9 +512,17 @@ private Token getnum()
        if (*(p+1) == 'x') {
            p += 2;
            base = 16;
        if (*(p+1) == 'x') {
            p += 2;
            base = 16;
+       } else if (*(p+1) == 't') {
+           base = 10;
+       } else if (varIsSet("$hexin")) {
+           base = 16;
        } else {
            base = 8;
        }
        } else {
            base = 8;
        }
+    } else if (varIsSet("$hexin")) {
+       base = 16;
+    } else if (varIsSet("$octin")) {
+       base = 8;
     } else {
        base = 10;
     }
     } else {
        base = 10;
     }
@@ -425,25 +620,28 @@ String s;
  * Scan a string.
  */
 
  * Scan a string.
  */
 
-private Token getstring()
+private Token getstring (quote)
+char quote;
 {
 {
-    char buf[256];
-    register Char *p, *q;
-    Boolean endofstring;
+    register char *p, *q;
+    char buf[MAXLINESIZE];
+    boolean endofstring;
+    Token t;
 
     p = curchar;
     q = buf;
     endofstring = false;
     while (not endofstring) {
 
     p = curchar;
     q = buf;
     endofstring = false;
     while (not endofstring) {
-       if (*p == '\n' or *p == '\0') {
+       if (*p == '\\' and *(p+1) == '\n') {
+           if (fgets(scanner_linebuf, MAXLINESIZE, in) == nil) {
+               error("non-terminated string");
+           }
+           p = &scanner_linebuf[0] - 1;
+       } else if (*p == '\n' or *p == '\0') {
            error("non-terminated string");
            endofstring = true;
            error("non-terminated string");
            endofstring = true;
-       } else if (*p == '"' or *p == '\'') {
-           if (*(p+1) != *p) {
-               endofstring = true;
-           } else {
-               *q++ = *p;
-           }
+       } else if (*p == quote) {
+           endofstring = true;
        } else {
            curchar = p;
            *q++ = charcon(p);
        } else {
            curchar = p;
            *q++ = charcon(p);
@@ -453,8 +651,14 @@ private Token getstring()
     }
     curchar = p;
     *q = '\0';
     }
     curchar = p;
     *q = '\0';
-    yylval.y_string = strdup(buf);
-    return STRING;
+    if (quote == '\'' and buf[1] == '\0') {
+       yylval.y_char = buf[0];
+       t = CHAR;
+    } else {
+       yylval.y_string = strdup(buf);
+       t = STRING;
+    }
+    return t;
 }
 
 /*
 }
 
 /*
@@ -462,61 +666,54 @@ private Token getstring()
  * Watch out for backslashes.
  */
 
  * Watch out for backslashes.
  */
 
-private Char charcon(p)
-char *p;
+private char charcon (s)
+String s;
 {
 {
-    char c, buf[10], *q;
+    register char *p, *q;
+    char c, buf[10];
 
 
+    p = s;
     if (*p == '\\') {
        ++p;
     if (*p == '\\') {
        ++p;
-       if (*p != '\\') {
-           q = buf;
-           do {
-               *q++ = *p++;
-           } while (*p != '\\' and *p != '\'' and *p != '\n' and *p != '\0');
-           *q = '\0';
-           if (isdigit(buf[0])) {
-               c = (Char) octal(buf);
-           } else {
-               c = charlookup(buf);
-           }
-           curchar = p - 1;
-       } else {
-           c = '\\';
-       }
-    } else {
-       c = *p;
-    }
-    return c;
-}
+       switch (*p) {
+           case '\\':
+               c = '\\';
+               break;
 
 
-/*
- * Do a lookup for a ASCII character name.
- */
+           case 'n':
+               c = '\n';
+               break;
 
 
-private String ascii[] = {
-    "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
-    "BS",  "HT",  "NL",  "VT",  "NP",  "CR",  "SO",  "SI",
-    "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
-    "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US",
-    "SP", nil
-};
+           case 'r':
+               c = '\r';
+               break;
 
 
-private char charlookup(s)
-String s;
-{
-    register int i;
+           case 't':
+               c = '\t';
+               break;
+
+           case '\'':
+           case '"':
+               c = *p;
+               break;
 
 
-    for (i = 0; ascii[i] != NULL; i++) {
-       if (streq(s, ascii[i])) {
-           return i;
+           default:
+               if (isdigit(*p)) {
+                   q = buf;
+                   do {
+                       *q++ = *p++;
+                   } while (isdigit(*p));
+                   *q = '\0';
+                   c = (char) octal(buf);
+               }
+               --p;
+               break;
        }
        }
+       curchar = p;
+    } else {
+       c = *p;
     }
     }
-    if (streq(s, "DEL")) {
-       return 0177;
-    }
-    error("unknown ascii name \"%s\"", s);
-    return '?';
+    return c;
 }
 
 /*
 }
 
 /*