scanner.c
来自「早期freebsd实现」· C语言 代码 · 共 864 行 · 第 1/2 页
C
864 行
/* * Copyright (c) 1983 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)scanner.c 5.3 (Berkeley) 6/1/90";#endif /* not lint *//* * Debugger scanner. */#include "defs.h"#include "scanner.h"#include "main.h"#include "keywords.h"#include "tree.h"#include "symbols.h"#include "names.h"#include "y.tab.h"#ifndef publictypedef int Token;#define MAXLINESIZE 10240#endifpublic String initfile = ".dbxinit";typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass;private Charclass class[256 + 1];private Charclass *lexclass = class + 1;#define isdigit(c) (lexclass[c] == NUM)#define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM)#define ishexdigit(c) ( \ isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \)public boolean chkalias;public char scanner_linebuf[MAXLINESIZE];private File in;private char *curchar, *prevchar;#define MAXINCLDEPTH 10private struct { File savefile; Filename savefn; int savelineno;} inclinfo[MAXINCLDEPTH];private unsigned int curinclindex;private Token getident();private Token getnum();private Token getstring();private Boolean eofinput();private char charcon();private enterlexclass(class, s)Charclass class;String s;{ register char *p; for (p = s; *p != '\0'; p++) { lexclass[*p] = class; }}public scanner_init(){ register Integer i; for (i = 0; i < 257; i++) { class[i] = OTHER; } enterlexclass(WHITE, " \t"); enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz"); enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$"); enterlexclass(NUM, "0123456789"); in = stdin; errfilename = nil; errlineno = 0; curchar = scanner_linebuf; scanner_linebuf[0] = '\0'; chkalias = true;}/* * Read a single token. * * The input is line buffered. Tokens cannot cross line boundaries. * * There are two "modes" of operation: one as in a compiler, * and one for reading shell-like syntax. In the first mode * there is the additional choice of doing alias processing. */private Boolean shellmode;public Token yylex(){ register int c; register char *p; register Token t; String line; integer n; p = curchar; if (*p == '\0') { do { if (isterm(in)) { printf("(%s) ", cmdname); } fflush(stdout); line = fgets(scanner_linebuf, MAXLINESIZE, in); } while (line == nil and not eofinput()); if (line == nil) { c = EOF; } else { p = scanner_linebuf; while (lexclass[*p] == WHITE) { p++; } shellmode = false; } chkalias = true; } else { while (lexclass[*p] == WHITE) { p++; } } curchar = p; prevchar = curchar; c = *p; if (lexclass[c] == ALPHA) { t = getident(chkalias); } else if (lexclass[c] == NUM) { if (shellmode) { t = getident(chkalias); } else { t = getnum(); } } else { ++curchar; switch (c) { case '\n': t = '\n'; if (errlineno != 0) { errlineno++; } break; case '"': case '\'': t = getstring(c); break; case '.': if (shellmode) { --curchar; t = getident(chkalias); } else if (isdigit(*curchar)) { --curchar; t = getnum(); } else { t = '.'; } break; case '-': if (shellmode) { --curchar; t = getident(chkalias); } else if (*curchar == '>') { ++curchar; t = ARROW; } else { t = '-'; } break; case '#': if (not isterm(in)) { *p = '\0'; curchar = p; t = '\n'; ++errlineno; } else { t = '#'; } break; 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 { t = '\\'; } break; case EOF: t = 0; break; default: if (shellmode and index("!&*<>()[]", c) == nil) { --curchar; t = getident(chkalias); } else { t = c; } break; } } chkalias = false;# ifdef LEXDEBUG if (lexdebug) { fprintf(stderr, "yylex returns "); print_token(stderr, t); fprintf(stderr, "\n"); }# endif 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. */public yyerror(s)String s;{ register char *p;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?