📄 c-parse.y
字号:
| save_filename save_lineno label lineno_labeled_stmt { } ;lineno_stmt_or_label: save_filename save_lineno stmt_or_label { } ;stmt_or_label: stmt | label { int next; position_after_white_space (); next = getc (finput); ungetc (next, finput); if (pedantic && next == '}') pedwarn ("ANSI C forbids label at end of compound statement"); } ;/* Parse a single real statement, not including any labels. */stmt: compstmt { stmt_count++; } | expr ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); c_expand_expr_stmt ($1); clear_momentary (); } | simple_if ELSE { expand_start_else (); $<itype>1 = stmt_count; position_after_white_space (); } lineno_labeled_stmt { expand_end_cond (); if (extra_warnings && stmt_count == $<itype>1) warning ("empty body in an else-statement"); } | simple_if %prec IF { expand_end_cond (); if (extra_warnings && stmt_count == $<itype>1) warning_with_file_and_line (if_stmt_file, if_stmt_line, "empty body in an if-statement"); }/* Make sure expand_end_cond is run once for each call to expand_start_cond. Otherwise a crash is likely. */ | simple_if ELSE error { expand_end_cond (); } | WHILE { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); /* The emit_nop used to come before emit_line_note, but that made the nop seem like part of the preceding line. And that was confusing when the preceding line was inside of an if statement and was not really executed. I think it ought to work to put the nop after the line number. We will see. --rms, July 15, 1991. */ emit_nop (); expand_start_loop (1); } '(' expr ')' { emit_line_note (input_filename, lineno); expand_exit_loop_if_false (0, truthvalue_conversion ($4)); position_after_white_space (); } lineno_labeled_stmt { expand_end_loop (); } | DO { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); /* See comment in `while' alternative, above. */ emit_nop (); expand_start_loop_continue_elsewhere (1); position_after_white_space (); } lineno_labeled_stmt WHILE { expand_loop_continue_here (); } '(' expr ')' ';' { emit_line_note (input_filename, lineno); expand_exit_loop_if_false (0, truthvalue_conversion ($7)); expand_end_loop (); clear_momentary (); } | FOR '(' xexpr ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); /* See comment in `while' alternative, above. */ emit_nop (); if ($3) c_expand_expr_stmt ($3); expand_start_loop_continue_elsewhere (1); } xexpr ';' { emit_line_note (input_filename, lineno); if ($6) expand_exit_loop_if_false (0, 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 (); position_after_white_space (); } lineno_labeled_stmt { emit_line_note ($<filename>-1, $<lineno>0); expand_loop_continue_here (); if ($9) c_expand_expr_stmt ($9); pop_momentary (); expand_end_loop (); } | SWITCH '(' expr ')' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); 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 (); position_after_white_space (); } lineno_labeled_stmt { expand_end_case ($3); pop_momentary (); } | BREAK ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); if ( ! expand_exit_something ()) error ("break statement not within loop or switch"); } | CONTINUE ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); if (! expand_continue_loop (0)) error ("continue statement not within a loop"); } | RETURN ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); c_expand_return (NULL_TREE); } | RETURN expr ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); c_expand_return ($2); } | ASM maybe_type_qual '(' expr ')' ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); STRIP_NOPS ($4); if ((TREE_CODE ($4) == ADDR_EXPR && TREE_CODE (TREE_OPERAND ($4, 0)) == STRING_CST) || TREE_CODE ($4) == STRING_CST) expand_asm ($4); else error ("argument of `asm' is not a constant string"); } /* This is the case with just output operands. */ | ASM maybe_type_qual '(' expr ':' asm_operands ')' ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); 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 '(' expr ':' asm_operands ':' asm_operands ')' ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); 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 '(' expr ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); c_expand_asm_operands ($4, $6, $8, $10, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); } | GOTO identifier ';' { tree decl; stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); decl = lookup_label ($2); if (decl != 0) { TREE_USED (decl) = 1; expand_goto (decl); } } | GOTO '*' expr ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); expand_computed_goto ($3); } | ';' ;/* Any kind of label, including jump labels and case labels. ANSI C accepts labels only before statements, but we allow them also at the end of a compound statement. */label: CASE expr ':' { register tree value = check_case_value ($2); register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); stmt_count++; if (value != error_mark_node) { tree duplicate; int success = pushcase (value, label, &duplicate); if (success == 1) error ("case label not within a switch statement"); else if (success == 2) { error ("duplicate case value"); error_with_decl (duplicate, "this is the first entry for that value"); } else if (success == 3) warning ("case value out of range"); else if (success == 5) error ("case label within scope of cleanup or variable array"); } position_after_white_space (); } | CASE expr ELLIPSIS expr ':' { register tree value1 = check_case_value ($2); register tree value2 = check_case_value ($4); register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); stmt_count++; if (value1 != error_mark_node && value2 != error_mark_node) { tree duplicate; int success = pushcase_range (value1, value2, label, &duplicate); if (success == 1) error ("case label not within a switch statement"); else if (success == 2) { error ("duplicate case value"); error_with_decl (duplicate, "this is the first entry for that value"); } else if (success == 3) warning ("case value out of range"); else if (success == 4) warning ("empty case range"); else if (success == 5) error ("case label within scope of cleanup or variable array"); } position_after_white_space (); } | DEFAULT ':' { tree duplicate; register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); int success = pushcase (NULL_TREE, label, &duplicate); stmt_count++; if (success == 1) error ("default label not within a switch statement"); else if (success == 2) { error ("multiple default labels in one switch"); error_with_decl (duplicate, "this is the first default label"); } position_after_white_space (); } | identifier ':' { tree label = define_label (input_filename, lineno, $1); stmt_count++; emit_nop (); if (label) expand_label (label); position_after_white_space (); } ;/* 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); clear_parm_order (); declare_parm_level (0); } parmlist_1 { $$ = $2; parmlist_tags_warning (); poplevel (0, 0, 0); } ;parmlist_1: parmlist_2 ')' | parms ';' { tree parm; /* Mark the forward decls as such. */ for (parm = getdecls (); parm; parm = TREE_CHAIN (parm)) TREE_ASM_WRITTEN (parm) = 1; clear_parm_order (); } parmlist_1 { $$ = $4; } | 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); } | ELLIPSIS { $$ = get_parm_info (0); if (pedantic) pedwarn ("ANSI C requires a named argument before `...'"); } | 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); } ;/* This is used in a function definition 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); clear_parm_order (); declare_parm_level (1); } parmlist_or_identifiers_1 { $$ = $2; parmlist_tags_warning (); poplevel (0, 0, 0); } ;parmlist_or_identifiers_1: parmlist_2 ')' | parms ';' { tree parm; /* Mark the forward decls as such. */ for (parm = getdecls (); parm; parm = TREE_CHAIN (parm)) TREE_ASM_WRITTEN (parm) = 1; clear_parm_order (); } parmlist_or_identifiers_1 { $$ = $4; } | identifiers ')' { tree t; for (t = $1; t; t = TREE_CHAIN (t)) if (TREE_VALUE (t) == NULL_TREE) error ("`...' in old-style identifier list"); $$ = tree_cons (NULL_TREE, NULL_TREE, $1); } | error ')' { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); } ;/* A nonempty list of identifiers. */identifiers: IDENTIFIER { $$ = build_tree_list (NULL_TREE, $1); } | identifiers ',' IDENTIFIER { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } ;/* A nonempty list of identifiers, including typenames. */identifiers_or_typenames: identifier { $$ = build_tree_list (NULL_TREE, $1); } | identifiers_or_typenames ',' identifier { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } ;%%
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -