📄 c-parse.in
字号:
{} | error compstmt ;compstmt_start: '{' { compstmt_count++; }compstmt: compstmt_start '}' { $$ = convert (void_type_node, integer_zero_node); } | compstmt_start pushlevel maybe_label_decls decls xstmts '}' { emit_line_note (input_filename, lineno); expand_end_bindings (getdecls (), 1, 0); $$ = poplevel (1, 1, 0); if (yychar == CONSTANT || yychar == STRING) pop_momentary_nofree (); else pop_momentary (); } | compstmt_start pushlevel maybe_label_decls error '}' { emit_line_note (input_filename, lineno); expand_end_bindings (getdecls (), kept_level_p (), 0); $$ = poplevel (kept_level_p (), 0, 0); if (yychar == CONSTANT || yychar == STRING) pop_momentary_nofree (); else pop_momentary (); } | compstmt_start pushlevel maybe_label_decls stmts '}' { emit_line_note (input_filename, lineno); expand_end_bindings (getdecls (), kept_level_p (), 0); $$ = poplevel (kept_level_p (), 0, 0); if (yychar == CONSTANT || yychar == STRING) pop_momentary_nofree (); else pop_momentary (); } ;/* Value is number of statements counted as of the closeparen. */simple_if: if_prefix lineno_labeled_stmt/* Make sure c_expand_end_cond is run once for each call to c_expand_start_cond. Otherwise a crash is likely. */ | if_prefix error ;if_prefix: IF '(' expr ')' { emit_line_note ($<filename>-1, $<lineno>0); c_expand_start_cond (truthvalue_conversion ($3), 0, compstmt_count); $<itype>$ = stmt_count; if_stmt_file = $<filename>-1; if_stmt_line = $<lineno>0; position_after_white_space (); } ;/* This is a subroutine of stmt. It is used twice, once for valid DO statements and once for catching errors in parsing the end test. */do_stmt_start: DO { stmt_count++; compstmt_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 (); } ;save_filename: { $$ = input_filename; } ;save_lineno: { $$ = lineno; } ;lineno_labeled_stmt: save_filename save_lineno stmt { }/* | save_filename save_lineno error { }*/ | save_filename save_lineno label lineno_labeled_stmt { } ;lineno_stmt_or_label: save_filename save_lineno stmt_or_label { $$ = $3; } ;stmt_or_label: stmt { $$ = 0; } | label { $$ = 1; } ;/* Parse a single real statement, not including any labels. */stmt: compstmt { stmt_count++; } | all_iter_stmt | expr ';' { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0);/* It appears that this should not be done--that a non-lvalue array shouldn't get an error if the value isn't used. Section 3.2.2.1 says that an array lvalue gets converted to a pointer if it appears as a top-level expression, but says nothing about non-lvalue arrays. */#if 0 /* Call default_conversion to get an error on referring to a register array if pedantic. */ if (TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE) $1 = default_conversion ($1);#endif iterator_expand ($1); clear_momentary (); } | simple_if ELSE { c_expand_start_else (); $<itype>1 = stmt_count; position_after_white_space (); } lineno_labeled_stmt { c_expand_end_cond (); if (extra_warnings && stmt_count == $<itype>1) warning ("empty body in an else-statement"); } | simple_if %prec IF { c_expand_end_cond (); /* This warning is here instead of in simple_if, because we do not want a warning if an empty if is followed by an else statement. Increment stmt_count so we don't give a second error if this is a nested `if'. */ 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 c_expand_end_cond is run once for each call to c_expand_start_cond. Otherwise a crash is likely. */ | simple_if ELSE error { c_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 (); } '(' expr ')' { /* Don't start the loop till we have succeeded in parsing the end test. This is to make sure that we end every loop we start. */ expand_start_loop (1); emit_line_note (input_filename, lineno); expand_exit_loop_if_false (NULL_PTR, truthvalue_conversion ($4)); position_after_white_space (); } lineno_labeled_stmt { expand_end_loop (); } | do_stmt_start '(' expr ')' ';' { emit_line_note (input_filename, lineno); expand_exit_loop_if_false (NULL_PTR, truthvalue_conversion ($3)); expand_end_loop (); clear_momentary (); }/* This rule is needed to make sure we end every loop we start. */ | do_stmt_start error { 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); /* Next step is to call expand_start_loop_continue_elsewhere, but wait till after we parse the entire for (...). Otherwise, invalid input might cause us to call that fn without calling expand_end_loop. */ } xexpr ';' /* Can't emit now; wait till after expand_start_loop... */ { $<lineno>7 = lineno; $<filename>$ = input_filename; } xexpr ')' { /* Start the loop. Doing this after parsing all the expressions ensures we will end the loop. */ expand_start_loop_continue_elsewhere (1); /* Emit the end-test, with a line number. */ emit_line_note ($<filename>8, $<lineno>7); if ($6) expand_exit_loop_if_false (NULL_PTR, truthvalue_conversion ($6)); /* Don't let the tree nodes for $9 be discarded by clear_momentary during the parsing of the next stmt. */ push_momentary (); $<lineno>7 = lineno; $<filename>8 = input_filename; position_after_white_space (); } lineno_labeled_stmt { /* Emit the increment expression, with a line number. */ emit_line_note ($<filename>8, $<lineno>7); expand_loop_continue_here (); if ($9) c_expand_expr_stmt ($9); if (yychar == CONSTANT || yychar == STRING) pop_momentary_nofree (); else 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); if (yychar == CONSTANT || yychar == STRING) pop_momentary_nofree (); else 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 (NULL_PTR)) 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_KEYWORD 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_KEYWORD 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_KEYWORD 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_KEYWORD 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 ';' { if (pedantic) pedwarn ("ANSI C forbids `goto *expr;'"); stmt_count++; emit_line_note ($<filename>-1, $<lineno>0); expand_computed_goto (convert (ptr_type_node, $3)); } | ';' ;all_iter_stmt: all_iter_stmt_simple/* | all_iter_stmt_with_decl */ ;all_iter_stmt_simple: FOR '(' primary ')' { /* The value returned by this action is */ /* 1 if everything is OK */ /* 0 in case of error or already bound iterator */ $<itype>$ = 0; if (TREE_CODE ($3) != VAR_DECL) error ("invalid `for (ITERATOR)' syntax"); else if (! ITERATOR_P ($3)) error ("`%s' is not an iterator", IDENTIFIER_POINTER (DECL_NAME ($3))); else if (ITERATOR_BOUND_P ($3)) error ("`for (%s)' inside expansion of same iterator", IDENTIFIER_POINTER (DECL_NAME ($3))); else { $<itype>$ = 1; iterator_for_loop_start ($3); } } lineno_labeled_stmt { if ($<itype>5) iterator_for_loop_end ($3); }/* This really should allow any kind of declaration, for generality. Fix it before turning it back on.all_iter_stmt_with_decl: FOR '(' ITERATOR pushlevel setspecs iterator_spec ')' {*/ /* The value returned by this action is */ /* 1 if everything is OK */ /* 0 in case of error or already bound iterator *//* iterator_for_loop_start ($6); } lineno_labeled_stmt { iterator_for_loop_end ($6); emit_line_note (input_filename, lineno); expand_end_bindings (getdecls (), 1, 0); $<ttype>$ = poplevel (1, 1, 0); if (yychar == CONSTANT || yychar == STRING) pop_momentary_nofree (); else pop_momentary (); }*//* 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_no_commas ':' { 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, convert_and_check, 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_no_commas ELLIPSIS expr_no_commas ':' { 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); if (pedantic) pedwarn ("ANSI C forbids case ranges"); stmt_count++; if (value1 != error_mark_node && value2 != error_mark_node) { tree duplicate; int success = pushcase_range (value1, value2, convert_and_check, 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, 0, 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -