📄 parse.c
字号:
return NULL_TREE; list_list = build_tree_list (NULL_TREE, list); while (check_token (COMMA)) { if (selectors != NULL_TREE) selectors = TREE_CHAIN (selectors); list = parse_case_label_list (selectors, 0); if (list == NULL_TREE) { error ("unrecognized case label list after ','"); return list_list; } list_list = tree_cons (NULL_TREE, list, list_list); } return nreverse (list_list);}static voidparse_single_dimension_case_action (selector) tree selector;{ int no_completeness_check = 0;/* The case label/action toggle. It is 0 initially, and when an action was last seen. It is 1 integer_zero_node when a label was last seen. */ int caseaction_flag = 0; if (! ignoring) { expand_exit_needed = 0; selector = check_case_selector (selector); expand_start_case (1, selector, TREE_TYPE (selector), "CASE statement"); push_momentary (); } for (;;) { tree label_spec = parse_case_label_specification (selector); if (label_spec != NULL_TREE) { expect (COLON, "missing ':' in case alternative"); if (! ignoring) { no_completeness_check |= chill_handle_single_dimension_case_label ( selector, label_spec, &expand_exit_needed, &caseaction_flag); } } else if (parse_action ()) { expand_exit_needed = 1; caseaction_flag = 0; } else break; } if (! ignoring) { if (expand_exit_needed || caseaction_flag == 1) expand_exit_something (); } if (check_token (ELSE)) { if (! ignoring) chill_handle_case_default (); parse_opt_actions (); if (! ignoring) { emit_line_note (input_filename, lineno); expand_exit_something (); } } else if (! ignoring && TREE_CODE (selector) != ERROR_MARK && ! no_completeness_check) check_missing_cases (TREE_TYPE (selector)); expect (ESAC, "missing 'ESAC' after 'CASE'"); if (! ignoring) { expand_end_case (selector); pop_momentary (); }}static voidparse_multi_dimension_case_action (selector) tree selector;{ struct rtx_def *begin_test_label = 0, *end_case_label = 0, *new_label; tree action_labels = NULL_TREE; tree tests = NULL_TREE; int save_lineno = lineno; char *save_filename = input_filename; /* We can't compute the range of an (ELSE) label until all of the CASE label specifications have been seen, however, the code for the actions between them is generated on the fly. We can still generate everything in one pass is we use the following form: Compile a CASE of the form case S1,...,Sn of (X11),...,(X1n): A1; ... (Xm1),...,(Xmn): Am; else Ae; esac; into: goto L0; L1: A1; goto L99; ... Lm: Am; goto L99; Le: Ae; goto L99; L0: T1 := s1; ...; Tn := Sn; if (T1 = X11 and ... and Tn = X1n) GOTO L1; ... if (T1 = Xm1 and ... and Tn = Xmn) GOTO Lm; GOTO Le; L99; */ if (! ignoring) { selector = check_case_selector_list (selector); begin_test_label = gen_label_rtx (); end_case_label = gen_label_rtx (); emit_jump (begin_test_label); } for (;;) { tree label_spec = parse_case_label_specification (selector); if (label_spec != NULL_TREE) { expect (COLON, "missing ':' in case alternative"); if (! ignoring) { tests = tree_cons (label_spec, NULL_TREE, tests); if (action_labels != NULL_TREE) emit_jump (end_case_label); new_label = gen_label_rtx (); emit_label (new_label); emit_line_note (input_filename, lineno); action_labels = tree_cons (NULL_TREE, NULL_TREE, action_labels); TREE_CST_RTL (action_labels) = new_label; } } else if (! parse_action ()) { if (action_labels != NULL_TREE) emit_jump (end_case_label); break; } } if (check_token (ELSE)) { if (! ignoring) { new_label = gen_label_rtx (); emit_label (new_label); emit_line_note (input_filename, lineno); action_labels = tree_cons (NULL_TREE, NULL_TREE, action_labels); TREE_CST_RTL (action_labels) = new_label; } parse_opt_actions (); if (! ignoring) emit_jump (end_case_label); } expect (ESAC, "missing 'ESAC' after 'CASE'"); if (! ignoring) { emit_label (begin_test_label); emit_line_note (save_filename, save_lineno); if (tests != NULL_TREE) { tree cond; tests = nreverse (tests); action_labels = nreverse (action_labels); compute_else_ranges (selector, tests); cond = build_multi_case_selector_expression (selector, TREE_PURPOSE (tests)); expand_start_cond (truthvalue_conversion (cond), label ? 1 : 0); emit_jump (TREE_CST_RTL (action_labels)); for (tests = TREE_CHAIN (tests), action_labels = TREE_CHAIN (action_labels); tests != NULL_TREE && action_labels != NULL_TREE; tests = TREE_CHAIN (tests), action_labels = TREE_CHAIN (action_labels)) { cond = build_multi_case_selector_expression (selector, TREE_PURPOSE (tests)); expand_start_elseif (truthvalue_conversion (cond)); emit_jump (TREE_CST_RTL (action_labels)); } if (action_labels != NULL_TREE) { expand_start_else (); emit_jump (TREE_CST_RTL (action_labels)); } expand_end_cond (); } emit_label (end_case_label); }}static voidparse_case_action (label) tree label;{ tree selector; int multi_dimension_case = 0; require (CASE); selector = parse_expr_list (); selector = nreverse (selector); expect (OF, "missing 'OF' after 'CASE'"); parse_range_list_clause (); PUSH_ACTION; if (label) pushlevel (1); if (! ignoring) { expand_exit_needed = 0; if (TREE_CODE (selector) == TREE_LIST) { if (TREE_CHAIN (selector) != NULL_TREE) multi_dimension_case = 1; else selector = TREE_VALUE (selector); } } /* We want to use the regular CASE support for the single dimension case. The multi dimension case requires different handling. Note that when "ignoring" is true we parse using the single dimension code. This is OK since it will still parse correctly. */ if (multi_dimension_case) parse_multi_dimension_case_action (selector); else parse_single_dimension_case_action (selector); if (label) { possibly_define_exit_label (label); poplevel (0, 0, 0); }}/* Matches: [ <asm_operand> { "," <asm_operand> }* ], where <asm_operand> = STRING '(' <expression> ')' These are the operands other than the first string and colon in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */static treeparse_asm_operands (){ tree list = NULL_TREE; if (PEEK_TOKEN () != STRING) return NULL_TREE; for (;;) { tree string, expr; if (PEEK_TOKEN () != STRING) { error ("bad ASM operand"); return list; } string = PEEK_TREE(); FORWARD_TOKEN (); expect (LPRN, "missing '(' in ASM operand"); expr = parse_expression (); expect (RPRN, "missing ')' in ASM operand"); list = tree_cons (string, expr, list); if (! check_token (COMMA)) break; } return nreverse (list);}/* Matches: STRING { ',' STRING }* */static treeparse_asm_clobbers (){ tree list = NULL_TREE; for (;;) { tree string; if (PEEK_TOKEN () != STRING) { error ("bad ASM operand"); return list; } string = PEEK_TREE(); FORWARD_TOKEN (); list = tree_cons (NULL_TREE, string, list); if (! check_token (COMMA)) break; } return list;}voidch_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) tree string, outputs, inputs, clobbers; int vol; char *filename; int line;{ int noutputs = list_length (outputs); register int i; /* o[I] is the place that output number I should be written. */ register tree *o = (tree *) alloca (noutputs * sizeof (tree)); register tree tail; if (TREE_CODE (string) == ADDR_EXPR) string = TREE_OPERAND (string, 0); if (TREE_CODE (string) != STRING_CST) { error ("asm template is not a string constant"); return; } /* Record the contents of OUTPUTS before it is modified. */ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) o[i] = TREE_VALUE (tail);#if 0 /* Perform default conversions on array and function inputs. */ /* Don't do this for other types-- it would screw up operands expected to be in memory. */ for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++) if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE) TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));#endif /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of OUTPUTS some trees for where the values were actually stored. */ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line); /* Copy all the intermediate outputs into the specified outputs. */ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) { if (o[i] != TREE_VALUE (tail)) { expand_expr (build_chill_modify_expr (o[i], TREE_VALUE (tail)), 0, VOIDmode, 0); free_temp_slots (); } /* Detect modification of read-only values. (Otherwise done by build_modify_expr.) */ else { tree type = TREE_TYPE (o[i]); if (TYPE_READONLY (type) || ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE) && TYPE_FIELDS_READONLY (type))) warning ("readonly location modified by 'asm'"); } } /* Those MODIFY_EXPRs could do autoincrements. */ emit_queue ();}static voidparse_asm_action (){ tree insn; require (ASM_KEYWORD); expect (LPRN, "missing '('"); PUSH_ACTION; if (!ignoring) emit_line_note (input_filename, lineno); insn = parse_expression (); if (check_token (COLON)) { tree output_operand, input_operand, clobbered_regs; output_operand = parse_asm_operands (); if (check_token (COLON)) input_operand = parse_asm_operands (); else input_operand = NULL_TREE; if (check_token (COLON)) clobbered_regs = parse_asm_clobbers (); else clobbered_regs = NULL_TREE; expect (RPRN, "missing ')'"); if (!ignoring) ch_expand_asm_operands (insn, output_operand, input_operand, clobbered_regs, FALSE, input_filename, lineno); } else { expect (RPRN, "missing ')'"); STRIP_NOPS (insn); if (ignoring) { } else if ((TREE_CODE (insn) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (insn, 0)) == STRING_CST) || TREE_CODE (insn) == STRING_CST) expand_asm (insn); else error ("argument of `asm' is not a constant string"); }}static voidparse_begin_end_block (label) tree label;{ require (BEGINTOKEN);#if 0 /* don't make a linenote at BEGIN */ INIT_ACTION;#endif pushlevel (1); if (! ignoring) { clear_last_expr (); push_momentary (); expand_start_bindings (label ? 1 : 0); } push_handler (); parse_body (); expect (END, "missing 'END'"); /* Note that the opthandler comes before the poplevel - hence a handler is in the scope of the block. */ parse_opt_handler (); possibly_define_exit_label (label); if (! ignoring) { emit_line_note (input_filename, lineno); expand_end_bindings (getdecls (), kept_level_p (), 0); } poplevel (kept_level_p (), 0, 0); if (! ignoring) pop_momentary (); parse_opt_end_label_semi_colon (label);}static voidparse_if_action (label) tree label;{ tree cond; require (IF); PUSH_ACTION; cond = parse_expression (); if (label) pushlevel (1); if (! ignoring) { expand_start_cond (truthvalue_conversion (cond), label ? 1 : 0); } parse_then_clause (); parse_opt_else_clause (); expect (FI, "expected 'FI' after 'IF'"); if (! ignoring) { emit_line_note (input_filename, lineno); expand_end_cond (); } if (label) { possibly_define_exit_label (label); poplevel (0, 0, 0); }}/* Matches: <iteration> (as in a <for control>). */static voidparse_iteration (){ tree loop_counter = parse_defining_occurrence (); if (check_token (ASGN)) { tree start_value = parse_expression (); tree step_value = check_token (BY) ? parse_expression () : NULL_TREE; int going_down = check_token (DOWN); tree end_value; if (check_token (TO)) end_value = parse_expression (); else { error ("expected 'TO' in step enumeration"); end_value = error_mark_node; } if (!ignoring) build_loop_iterator (loop_counter, start_value, step_value, end_value, going_down, 0, 0); } else { int going_down = check_token (DOWN); tree expr; if (check_token (IN)) expr = parse_expression (); else { error ("expected 'IN' in FOR control here"); expr = error_mark_node; } if (!ignoring) { tree low_bound, high_bound; if (expr && TREE_CODE (expr) == TYPE_DECL) { expr = TREE_TYPE (expr); /* FIXME: expr must be an array or powerset */ low_bound = convert (expr, TYPE_MIN_VALUE (expr)); high_bound = convert (expr, TYPE_MAX_VALUE (expr)); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -