📄 ytab.c
字号:
/* c:/mks\bin\yacc -d gram.y */#line 1 "gram.y"/************************************************************* Copyright (c) 1993-1995 by Paul Long All rights reserved.**************************************************************//************************************************************* gram.y - This source file contains the YACC grammar and actions for Metre's Standard C parser. It also contains main(), error-handling functions, trigger-firing functions, functions that maintain the typedef symbol table, functions that administer the execution of Metre, functions that can be called from the rules() function, and a replacement for YACC's yyerror(). As you can see, most of the grammar rules have no actions. This is because the grammar is largely used to just skip over the parts of C that Metre doesn't care about.**************************************************************/#include <stdio.h>#include <limits.h>#include <stdarg.h>#include <stdlib.h>#include "metreint.h"/* NOTE: Someone said that that the default stack size for MKS yacc and AT&T (SCO) yacc of 150 was not sufficient for the code he was running through Metre, so he redefined the stack size to 1000. If you encounter the same situation, use one of the following directives to increase the stack size for the the version of yacc that you're using.*/#if 0#define YYSSIZE 1000 /* MKS yacc stack size */#define YYMAXDEPTH 1000 /* AT&T yacc stack size */#endif/* String containing all of the white-space characters. */#define WHITE_SPACE_CHARS " \t\r\n\v\f"/* VMS has different ideas about what constitutes a successful return value. */#ifdef VAX#define RETURN_FROM_MAIN_VALUE 1#else#define RETURN_FROM_MAIN_VALUE 0#endif/* External-function prototypes. *//* Defines behavior for this Metre tool. */extern void rules(void);/* YACC-generated parser function. */extern yyparse();/* lex-generated scanner function. */extern yylex();/* Error function that yacc-generated parser calls. */extern void yyerror(char *);/* External variables. *//* Metre maintains statistics in the int_* structures, e.g., int_prj. The structures with the unadorned names, e.g., prj, are used to communicate with the rules. They are zero-filled except when a trigger is being fired. At that time, the contents of the corresponding int_* structure is copied to it, the rules() function is called, and then the structure is zero-filed again.*/PRJ prj, int_prj; /* Project. */MOD mod, int_mod; /* Module. */FCN fcn; /* Function. */static FCN int_fcn;STM stm; /* Statement. */static STM int_stm;LIN lin, int_lin; /* Line. */GRM grm, int_grm; /* Grammatical. */LEX lex, int_lex; /* Lexical. *//* Which command-line argument (argv) at which to start looking for the next file name to process and original file name, respectively.*/unsigned next_cmd_line_file;unsigned next_cmd_line_file_orig_n;/* Number of decision points, conditions, and functions in module (file). */unsigned mod_decisions;unsigned mod_conditions;unsigned mod_functions;/* Indicates whether we are looking for a tag. Parser writes it, lexer reads it. Since tags are in a separate name space from other identifiers, this helps the lexer determine whether a lexeme is an identifier or a type name.*/BOOLEAN looking_for_tag;/* Indicates whether we are within a function definition. Used to determine whether to use the last identifier as the function name.*/BOOLEAN is_within_function;/* Name of current input file and name of original file, if specified on command line with the substitute-file-name option. If substitute not provided, input_file_orig_name points to the same name as input_file.*/char *input_file;char *input_file_orig_name;/* Where all output is written. */FILE *out_fp;static char *command_name = DEFAULT_COMMAND_NAME;/* Global versions of main's argc and argv. */int cmd_line_argc;char **cmd_line_argv;/* Block within which typedef type names are held in the typedef symbol-table.*/typedef struct typedef_sym_blk { struct typedef_sym_blk *next; /* Next block. */ unsigned total; /* Total in this block. */ char *id[TYPEDEF_SYMBOLS_PER_BLOCK]; /* Array of pointers to type names. */} TYPEDEF_SYM_BLK;/* Head of the typedef symbol-table. NOTE: This is the only symbol table in Metre, and it is used just to hold typedef type names, not all symbols.*/TYPEDEF_SYM_BLK *typedef_sym_tbl_head = NULL;/* Command-line argument. Used to hold arguments taken from script file. */typedef struct arg { struct arg *next; char *string;} ARG;/* Static variables. *//* Control depth--current number of nested control structures. */static unsigned depth;/* Used to determine how many statements are on a line. */static unsigned previous_statements_line_number;/* Number of decision points and conditions in function. */static unsigned fcn_decisions;static unsigned fcn_conditions;/* Metre maintains the number of statements appearing on a line. The is_if and is_else BOOLEANs are used principally to relax the criteria for what constitutes a statement. For example, "else if," is not considered two statements because this is a common idiom.*/static BOOLEAN is_else, is_if;/* is_typedef indicates whether we are parsing a typedef. Since typedefs cannot be nested, it's okay that this is just a BOOLEAN. This is used to find the type name of a typedef so that it can be added to the typedef symbol table. If the type name is subsequently encountered by the lexer, the lexer returns a token for a type name rather than for an identifier. This is the ugly part of C that cannot practically be expressed by a YACC grammar specification.*/static BOOLEAN is_typedef;/* nested_decl_specs is used to distinguish the name of the thing being declared, such as the type name in a typedef, from other identifiers in the declaration.*/static unsigned nested_decl_specs;/* Whether the last statement was a case label. Used to consider adjacent case labels as one decision point. The transition from is_case_label==TRUE to is_case_label==FALSE is a decision point, instead of each case label being a decision point. Adjacent case labels are considered one decision point because this is analogous to an if statement with or logical operators, ||. For example, switch (expr) { case 5: case 10: a; } is, in this regard, analogous to if (expr == 5 || expr == 10) a; I did not want to bias the metric against the switch statement.*/static BOOLEAN is_case_label;static IDENTIFIER function_name;static IDENTIFIER last_ident;static IDENTIFIER last_decl;/* Pointer to current operator, keyword, or identifier as passed to rules if such a token is encountered.*/static char *current_operator;static char *current_keyword;static char *current_identifier;static char *current_type_name;/* Static function declarations. */static void begin_project(char *);static void fire_fcn(void);static void fire_stm(void);static void print_exception(int, char *, char *, va_list);static void typedef_symbol_table_add(char *);static void case_label(void);static void not_case_label(void);static void check_starting_options(void);static void print_banner(void);static void print_help(void);static void stat_func_begin(void);static void stat_func_end(void);static void check_multiple_statements(void);static void int_warn(int, char *, ...);static void fire_operator(void);static void fire_keyword(void);static void fire_identifier(void);static void fire_declarator(void);static void fire_type_name(void);static void found_constant(void);static void found_string(void);static void found_expression_statement(BOOLEAN);static void function_call(void);static void after_compound_declarations(void);static void before_compound_declarations(void);static void after_initializer(void);static void before_initializer(void);static void get_options_from_file(char *);static void build_new_argv(ARG *);#define TK_IDENTIFIER 257#define TK_CONSTANT 258#define TK_STRING_LITERAL 259#define TK_SIZEOF 260#define TK_PTR_OP 261#define TK_INC_OP 262#define TK_DEC_OP 263#define TK_LEFT_OP 264#define TK_RIGHT_OP 265#define TK_LE_OP 266#define TK_GE_OP 267#define TK_EQ_OP 268#define TK_NE_OP 269#define TK_AND_OP 270#define TK_OR_OP 271#define TK_MUL_ASSIGN 272#define TK_DIV_ASSIGN 273#define TK_MOD_ASSIGN 274#define TK_ADD_ASSIGN 275#define TK_SUB_ASSIGN 276#define TK_LEFT_ASSIGN 277#define TK_RIGHT_ASSIGN 278#define TK_AND_ASSIGN 279#define TK_XOR_ASSIGN 280#define TK_OR_ASSIGN 281#define TK_TYPE_NAME 282#define TK_TYPEDEF 283#define TK_EXTERN 284#define TK_STATIC 285#define TK_AUTO 286#define TK_REGISTER 287#define TK_CHAR 288#define TK_SHORT 289#define TK_INT 290#define TK_LONG 291#define TK_SIGNED 292#define TK_UNSIGNED 293#define TK_FLOAT 294#define TK_DOUBLE 295#define TK_CONST 296#define TK_VOLATILE 297#define TK_VOID 298#define TK_STRUCT 299#define TK_UNION 300#define TK_ENUM 301#define TK_ELIPSIS 302#define TK_RANGE 303#define TK_CASE 304#define TK_DEFAULT 305#define TK_IF 306#define TK_ELSE 307#define TK_SWITCH 308#define TK_WHILE 309#define TK_DO 310#define TK_FOR 311#define TK_GOTO 312#define TK_CONTINUE 313#define TK_BREAK 314#define TK_RETURN 315#define THEN 316extern int yychar, yyerrflag;#ifndef YYSTYPE#define YYSTYPE int#endifextern YYSTYPE yyval;extern YYSTYPE yylval;#line 1472 "gram.y"/* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -