#ifndef lint static char sccsid[] = "@(#)rpc←scan.c 1.1 90/10/29 (C) 1987 SMI"; #endif /* * rpc←scan.c, Scanner for the RPC protocol compiler * Copyright (C) 1987, Sun Microsystems, Inc. */ #include <stdio.h> #include <ctype.h> #include <strings.h> #include <string.h> #include "rpc←scan.h" #include "rpc←util.h" #define startcomment(where) (where[0] == '/' && where[1] == '*') #define endcomment(where) (where[-1] == '*' && where[0] == '/') static int pushed = 0; /* is a token pushed */ static token lasttok; /* last token, if pushed */ /* * scan expecting 1 given token */ void scan(expect, tokp) tok←kind expect; token *tokp; { get←token(tokp); if (tokp->kind != expect) { expected1(expect); } } /* * scan expecting any of the 2 given tokens */ void scan2(expect1, expect2, tokp) tok←kind expect1; tok←kind expect2; token *tokp; { get←token(tokp); if (tokp->kind != expect1 && tokp->kind != expect2) { expected2(expect1, expect2); } } /* * scan expecting any of the 3 given token */ void scan3(expect1, expect2, expect3, tokp) tok←kind expect1; tok←kind expect2; tok←kind expect3; token *tokp; { get←token(tokp); if (tokp->kind != expect1 && tokp->kind != expect2 && tokp->kind != expect3) { expected3(expect1, expect2, expect3); } } /* * scan expecting a constant, possibly symbolic */ void scan←num(tokp) token *tokp; { get←token(tokp); switch (tokp->kind) { case TOK←IDENT: break; default: error("constant or identifier expected"); } } /* * Peek at the next token */ void peek(tokp) token *tokp; { get←token(tokp); unget←token(tokp); } /* * Peek at the next token and scan it if it matches what you expect */ int peekscan(expect, tokp) tok←kind expect; token *tokp; { peek(tokp); if (tokp->kind == expect) { get←token(tokp); return (1); } return (0); } /* * Get the next token, printing out any directive that are encountered. */ void get←token(tokp) token *tokp; { int commenting; if (pushed) { pushed = 0; *tokp = lasttok; return; } commenting = 0; for (;;) { if (*CurrentContext->where == 0) { for (;;) { if (!fgets(CurrentContext->curline, MAXLINESIZE, CurrentContext->fin)) { tokp->kind = TOK←EOF; *CurrentContext->where = 0; return; } CurrentContext->linenum++; if (commenting) { break; } else if (cppline(CurrentContext->curline)) { docppline(CurrentContext->curline, &CurrentContext->linenum, &CurrentContext->infilename); } else if (directive(CurrentContext->curline)) { printdirective(CurrentContext->curline); } else { break; } } CurrentContext->where = CurrentContext->curline; } else if (isspace(*CurrentContext->where)) { while (isspace(*CurrentContext->where)) { CurrentContext->where++; /* eat */ } } else if (commenting) { for (CurrentContext->where++; *CurrentContext->where; CurrentContext->where++) { if (endcomment(CurrentContext->where)) { CurrentContext->where++; commenting--; break; } } } else if (startcomment(CurrentContext->where)) { CurrentContext->where += 2; commenting++; } else { break; } } /* * 'where' is not whitespace, comment or directive Must be a token! */ switch (*CurrentContext->where) { case ':': tokp->kind = TOK←COLON; CurrentContext->where++; break; case ';': tokp->kind = TOK←SEMICOLON; CurrentContext->where++; break; case ',': tokp->kind = TOK←COMMA; CurrentContext->where++; break; case '=': tokp->kind = TOK←EQUAL; CurrentContext->where++; break; case '*': tokp->kind = TOK←STAR; CurrentContext->where++; break; case '[': tokp->kind = TOK←LBRACKET; CurrentContext->where++; break; case ']': tokp->kind = TOK←RBRACKET; CurrentContext->where++; break; case '{': tokp->kind = TOK←LBRACE; CurrentContext->where++; break; case '}': tokp->kind = TOK←RBRACE; CurrentContext->where++; break; case '(': tokp->kind = TOK←LPAREN; CurrentContext->where++; break; case ')': tokp->kind = TOK←RPAREN; CurrentContext->where++; break; case '<': tokp->kind = TOK←LANGLE; CurrentContext->where++; break; case '>': tokp->kind = TOK←RANGLE; CurrentContext->where++; break; case '"': tokp->kind = TOK←STRCONST; findstrconst(&CurrentContext->where, &tokp->str); break; case '\'': tokp->kind = TOK←CHARCONST; findchrconst(&CurrentContext->where, &tokp->str); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tokp->kind = TOK←IDENT; findconst(&CurrentContext->where, &tokp->str); break; default: if (!(isalpha(*CurrentContext->where) || *CurrentContext->where == '←')) { char buf[100]; char *p; s←print(buf, "illegal character in file: "); p = buf + strlen(buf); if (isprint(*CurrentContext->where)) { s←print(p, "%c", *CurrentContext->where); } else { s←print(p, "%d", *CurrentContext->where); } error(buf); } findkind(&CurrentContext->where, tokp); break; } } static unget←token(tokp) token *tokp; { lasttok = *tokp; pushed = 1; } static findstrconst(str, val) char **str; char **val; { char *p; int size; p = *str; do { *p++; } while (*p && *p != '"'); if (*p == 0) { error("unterminated string constant"); } p++; size = p - *str; *val = alloc(size + 1); (void) strncpy(*val, *str, size); (*val)[size] = 0; *str = p; } static findchrconst(str, val) char **str; char **val; { char *p; int size; p = *str; do { *p++; } while (*p && *p != '\''); if (*p == 0) { error("unterminated string constant"); } p++; size = p - *str; if (size != 3) { error("empty char string"); } *val = alloc(size + 1); (void) strncpy(*val, *str, size); (*val)[size] = 0; *str = p; } static findconst(str, val) char **str; char **val; { char *p; int size; p = *str; if (*p == '0' && *(p + 1) == 'x') { p++; do { p++; } while (isxdigit(*p)); } else { do { p++; } while (isdigit(*p)); } size = p - *str; *val = alloc(size + 1); (void) strncpy(*val, *str, size); (*val)[size] = 0; *str = p; } static token symbols[] = { {TOK←CONST, "const"}, {TOK←UNION, "union"}, {TOK←SWITCH, "switch"}, {TOK←CASE, "case"}, {TOK←DEFAULT, "default"}, {TOK←STRUCT, "struct"}, {TOK←TYPEDEF, "typedef"}, {TOK←ENUM, "enum"}, {TOK←OPAQUE, "opaque"}, {TOK←BOOL, "bool"}, {TOK←VOID, "void"}, {TOK←CHAR, "char"}, {TOK←INT, "int"}, {TOK←UNSIGNED, "unsigned"}, {TOK←SHORT, "short"}, {TOK←LONG, "long"}, {TOK←FLOAT, "float"}, {TOK←DOUBLE, "double"}, {TOK←STRING, "string"}, {TOK←PROGRAM, "program"}, {TOK←VERSION, "version"}, {TOK←EOF, "??????"}, }; static findkind(mark, tokp) char **mark; token *tokp; { int len; token *s; char *str; int i; char *dest, *src; char nameBuf[128]; str = *mark; for (s = symbols; s->kind != TOK←EOF; s++) { len = strlen(s->str); if (strncmp(str, s->str, len) == 0) { if (!isalnum(str[len]) && str[len] != '←') { tokp->kind = s->kind; tokp->str = s->str; *mark = str + len; return; } } } tokp->kind = TOK←IDENT; for (len = 0; isalnum(str[len]) || str[len] == '←'; len++); tokp->str = alloc(len + 1); for (i = 0, dest = tokp->str, src = str; i < len; i++) { if (*src != '←') *dest++ = *src++; else src++; } *dest = '\0'; *mark = str + len; tokp->str = StripPrefix(svcName, tokp->str); } static cppline(line) char *line; { return (line == CurrentContext->curline && *line == '#'); } static directive(line) char *line; { return (line == CurrentContext->curline && *line == '%'); } /* Return ptr to just past non-white space. */ static char *SkipName(p) char *p; { char *p1; for (p1 = p; ((*p1 != ' ') && (*p1 != '\t') && (*p1 != '\0')); p1++) ; /* NULL STAT */ return (p1); } /* Return ptr to just past white space. */ static char *SkipWhiteSpace(p) char *p; { char *p1; for (p1 = p; ((*p1 == ' ') || (*p1 == '\t')); p1++) ; /* NULL STAT */ return (p1); } static printdirective(line) char *line; { char *line0 = line; char *p = malloc(strlen(line)); char *p1, *p2; /* * We can handle directives of the following form: * #define name value * Don't emit anything since we can't be sure what's there. * #ifndef ... * Emit nothing. * #endif ... * Emit nothing. * #define name * Emit nothing. * #include "foo.h" * We can handle this only if there is a corresponding .x file * that we can parse. The meaning, in this case, is that we * should import all the type decls from the corresponding Cedar * interface file. */ line++; /* Skip over directive character. */ line[strlen(line)-1] = '\0'; /* Get rid of trailing newline. */ /* Determine what kind of directive we have and act accordingly. */ if (strncmp(line, "#define", 7) == 0) { /* Emit nothing. */; } else if (strncmp(line, "#if", 3) == 0) { return; } else if (strncmp(line, "#endif", 6) == 0) { return; } else if (strncmp(line, "#include", 8) == 0) { line += 8; /* Skip over #include */ line = SkipWhiteSpace(line); /* Skip over white space. */ line++; /* Skip over " or < character. */ strcpy(p, line); p1 = strrchr(p, '.'); if (p1 == NULL) { fprintf(stderr, "ERROR: Unanticipated .X file directive encountered: %s\n", line0); fprintf(stderr, " Unable to translate to Cedar.\n"); exit(-1); } *p1 = '\0'; /* Delimit end of include name. */ ProcessImport(p); } /* else Unknown directive line encountered. All we can do is ignore it. */ } static docppline(line, lineno, fname) char *line; int *lineno; char **fname; { char *file; int num; char *p; line++; while (isspace(*line)) { line++; } num = atoi(line); while (isdigit(*line)) { line++; } while (isspace(*line)) { line++; } if (*line != '"') { error("preprocessor error"); } line++; p = file = alloc(strlen(line) + 1); while (*line && *line != '"') { *p++ = *line++; } if (*line == 0) { error("preprocessor error"); } *p = 0; if (*file == 0) { *fname = NULL; } else { *fname = file; } *lineno = num - 1; }