📄 c-parse.y
字号:
| stmts ;errstmt: error ';' ;pushlevel: /* empty */ { pushlevel (0); clear_last_expr (); push_momentary (); expand_start_bindings (0); } ;/* This is the body of a function definition. It causes syntax errors to ignore to the next openbrace. */compstmt_or_error: compstmt {} | error compstmt ;compstmt: '{' '}' { $$ = 0; } | '{' pushlevel decls xstmts '}' { expand_end_bindings (getdecls (), 1, 0); $$ = poplevel (1, 1, 0); pop_momentary (); } | '{' pushlevel error '}' { expand_end_bindings (getdecls (), kept_level_p (), 0); $$ = poplevel (kept_level_p (), 0, 0); pop_momentary (); } | '{' pushlevel stmts '}' { expand_end_bindings (getdecls (), kept_level_p (), 0); $$ = poplevel (kept_level_p (), 0, 0); pop_momentary (); } ;simple_if: IF '(' expr ')' { emit_line_note (input_filename, lineno); expand_start_cond (truthvalue_conversion ($3), 0); } stmt ;stmt: compstmt {} | expr ';' { emit_line_note (input_filename, lineno); /* Do default conversion if safe and possibly important, in case within ({...}). */ if ((TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE && lvalue_p ($1)) || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE) $1 = default_conversion ($1); expand_expr_stmt ($1); clear_momentary (); } | simple_if ELSE { expand_start_else (); } stmt { expand_end_else (); } | simple_if %prec IF { expand_end_cond (); } | WHILE { emit_nop (); emit_line_note (input_filename, lineno); expand_start_loop (1); } '(' expr ')' { emit_line_note (input_filename, lineno); expand_exit_loop_if_false (truthvalue_conversion ($4)); } stmt { expand_end_loop (); } | DO { emit_nop (); emit_line_note (input_filename, lineno); expand_start_loop_continue_elsewhere (1); } stmt WHILE { expand_loop_continue_here (); } '(' expr ')' ';' { emit_line_note (input_filename, lineno); expand_exit_loop_if_false (truthvalue_conversion ($7)); expand_end_loop (); clear_momentary (); } | FOR '(' xexpr ';' { emit_nop (); emit_line_note (input_filename, lineno); if ($3) expand_expr_stmt ($3); expand_start_loop_continue_elsewhere (1); } xexpr ';' { emit_line_note (input_filename, lineno); if ($6) expand_exit_loop_if_false (truthvalue_conversion ($6)); } xexpr ')' /* Don't let the tree nodes for $9 be discarded by clear_momentary during the parsing of the next stmt. */ { push_momentary (); $<itype>10 = lineno; } stmt { emit_line_note (input_filename, $<itype>10); expand_loop_continue_here (); if ($9) expand_expr_stmt ($9); pop_momentary (); expand_end_loop (); } | SWITCH '(' expr ')' { emit_line_note (input_filename, lineno); c_expand_start_case ($3); /* Don't let the tree nodes for $3 be discarded by clear_momentary during the parsing of the next stmt. */ push_momentary (); } stmt { expand_end_case ($3); pop_momentary (); } | CASE expr ':' { register tree value = fold ($2); register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); /* build_c_cast puts on a NOP_EXPR to make a non-lvalue. Strip such NOP_EXPRs. */ if (TREE_CODE (value) == NOP_EXPR && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0))) value = TREE_OPERAND (value, 0); if (TREE_CODE (value) != INTEGER_CST && value != error_mark_node) { error ("case label does not reduce to an integer constant"); value = error_mark_node; } else /* Promote char or short to int. */ value = default_conversion (value); if (value != error_mark_node) { int success = pushcase (value, label); if (success == 1) error ("case label not within a switch statement"); else if (success == 2) error ("duplicate case value"); else if (success == 3) warning ("case value out of range"); } } stmt | DEFAULT ':' { register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); int success = pushcase (NULL_TREE, label); if (success == 1) error ("default label not within a switch statement"); else if (success == 2) error ("multiple default labels in one switch"); } stmt | BREAK ';' { emit_line_note (input_filename, lineno); if ( ! expand_exit_something ()) error ("break statement not within loop or switch"); } | CONTINUE ';' { emit_line_note (input_filename, lineno); if (! expand_continue_loop ()) error ("continue statement not within a loop"); } | RETURN ';' { emit_line_note (input_filename, lineno); c_expand_return (NULL_TREE); } | RETURN expr ';' { emit_line_note (input_filename, lineno); c_expand_return ($2); } | ASM maybe_type_qual '(' string ')' ';' { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); emit_line_note (input_filename, lineno); expand_asm ($4); } /* This is the case with just output operands. */ | ASM maybe_type_qual '(' string ':' asm_operands ')' ';' { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); emit_line_note (input_filename, lineno); c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); } /* This is the case with input operands as well. */ | ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands ')' ';' { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); emit_line_note (input_filename, lineno); c_expand_asm_operands ($4, $6, $8, NULL_TREE, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); } /* This is the case with clobbered registers as well. */ | ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); emit_line_note (input_filename, lineno); c_expand_asm_operands ($4, $6, $8, $10, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); } | GOTO identifier ';' { tree decl; emit_line_note (input_filename, lineno); decl = lookup_label ($2); TREE_USED (decl) = 1; expand_goto (decl); } | identifier ':' { tree label = define_label (input_filename, lineno, $1); emit_nop (); if (label) expand_label (label); } stmt | ';' ;/* Either a type-qualifier or nothing. First thing in an `asm' statement. */maybe_type_qual: /* empty */ { emit_line_note (input_filename, lineno); } | TYPE_QUAL { emit_line_note (input_filename, lineno); } ;xexpr: /* empty */ { $$ = NULL_TREE; } | expr ;/* These are the operands other than the first string and colon in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */asm_operands: /* empty */ { $$ = NULL_TREE; } | nonnull_asm_operands ;nonnull_asm_operands: asm_operand | nonnull_asm_operands ',' asm_operand { $$ = chainon ($1, $3); } ;asm_operand: STRING '(' expr ')' { $$ = build_tree_list ($1, $3); } ;asm_clobbers: string { $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); } | asm_clobbers ',' string { $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); } ;/* This is what appears inside the parens in a function declarator. Its value is a list of ..._TYPE nodes. */parmlist: { pushlevel (0); declare_parm_level (); } parmlist_1 { $$ = $2; parmlist_tags_warning (); poplevel (0, 0, 0); } ;/* This is referred to where either a parmlist or an identifier list is ok. Its value is a list of ..._TYPE nodes or a list of identifiers. */parmlist_or_identifiers: { pushlevel (0); declare_parm_level (); } parmlist_or_identifiers_1 { $$ = $2; parmlist_tags_warning (); poplevel (0, 0, 0); } ;parmlist_or_identifiers_1: parmlist_2 ')' | identifiers ')' { $$ = tree_cons (NULL_TREE, NULL_TREE, $1); } | error ')' { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); } ;parmlist_1: parmlist_2 ')' | error ')' { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); } ;/* This is what appears inside the parens in a function declarator. Is value is represented in the format that grokdeclarator expects. */parmlist_2: /* empty */ { $$ = get_parm_info (0); } | parms { $$ = get_parm_info (1); } | parms ',' ELLIPSIS { $$ = get_parm_info (0); } ;parms: parm { push_parm_decl ($1); } | parms ',' parm { push_parm_decl ($3); } ;/* A single parameter declaration or parameter type name, as found in a parmlist. */parm: typed_declspecs parm_declarator { $$ = build_tree_list ($1, $2) ; } | typed_declspecs notype_declarator { $$ = build_tree_list ($1, $2) ; } | typed_declspecs absdcl { $$ = build_tree_list ($1, $2); } | declmods notype_declarator { $$ = build_tree_list ($1, $2) ; } | declmods absdcl { $$ = build_tree_list ($1, $2); } ;/* A nonempty list of identifiers. */identifiers: IDENTIFIER { $$ = build_tree_list (NULL_TREE, $1); } | identifiers ',' IDENTIFIER { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } ;%%/* Return something to represent absolute declarators containing a *. TARGET is the absolute declarator that the * contains. TYPE_QUALS is a list of modifiers such as const or volatile to apply to the pointer type, represented as identifiers. We return an INDIRECT_REF whose "contents" are TARGET and whose type is the modifier list. */static treemake_pointer_declarator (type_quals, target) tree type_quals, target;{ return build (INDIRECT_REF, type_quals, target);}/* Given a chain of STRING_CST nodes, concatenate them into one STRING_CST and give it a suitable array-of-chars data type. */static treecombine_strings (strings) tree strings;{ register tree value, t; register int length = 1; int wide_length = 0; int wide_flag = 0; int nchars; if (TREE_CHAIN (strings)) { /* More than one in the chain, so concatenate. */ register char *p, *q; /* Don't include the \0 at the end of each substring, except for the last one. Count wide strings and ordinary strings separately. */ for (t = strings; t; t = TREE_CHAIN (t)) { if (TREE_TYPE (t) == int_array_type_node) { wide_length += (TREE_STRING_LENGTH (t) - UNITS_PER_WORD); wide_flag = 1; } else length += (TREE_STRING_LENGTH (t) - 1); } /* If anything is wide, the non-wides will be converted, which makes them take more space. */ if (wide_flag) length = length * UNITS_PER_WORD + wide_length; p = (char *) savealloc (length); /* Copy the individual strings into the new combined string. If the combined string is wide, convert the chars to ints for any individual strings that are not wide. */ q = p; for (t = strings; t; t = TREE_CHAIN (t)) { int len = (TREE_STRING_LENGTH (t) - ((TREE_TYPE (t) == int_array_type_node) ? UNITS_PER_WORD : 1)); if ((TREE_TYPE (t) == int_array_type_node) == wide_flag) { bcopy (TREE_STRING_POINTER (t), q, len); q += len; } else { int i; for (i = 0; i < len; i++) ((int *) q)[i] = TREE_STRING_POINTER (t)[i]; q += len * UNITS_PER_WORD; } } if (wide_flag) { int i; for (i = 0; i < UNITS_PER_WORD; i++) *q++ = 0; } else *q = 0; value = make_node (STRING_CST); TREE_STRING_POINTER (value) = p; TREE_STRING_LENGTH (value) = length; TREE_LITERAL (value) = 1; } else { value = strings; length = TREE_STRING_LENGTH (value); if (TREE_TYPE (value) == int_array_type_node) wide_flag = 1; } /* Compute the number of elements, for the array type. */ nchars = wide_flag ? length / UNITS_PER_WORD : length; /* Create the array type for the string constant. -Wwrite-strings says make the string constant an array of const char so that copying it to a non-const pointer will get a warning. */ if (warn_write_strings) { tree elements = build_type_variant (wide_flag ? integer_type_node : char_type_node, 1, 0); TREE_TYPE (value) = build_array_type (elements, build_index_type (build_int_2 (nchars - 1, 0))); } else TREE_TYPE (value) = build_array_type (wide_flag ? integer_type_node : char_type_node, build_index_type (build_int_2 (nchars - 1, 0))); TREE_LITERAL (value) = 1; TREE_STATIC (value) = 1; return value;}FILE *finput; /* input file. Normally a pipe from the preprocessor. *//* lexical analyzer */static int maxtoken; /* Current nominal length of token buffer. */static char *token_buffer; /* Pointer to token buffer. Actual allocated length is maxtoken + 2. */static int max_wide; /* Current nominal length of wide_buffer. */static int *wide_buffer; /* Pointer to wide-string buffer. Actual allocated length is max_wide + 1. *//* Nonzero if end-of-file has been seen on input. */static int end_of_file;/* Buffered character to reread. I'm not sure why ungetc is not used. */static int nextchar = -1;/* Data type that represents the GNU C reserved words. */struct resword { char *name; short token; enum rid rid; };#define MIN_WORD_LENGTH 2 /* minimum size for C keyword */#define MAX_WORD_LENGTH 13 /* maximum size for C keyword */#define MIN_HASH_VALUE 7 /* range of the hash keys values */#define MAX_HASH_VALUE 91 /* for the perfect hash generator */#define NORID RID_UNUSED/* This function performs the minimum-perfect hash mapping from input string to reswords table index. It only looks at the first and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -