📄 gram.y
字号:
Indicate at the end of a compound, high-level statement, then fire the end-of-statement trigger. */ int_stm.is_comp = int_stm.is_high = int_stm.end = TRUE; int_stm.depth = depth; fire_stm(); ZERO(int_stm); } | expression_statement | selection_statement { ++int_fcn.high; /* High-level statement. */ /* Used to consider adjacent case labels as one decision point. */ not_case_label(); /* Indicate at the end of a selection, high-level statement, then fire the end-of-statement trigger. */ int_stm.is_select = int_stm.is_high = int_stm.end = TRUE; int_stm.depth = depth; fire_stm(); ZERO(int_stm); } | iteration_statement { ++int_fcn.high; /* High-level statement. */ /* Used to consider adjacent case labels as one decision point. */ not_case_label(); /* Indicate at the end of an iteration, high-level statement, then fire the end-of-statement trigger. */ int_stm.is_iter = int_stm.is_high = int_stm.end = TRUE; int_stm.depth = depth; fire_stm(); ZERO(int_stm); } | jump_statement { check_multiple_statements(); ++int_fcn.low; /* Low-level statement. */ /* Used to consider adjacent case labels as one decision point. */ not_case_label(); /* Indicate at the end of a jump, low-level statement, then fire the end-of-statement trigger. */ int_stm.is_jump = int_stm.is_low = int_stm.end = TRUE; int_stm.depth = depth; fire_stm(); ZERO(int_stm); } ;labeled_statement : identifier tk_colon { /* Indicate a label (target of a goto) and the depth at which it occurs. */ int_stm.is_label = TRUE; int_stm.depth = depth; fire_stm(); ZERO(int_stm); } statement { is_else = is_if = FALSE; } | tk_case constant_expr tk_colon { check_multiple_statements(); /* Used to consider adjacent case labels as one decision point. */ case_label(); /* Each case counts as a condition, but not necessarily a decision point. This is because adjacent cases count as one decision point, but each of those cases count as a distinct condition. */ ++fcn_conditions; } statement | tk_default tk_colon { check_multiple_statements(); } statement ;compound_statement : compound_intro { after_compound_declarations(); } tk_rcurly_brace | compound_intro { after_compound_declarations(); } statement_list tk_rcurly_brace | compound_intro declaration_list { after_compound_declarations(); } tk_rcurly_brace | compound_intro declaration_list { after_compound_declarations(); } statement_list tk_rcurly_brace ;compound_intro : tk_lcurly_brace { before_compound_declarations(); } ;declaration_list : declaration | declaration_list declaration ;statement_list : statement | statement_list statement ;expression_statement : tk_semicolon { found_expression_statement(TRUE); } | expr tk_semicolon { found_expression_statement(FALSE); } ;selection_statement : tk_if tk_lparen expr tk_rparen { is_if = TRUE; check_multiple_statements(); ++depth; /* Increase control depth. */ /* This is a decision point and a condition. */ ++fcn_decisions; ++fcn_conditions; } statement { --depth; /* Decrease control depth. */ } opt_else | tk_switch tk_lparen expr tk_rparen { check_multiple_statements(); ++depth; /* Increase control depth. */ } statement { --depth; /* Decrease control depth. */ } ;opt_else : %prec THEN | tk_else { check_multiple_statements(); is_else = TRUE; /* Must be after check_...() */ ++depth; /* Increase control depth. */ } statement { --depth; /* Decrease control depth. */ } ;iteration_statement : tk_while tk_lparen expr tk_rparen { check_multiple_statements(); ++depth; /* Increase control depth. */ /* This is a decision point and a condition. */ ++fcn_decisions; ++fcn_conditions; } statement { --depth; /* Decrease control depth. */ } | tk_do { ++depth; /* Increase control depth. */ /* This is a decision point and a condition. */ ++fcn_decisions; ++fcn_conditions; } statement { --depth; /* Decrease control depth. */ } tk_while tk_lparen expr tk_rparen tk_semicolon { check_multiple_statements(); } | tk_for tk_lparen opt_expr tk_semicolon tk_semicolon opt_expr tk_rparen { check_multiple_statements(); ++depth; /* Increase control depth. */ /* NOTE: This for statement does not contain a decision point or a condition. */ } statement { --depth; /* Decrease control depth. */ } | tk_for tk_lparen opt_expr tk_semicolon expr tk_semicolon opt_expr tk_rparen { check_multiple_statements(); ++depth; /* Increase control depth. */ /* This is a decision point and a condition. */ ++fcn_decisions; ++fcn_conditions; } statement { --depth; /* Decrease control depth. */ } ;opt_expr : | expr ;jump_statement : tk_goto identifier tk_semicolon | tk_continue tk_semicolon | tk_break tk_semicolon | tk_return opt_expr tk_semicolon ;/* Standard C requires there to be one or more external declarations in a translation unit. However, header files often contain preprocessor directives but no external declarations. So that header files can be parsed independent of any source files that may include them, Metre makes external declarations optional in a translation unit.*/translation_unit : | body ;body : external_declaration | body external_declaration ;external_declaration : function_definition { stat_func_end(); } | declaration ;function_definition : declarator { stat_func_begin(); } function_body | declaration_specifiers declarator { stat_func_begin(); } function_body ;function_body : compound_statement | declaration_list compound_statement ;%%/* Functions. */int main(int main_argc, char *main_argv[]){ ZERO(grm); ZERO(int_grm); /* Input not determined yet. */ yyin = NULL; /* Use stdout until/if output is redirected with command-line option. */ out_fp = stdout; /* Fire the need-command-name trigger. */ ZERO(int_prj); int_prj.need_cmd_name = TRUE; fire_prj(); int_prj.need_cmd_name = FALSE; print_banner(); /* Save so that the argument list may be accessed globally. */ cmd_line_argv = main_argv; cmd_line_argc = main_argc; /* Get command-line options that affect Metre at the start. */ check_starting_options(); /* Initialize YACC and Lex. */ init_yacc(); init_lex(); if (option(HELP_OPT_CHAR)) print_help(); else { /* Look for the first input file and first original name of that input file. */ next_cmd_line_file = 0; next_cmd_line_file_orig_n = 0; if ((input_file = get_next_input_file(&next_cmd_line_file)) != NULL) if ((yyin = fopen(input_file, "r")) != NULL) begin_project(input_file); else int_warn(W_CANNOT_OPEN_FILE, input_file); else /* Since no input file specified on command line, process stdin. */ begin_project("stdin"); } return RETURN_FROM_MAIN_VALUE;}/* Begin the project by firing initial triggers and calling parser. */static void begin_project(char *input_file){ input_file_orig_name = get_next_input_file_orig_name(&next_cmd_line_file_orig_n); /* If no original name given, use the actual as the original, also. */ if (input_file_orig_name == NULL) input_file_orig_name = input_file; /* Fire the beginning-of-project trigger. */ ZERO(int_prj); int_prj.begin = TRUE; fire_prj(); int_prj.begin = FALSE; /* Fire the beginning-of-module trigger. */ ZERO(int_mod); int_mod.begin = TRUE; fire_mod(); int_mod.begin = FALSE; /* Call the YACC-generated parser to wade through the input file(s). When all done, close the last input file. yywrap() could have opened any number of subsequent input files. */ yyparse(); fclose(yyin);}/* Common exception-handling function. */static void print_exception(int n, char *severity_str, char *format, va_list ap){ fflush(out_fp); /* Display input line if supposed to, then display line with marker character in it if appropriate. */ if (mod_name() != NULL && strlen(mod_name()) > 0 && !int_mod.end && !int_fcn.end) { if (!display_input) fputs(line(), out_fp); if (!int_lin.end) fputs(marker(), out_fp); } /* Display module name and line number if a module name has been established. If one hasn't, the error must not relate to a location in the input file. */ if (mod_name() != NULL && strlen(mod_name()) > 0) fprintf(out_fp, "%s(%u): ", mod_name(), lineno()); fprintf(out_fp, "%s%04u: ", severity_str, n); vfprintf(out_fp, format, ap); fputc('\n', out_fp);}/* Print message for internal fatal error. */void int_fatal(int n, char *format, ...){ va_list ap; va_start(ap, format); print_exception(n, "Fatal Error ME", format, ap); exit(1);}/* Print message for fatal error that occured in the rules() function. */void fatal(int n, char *format, ...){ va_list ap; va_start(ap, format); print_exception(n, "Fatal Error E", format, ap); exit(1);}/* Print message for internal warning. */static void int_warn(int n, char *format, ...){ va_list ap; if (!option(NO_WARNINGS_OPT_CHAR)) { va_start(ap, format); print_exception(n, "Warning MW", format, ap); }}/* Print message for warning that occured in the rules() function. */void warn(int n, char *format, ...){ va_list ap; if (!option(NO_WARNINGS_OPT_CHAR)) { va_start(ap, format); print_exception(n, "Warning W", format, ap); }}/* Function called by YACC when it detects an error. */void yyerror(char *s){#ifdef DEBUG_TYPEDEF /* Used for debugging typedef processing. */ typedef_symbol_table_dump();#endif int_fatal(0, "%s", s);}/* Add type name to the typedef symbol table. */static void typedef_symbol_table_add(char *p_symbol){ TYPEDEF_SYM_BLK *block; /* Allocate room for string and its '\0' terminator. */ char *str_buf = (char *)malloc(strlen(p_symbol) + 1); if (str_buf == NULL) int_fatal(E_NO_HEAP); /* Make copy of argument. */ strcpy(str_buf, p_symbol); /* Is symbol table empty? */ if (typedef_sym_tbl_head == NULL) { /* Allocate first block and make the head of the table list. */ typedef_sym_tbl_head = block = (TYPEDEF_SYM_BLK *)malloc(sizeof *block); if (block == NULL) int_fatal(E_NO_HEAP); block->total = 0; block->next = NULL; } else { TYPEDEF_SYM_BLK *prev_block; /* Find first block in symbol-table list that isn't full. */ for (prev_block = NULL, block = typedef_sym_tbl_head; block != NULL && block->total == DIM_OF(block->id); prev_block = block, block = block->next) ; /* If all blocks are full, allocate a new one and append to list. */ if (block == NULL) { block = (TYPEDEF_SYM_BLK *)malloc(sizeof *block); if (block == NULL) int_fatal(E_NO_HEAP); block->total = 0; block->next = NULL; if (prev_block == NULL) typedef_sym_tbl_head = block; else prev_block->next = block; } } /* Save pointer to the new type name in first empty slot of this block. */ block->id[block->total++] = str_buf;}/* Return TRUE if symbol exists in the typedef symbol table. */BOOLEAN typedef_symbol_table_find(char *p_symbol){ TYPEDEF_SYM_BLK *block; BOOLEAN found = FALSE; /* Loop for each block of symbols. */ for (block = typedef_sym_tbl_head; block != NULL; block = block->next) { unsigned i; /* Loop for each symbol in this block. */ for (i = 0; i < block->total; ++i) if (strcmp(block->id[i], p_symbol) == 0) found = TRUE; } return found;}/* Remove all symbols (and symbol blocks) from the symbol table--make the table empty.*/void typedef_symbol_table_flush(void){ TYPEDEF_SYM_BLK *block; /* Loop for each block of symbols. */ for (block = typedef_sym_tbl_head; block != NULL; ) { unsigned i; TYPEDEF_SYM_BLK *temp_block; /* Loop for each symbol in this block. */ for (i = 0; i < block->total; ++i) free(block->id[i]); /* Free symbol. */ temp_block = block->next; free(block); /* Free block now that it's empty. */ block = temp_block; } typedef_sym_tbl_head = NULL;}#ifdef DEBUG_TYPEDEF/* Display the contents of the typedef symbol table. Used for debugging typedef processing.*/void typedef_symbol_table_dump(void){ TYPEDEF_SYM_BLK *block; fputs("typedef symbol table dump:\n", out_fp); /* Loop for each block of symbols. */ for (block = typedef_sym_tbl_head; block != NULL; block = block->next) { unsigned i; /* Loop for each symbol in this block. */ for (i = 0; i < block->total; ++i) fprintf(out_fp, "%s\n", block->id[i]); }}#endif/* Record that the last statement was a case label. */static void case_label(void){ is_case_label = TRUE;}/* Record that the last statement was not a case label. If the previous statement was a case label, increment the decision-point counter--this ends a run of adjacent case labels which count as one decision point.*/static void not_case_label(void){ if (is_case_label) { is_case_label = FALSE; ++fcn_decisions; /* This is a decision point. */ }}/* Initialize parser. */void init_yacc(void){ /* Make the typedef symbol table empty. */ typedef_symbol_table_flush(); /* See the definition of each of these variables, above, for more information. */ is_typedef = FALSE; nested_decl_specs = 0; is_case_label = FALSE; function_name[0] = '\0'; last_ident[0] = '\0'; last_decl[0] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -