📄 c-parse.y
字号:
last characters in the string, thus assuring the O(1) lookup time (this keeps our constant down to an insignificant amount!). Compiling the following 2 functions as inline removes all overhead of the function calls. */#ifdef __GNUC____inline#endifstatic inthash (str, len) register char *str; register int len;{/* This table is used to build the hash table index that recognizes reserved words in 0(1) steps. It is larger than strictly necessary, but I'm trading off the space for the time-saving luxury of avoiding subtraction of an offset. All those ``91's'' (actually just a short-hand for MAX_HASH_VALUE #defined above) are used to speed up the search when the string found on the input stream doesn't have a first or last character that is part of the set of alphabetic characters that comprise the first or last characters in C reserved words. */ static int hash_table[] = { 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 1, 91, 2, 1, 32, 7, 5, 18, 20, 1, 17, 91, 1, 18, 1, 28, 1, 23, 91, 12, 20, 1, 41, 7, 15, 91, 91, 10, 91, 91, 91, 91, 91, }; register int hval = len ; switch (hval) { default: case 3: hval += hash_table[str[2]]; case 2: case 1: return hval + hash_table[str[0]] + hash_table[str[len - 1]]; }}/* This routine attempts to match the string found in the reswords table with the one from the input stream. If all the relevant details match then an actual strcmp comparison is performed and the address of correct struct resword entry is returned. Otherwise, a NULL pointer is returned. */#ifdef __GNUC____inline#endifstruct resword *is_reserved_word (str, len) register char *str; register int len;{ /* This is the hash table of keywords. The order of keywords has been chosen for perfect hashing. Therefore, this table cannot be updated by hand. Use the program ``gperf,'' available with the latest libg++ distribution, to generate an updated table. A file called c-parse.gperf, distributed with GNU C, contains the keyword file. */ static struct resword reswords[] = { { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, {"asm", ASM, NORID }, {"auto", SCSPEC, RID_AUTO }, {"__asm", ASM, NORID }, {"do", DO, NORID }, {"__asm__", ASM, NORID }, {"break", BREAK, NORID }, {"__typeof__", TYPEOF, NORID }, { "", }, {"__alignof__", ALIGNOF, NORID }, { "", }, {"__attribute__", ATTRIBUTE, NORID }, { "", }, {"__attribute", ATTRIBUTE, NORID }, { "", }, {"__volatile__", TYPE_QUAL, RID_VOLATILE }, {"int", TYPESPEC, RID_INT }, {"__volatile", TYPE_QUAL, RID_VOLATILE }, { "", }, {"float", TYPESPEC, RID_FLOAT }, {"goto", GOTO, NORID }, {"short", TYPESPEC, RID_SHORT }, {"__typeof", TYPEOF, NORID }, {"__inline__", SCSPEC, RID_INLINE }, {"__alignof", ALIGNOF, NORID }, {"__inline", SCSPEC, RID_INLINE }, {"__signed__", TYPESPEC, RID_SIGNED }, {"default", DEFAULT, NORID }, {"else", ELSE, NORID }, {"void", TYPESPEC, RID_VOID }, {"__signed", TYPESPEC, RID_SIGNED }, {"if", IF, NORID }, {"volatile", TYPE_QUAL, RID_VOLATILE }, {"struct", STRUCT, NORID }, {"extern", SCSPEC, RID_EXTERN }, {"__const", TYPE_QUAL, RID_CONST }, {"while", WHILE, NORID }, {"__const__", TYPE_QUAL, RID_CONST }, {"switch", SWITCH, NORID }, {"for", FOR, NORID }, {"inline", SCSPEC, RID_INLINE }, {"return", RETURN, NORID }, {"typeof", TYPEOF, NORID }, {"typedef", SCSPEC, RID_TYPEDEF }, {"char", TYPESPEC, RID_CHAR }, {"enum", ENUM, NORID }, {"register", SCSPEC, RID_REGISTER }, {"signed", TYPESPEC, RID_SIGNED }, {"sizeof", SIZEOF, NORID }, { "", }, { "", }, { "", }, { "", }, {"double", TYPESPEC, RID_DOUBLE }, {"static", SCSPEC, RID_STATIC }, {"case", CASE, NORID }, { "", }, { "", }, { "", }, { "", }, {"const", TYPE_QUAL, RID_CONST }, { "", }, { "", }, { "", }, {"long", TYPESPEC, RID_LONG }, { "", }, { "", }, {"continue", CONTINUE, NORID }, { "", }, { "", }, {"unsigned", TYPESPEC, RID_UNSIGNED }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, {"union", UNION, NORID }, }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { register int key = hash (str, len); if (key <= MAX_HASH_VALUE) { register char *s = reswords[key].name; if (*s == *str && !strcmp (str + 1, s + 1)) return &reswords[key]; } } return 0;}/* The elements of `ridpointers' are identifier nodes for the reserved type names and storage classes. It is indexed by a RID_... value. */tree ridpointers[(int) RID_MAX];int check_newline ();voidinit_lex (){ /* Start it at 0, because check_newline is called at the very beginning and will increment it to 1. */ lineno = 0; maxtoken = 40; token_buffer = (char *) xmalloc (maxtoken + 2); max_wide = 40; wide_buffer = (int *) xmalloc ((max_wide + 1) * UNITS_PER_WORD); ridpointers[(int) RID_INT] = get_identifier ("int"); ridpointers[(int) RID_CHAR] = get_identifier ("char"); ridpointers[(int) RID_VOID] = get_identifier ("void"); ridpointers[(int) RID_FLOAT] = get_identifier ("float"); ridpointers[(int) RID_DOUBLE] = get_identifier ("double"); ridpointers[(int) RID_SHORT] = get_identifier ("short"); ridpointers[(int) RID_LONG] = get_identifier ("long"); ridpointers[(int) RID_UNSIGNED] = get_identifier ("unsigned"); ridpointers[(int) RID_SIGNED] = get_identifier ("signed"); ridpointers[(int) RID_INLINE] = get_identifier ("inline"); ridpointers[(int) RID_CONST] = get_identifier ("const"); ridpointers[(int) RID_VOLATILE] = get_identifier ("volatile"); ridpointers[(int) RID_AUTO] = get_identifier ("auto"); ridpointers[(int) RID_STATIC] = get_identifier ("static"); ridpointers[(int) RID_EXTERN] = get_identifier ("extern"); ridpointers[(int) RID_TYPEDEF] = get_identifier ("typedef"); ridpointers[(int) RID_REGISTER] = get_identifier ("register");}static voidreinit_parse_for_function (){}/* If C is not whitespace, return C. Otherwise skip whitespace and return first nonwhite char read. */static intskip_white_space (c) register int c;{#if 0 register int inside;#endif for (;;) { switch (c) { /* Don't recognize comments in cc1: all comments are removed by cpp, and cpp output can include / and * consecutively as operators. */#if 0 case '/': c = getc (finput); if (c != '*') { ungetc (c, finput); return '/'; } c = getc (finput); inside = 1; while (inside) { if (c == '*') { while (c == '*') c = getc (finput); if (c == '/') { inside = 0; c = getc (finput); } } else if (c == '\n') { lineno++; c = getc (finput); } else if (c == EOF) { error ("unterminated comment"); break; } else c = getc (finput); } break;#endif case '\n': c = check_newline (); break; case ' ': case '\t': case '\f': case '\r': case '\v': case '\b': c = getc (finput); break; case '\\': c = getc (finput); if (c == '\n') lineno++; else error ("stray '\\' in program"); c = getc (finput); break; default: return (c); } }}/* Make the token buffer longer, preserving the data in it. P should point to just beyond the last valid character in the old buffer. The value we return is a pointer to the new buffer at a place corresponding to P. */static char *extend_token_buffer (p) char *p;{ int offset = p - token_buffer; maxtoken = maxtoken * 2 + 10; token_buffer = (char *) xrealloc (token_buffer, maxtoken + 2); return token_buffer + offset;}/* At the beginning of a line, increment the line number and process any #-directive on this line. If the line is a #-directive, read the entire line and return a newline. Otherwise, return the line's first non-whitespace character. */intcheck_newline (){ register int c; register int token; lineno++; /* Read first nonwhite char on the line. */ c = getc (finput); while (c == ' ' || c == '\t') c = getc (finput); if (c != '#') { /* If not #, return it so caller will use it. */ return c; } /* Read first nonwhite char after the `#'. */ c = getc (finput); while (c == ' ' || c == '\t') c = getc (finput); /* If a letter follows, then if the word here is `line', skip it and ignore it; otherwise, ignore the line, with an error if the word isn't `pragma'. */ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { if (c == 'p') { if (getc (finput) == 'r' && getc (finput) == 'a' && getc (finput) == 'g' && getc (finput) == 'm' && getc (finput) == 'a' && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n')) goto skipline; } else if (c == 'l') { if (getc (finput) == 'i' && getc (finput) == 'n' && getc (finput) == 'e' && ((c = getc (finput)) == ' ' || c == '\t')) goto linenum; } else if (c == 'i') { if (getc (finput) == 'd' && getc (finput) == 'e' && getc (finput) == 'n' && getc (finput) == 't' && ((c = getc (finput)) == ' ' || c == '\t')) { extern FILE *asm_out_file; if (pedantic) error ("ANSI C does not allow #ident"); /* Here we have just seen `#ident '. A string constant should follow. */ while (c == ' ' || c == '\t') c = getc (finput); /* If no argument, ignore the line. */ if (c == '\n') return c; ungetc (c, finput); token = yylex (); if (nextchar >= 0) ungetc (nextchar, finput), nextchar = -1; if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST) { error ("invalid #ident"); goto skipline; }#ifdef ASM_OUTPUT_IDENT ASM_OUTPUT_IDENT (asm_out_file, TREE_STRING_POINTER (yylval.ttype));#endif /* Skip the rest of this line. */ goto skipline; } } error ("undefined or invalid # directive"); goto skipline; }linenum: /* Here we have either `#line' or `# <nonletter>'. In either case, it should be a line number; a digit should follow. */ while (c == ' ' || c == '\t') c = getc (finput); /* If the # is the only nonwhite char on the line, just ignore it. Check the new newline. */ if (c == '\n') return c; /* Something follows the #; read a token. */ ungetc (c, finput); token = yylex (); if (nextchar >= 0) ungetc (nextchar, finput), nextchar = -1; if (token == CONSTANT && TREE_CODE (yylval.ttype) == INTEGER_CST) { int old_lineno = lineno; /* subtract one, because it is the following line that gets the specified number */ int l = TREE_INT_CST_LOW (yylval.ttype) - 1; /* Is this the last nonwhite stuff on the line? */ c = getc (finput); while (c == ' ' || c == '\t') c = getc (finput); if (c == '\n') { /* No more: store the line number and check following line. */ lineno = l; return c; } ungetc (c, finput); /* More follows: it must be a string constant (filename). */ token = yylex (); if (nextchar >= 0) ungetc (nextchar, finput), nextchar = -1; if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST) { error ("invalid #line"); goto skipline; } input_filename = (char *) permalloc (TREE_STRING_LENGTH (yylval.ttype) + 1); strcpy (input_filename, TREE_STRING_POINTER (yylval.ttype)); lineno = l; if (main_input_filename == 0) main_input_filename = input_filename; /* Is this the last nonwhite stuff on the line? */ c = getc (finput); while (c == ' ' || c == '\t') c = getc (finput); if (c == '\n') return c; ungetc (c, finput); token = yylex (); if (nextchar >= 0) ungetc (nextchar, finput), nextchar = -1; /* `1' after file name means entering new file. `2' after file name means just left a file. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -