|  | /* | 
|  | * From: @(#)rpc_scan.c 1.11 89/02/22 | 
|  | * | 
|  | * Copyright (c) 2010, Oracle America, Inc. | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions are | 
|  | * met: | 
|  | * | 
|  | *     * Redistributions of source code must retain the above copyright | 
|  | *       notice, this list of conditions and the following disclaimer. | 
|  | *     * 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. | 
|  | *     * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 | 
|  | *   COPYRIGHT HOLDER 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. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * rpc_scan.c, Scanner for the RPC protocol compiler | 
|  | * Copyright (C) 1987, Sun Microsystems, Inc. | 
|  | */ | 
|  | #include <stdio.h> | 
|  | #include <ctype.h> | 
|  | #include <string.h> | 
|  | #include <libintl.h> | 
|  | #include "rpc_scan.h" | 
|  | #include "rpc_parse.h" | 
|  | #include "rpc_util.h" | 
|  | #include "proto.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 */ | 
|  |  | 
|  | static void unget_token (token * tokp); | 
|  | static void findstrconst (const char **str, const char **val); | 
|  | static void findchrconst (const char **str, const char **val); | 
|  | static void findconst (const char **str, const char **val); | 
|  | static void findkind (const char **mark, token * tokp); | 
|  | static int cppline (const char *line); | 
|  | static int directive (const char *line); | 
|  | static void printdirective (const char *line); | 
|  | static void docppline (const char *line, int *lineno, const char **fname); | 
|  |  | 
|  | /* | 
|  | * scan expecting 1 given token | 
|  | */ | 
|  | void | 
|  | scan (tok_kind expect, token * tokp) | 
|  | { | 
|  | get_token (tokp); | 
|  | if (tokp->kind != expect) | 
|  | expected1 (expect); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * scan expecting any of the 2 given tokens | 
|  | */ | 
|  | void | 
|  | scan2 (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 (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 (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 (token *tokp) | 
|  | { | 
|  | get_token (tokp); | 
|  | unget_token (tokp); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Peek at the next token and scan it if it matches what you expect | 
|  | */ | 
|  | int | 
|  | peekscan (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 (token *tokp) | 
|  | { | 
|  | int commenting; | 
|  |  | 
|  | if (pushed) | 
|  | { | 
|  | pushed = 0; | 
|  | *tokp = lasttok; | 
|  | return; | 
|  | } | 
|  | commenting = 0; | 
|  | for (;;) | 
|  | { | 
|  | if (*where == 0) | 
|  | { | 
|  | for (;;) | 
|  | { | 
|  | if (!fgets (curline, MAXLINESIZE, fin)) | 
|  | { | 
|  | tokp->kind = TOK_EOF; | 
|  | *curline = 0; | 
|  | where = curline; | 
|  | return; | 
|  | } | 
|  | linenum++; | 
|  | if (commenting) | 
|  | { | 
|  | break; | 
|  | } | 
|  | else if (cppline (curline)) | 
|  | { | 
|  | docppline (curline, &linenum, | 
|  | &infilename); | 
|  | } | 
|  | else if (directive (curline)) | 
|  | { | 
|  | printdirective (curline); | 
|  | } | 
|  | else | 
|  | { | 
|  | break; | 
|  | } | 
|  | } | 
|  | where = curline; | 
|  | } | 
|  | else if (isspace (*where)) | 
|  | { | 
|  | while (isspace (*where)) | 
|  | { | 
|  | where++;		/* eat */ | 
|  | } | 
|  | } | 
|  | else if (commenting) | 
|  | { | 
|  | for (where++; *where; where++) | 
|  | { | 
|  | if (endcomment (where)) | 
|  | { | 
|  | where++; | 
|  | commenting--; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | else if (startcomment (where)) | 
|  | { | 
|  | where += 2; | 
|  | commenting++; | 
|  | } | 
|  | else | 
|  | { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 'where' is not whitespace, comment or directive Must be a token! | 
|  | */ | 
|  | switch (*where) | 
|  | { | 
|  | case ':': | 
|  | tokp->kind = TOK_COLON; | 
|  | where++; | 
|  | break; | 
|  | case ';': | 
|  | tokp->kind = TOK_SEMICOLON; | 
|  | where++; | 
|  | break; | 
|  | case ',': | 
|  | tokp->kind = TOK_COMMA; | 
|  | where++; | 
|  | break; | 
|  | case '=': | 
|  | tokp->kind = TOK_EQUAL; | 
|  | where++; | 
|  | break; | 
|  | case '*': | 
|  | tokp->kind = TOK_STAR; | 
|  | where++; | 
|  | break; | 
|  | case '[': | 
|  | tokp->kind = TOK_LBRACKET; | 
|  | where++; | 
|  | break; | 
|  | case ']': | 
|  | tokp->kind = TOK_RBRACKET; | 
|  | where++; | 
|  | break; | 
|  | case '{': | 
|  | tokp->kind = TOK_LBRACE; | 
|  | where++; | 
|  | break; | 
|  | case '}': | 
|  | tokp->kind = TOK_RBRACE; | 
|  | where++; | 
|  | break; | 
|  | case '(': | 
|  | tokp->kind = TOK_LPAREN; | 
|  | where++; | 
|  | break; | 
|  | case ')': | 
|  | tokp->kind = TOK_RPAREN; | 
|  | where++; | 
|  | break; | 
|  | case '<': | 
|  | tokp->kind = TOK_LANGLE; | 
|  | where++; | 
|  | break; | 
|  | case '>': | 
|  | tokp->kind = TOK_RANGLE; | 
|  | where++; | 
|  | break; | 
|  |  | 
|  | case '"': | 
|  | tokp->kind = TOK_STRCONST; | 
|  | findstrconst (&where, &tokp->str); | 
|  | break; | 
|  | case '\'': | 
|  | tokp->kind = TOK_CHARCONST; | 
|  | findchrconst (&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 (&where, &tokp->str); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | if (!(isalpha (*where) || *where == '_')) | 
|  | { | 
|  | char buf[100]; | 
|  | char *p; | 
|  |  | 
|  | s_print (buf, _("illegal character in file: ")); | 
|  | p = buf + strlen (buf); | 
|  | if (isprint (*where)) | 
|  | { | 
|  | s_print (p, "%c", *where); | 
|  | } | 
|  | else | 
|  | { | 
|  | s_print (p, "%d", *where); | 
|  | } | 
|  | error (buf); | 
|  | } | 
|  | findkind (&where, tokp); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | unget_token (token * tokp) | 
|  | { | 
|  | lasttok = *tokp; | 
|  | pushed = 1; | 
|  | } | 
|  |  | 
|  | static void | 
|  | findstrconst (const char **str, const char **val) | 
|  | { | 
|  | const char *p; | 
|  | char *tmp; | 
|  | int size; | 
|  |  | 
|  | p = *str; | 
|  | do | 
|  | { | 
|  | p++; | 
|  | } | 
|  | while (*p && *p != '"'); | 
|  | if (*p == 0) | 
|  | { | 
|  | error (_("unterminated string constant")); | 
|  | } | 
|  | p++; | 
|  | size = p - *str; | 
|  | tmp = alloc (size + 1); | 
|  | strncpy (tmp, *str, size); | 
|  | tmp[size] = 0; | 
|  | *val = tmp; | 
|  | *str = p; | 
|  | } | 
|  |  | 
|  | static void | 
|  | findchrconst (const char **str, const char **val) | 
|  | { | 
|  | const char *p; | 
|  | char *tmp; | 
|  | 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")); | 
|  | } | 
|  | tmp = alloc (size + 1); | 
|  | strncpy (tmp, *str, size); | 
|  | tmp[size] = 0; | 
|  | *val = tmp; | 
|  | *str = p; | 
|  | } | 
|  |  | 
|  | static void | 
|  | findconst (const char **str, const char **val) | 
|  | { | 
|  | const char *p; | 
|  | char *tmp; | 
|  | 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; | 
|  | tmp = alloc (size + 1); | 
|  | strncpy (tmp, *str, size); | 
|  | tmp[size] = 0; | 
|  | *val = tmp; | 
|  | *str = p; | 
|  | } | 
|  |  | 
|  | static const 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_HYPER, "hyper"}, | 
|  | {TOK_FLOAT, "float"}, | 
|  | {TOK_DOUBLE, "double"}, | 
|  | {TOK_STRING, "string"}, | 
|  | {TOK_PROGRAM, "program"}, | 
|  | {TOK_VERSION, "version"}, | 
|  | {TOK_EOF, "??????"}, | 
|  | }; | 
|  |  | 
|  | static void | 
|  | findkind (const char **mark, token *tokp) | 
|  | { | 
|  | int len; | 
|  | const token *s; | 
|  | const char *str; | 
|  | char *tmp; | 
|  |  | 
|  | 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++); | 
|  | tmp = alloc (len + 1); | 
|  | strncpy (tmp, str, len); | 
|  | tmp[len] = 0; | 
|  | tokp->str = tmp; | 
|  | *mark = str + len; | 
|  | } | 
|  |  | 
|  | static int | 
|  | cppline (const char *line) | 
|  | { | 
|  | return line == curline && *line == '#'; | 
|  | } | 
|  |  | 
|  | static int | 
|  | directive (const char *line) | 
|  | { | 
|  | return line == curline && *line == '%'; | 
|  | } | 
|  |  | 
|  | static void | 
|  | printdirective (const char *line) | 
|  | { | 
|  | f_print (fout, "%s", line + 1); | 
|  | } | 
|  |  | 
|  | static void | 
|  | docppline (const char *line, int *lineno, const 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) | 
|  | { | 
|  | free (file); | 
|  | *fname = NULL; | 
|  | } | 
|  | else | 
|  | { | 
|  | *fname = file; | 
|  | } | 
|  | *lineno = num - 1; | 
|  | } |