| /* |
| * 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; |
| } |