📄 parse.c
字号:
/* Parser for GNU CHILL (CCITT High-Level Language) -*- C -*- Copyright (C) 1992, 1993, 1998, 1999 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */ /* * This is a two-pass parser. In pass 1, we collect declarations, * ignoring actions and most expressions. We store only the * declarations and close, open and re-lex the input file to save * main memory. We anticipate that the compiler will be processing * *very* large single programs which are mechanically generated, * and so we want to store a minimum of information between passes. * * yylex detects the end of the main input file and returns the * END_PASS_1 token. We then re-initialize each CHILL compiler * module's global variables and re-process the input file. The * grant file is output. If the user has requested it, GNU CHILL * exits at this time - its only purpose was to generate the grant * file. Optionally, the compiler may exit if errors were detected * in pass 1. * * As each symbol scope is entered, we install its declarations into * the symbol table. Undeclared types and variables are announced * now. * * Then code is generated. */#include "config.h"#include "system.h"#include "tree.h"#include "ch-tree.h"#include "lex.h"#include "actions.h"#include "tasking.h"#include "parse.h"#include "toplev.h"/* Since parsers are distinct for each language, put the language string definition here. (fnf) */char *language_string = "GNU CHILL";/* Common code to be done before expanding any action. */#define INIT_ACTION { \ if (! ignoring) emit_line_note (input_filename, lineno); }/* Pop a scope for an ON handler. */#define POP_USED_ON_CONTEXT pop_handler(1)/* Pop a scope for an ON handler that wasn't there. */#define POP_UNUSED_ON_CONTEXT pop_handler(0)#define PUSH_ACTION push_action()/* Cause the `yydebug' variable to be defined. */#define YYDEBUG 1extern struct rtx_def* gen_label_rtx PROTO((void));extern void emit_jump PROTO((struct rtx_def *));extern struct rtx_def* emit_label PROTO((struct rtx_def *));/* This is a hell of a lot easier than getting expr.h included in by parse.c. */extern struct rtx_def *expand_expr PROTO((tree, struct rtx_def *, enum machine_mode, int));static int parse_action PROTO((void));extern int lineno;extern char *input_filename;extern tree generic_signal_type_node;extern tree signal_code;extern int all_static_flag;extern int ignore_case; #if 0static int quasi_signal = 0; /* 1 if processing a quasi signal decl */#endifint parsing_newmode; /* 0 while parsing SYNMODE; 1 while parsing NEWMODE. */int expand_exit_needed = 0;/* Gets incremented if we see errors such that we don't want to run pass 2. */int serious_errors = 0;static tree current_fieldlist;/* We don't care about expressions during pass 1, except while we're parsing the RHS of a SYN definition, or while parsing a mode that we need. NOTE: This also causes mode expressions to be ignored. */int ignoring = 1; /* 1 to ignore expressions *//* True if we have seen an action not in a (user) function. */int seen_action = 0;int build_constructor = 0;/* The action_nesting_level of the current procedure body. */ int proc_action_level = 0;/* This is the identifier of the label that prefixes the current action, or NULL if there was none. It is cleared at the end of an action, or when starting a nested action list, so get it while you can! */static tree label = NULL_TREE; /* for statement labels */#if 0static tree current_block;#endifint in_pseudo_module = 0;int pass = 0; /* 0 for init_decl_processing, 1 for pass 1, 2 for pass 2 *//* re-initialize global variables for pass 2 */static voidch_parse_init (){ expand_exit_needed = 0; label = NULL_TREE; /* for statement labels */ current_module = NULL; in_pseudo_module = 0;}static voidcheck_end_label (start, end) tree start, end;{ if (end != NULL_TREE) { if (start == NULL_TREE && pass == 1) error ("there was no start label to match the end label '%s'", IDENTIFIER_POINTER(end)); else if (start != end && pass == 1) error ("start label '%s' does not match end label '%s'", IDENTIFIER_POINTER(start), IDENTIFIER_POINTER(end)); }}/* * given a tree which is an id, a type or a decl, * return the associated type, or issue an error and * return error_mark_node. */treeget_type_of (id_or_decl) tree id_or_decl;{ tree type = id_or_decl; if (id_or_decl == NULL_TREE || TREE_CODE (id_or_decl) == ERROR_MARK) return error_mark_node; if (pass == 1 || ignoring == 1) return id_or_decl; if (TREE_CODE (type) == IDENTIFIER_NODE) { type = lookup_name (id_or_decl); if (type == NULL_TREE) { error ("`%s' not declared", IDENTIFIER_POINTER (id_or_decl)); type = error_mark_node; } } if (TREE_CODE (type) == TYPE_DECL) type = TREE_TYPE (type); return type; /* was a type all along */}static voidend_function (){ if (CH_DECL_PROCESS (current_function_decl)) { /* finishing a process */ if (! ignoring) { tree result = build_chill_function_call (lookup_name (get_identifier ("__stop_process")), NULL_TREE); expand_expr_stmt (result); emit_line_note (input_filename, lineno); } } else { /* finishing a procedure.. */ if (! ignoring) { if (result_never_set && TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) != VOID_TYPE) warning ("No RETURN or RESULT in procedure"); chill_expand_return (NULL_TREE, 1); } } finish_chill_function (); pop_chill_function_context (); }static treebuild_prefix_clause (id) tree id;{ if (!id) { if (current_module && current_module->name) { char *module_name = IDENTIFIER_POINTER (current_module->name); if (module_name[0] && module_name[0] != '_') return current_module->name; } error ("PREFIXED clause with no prelix in unlabeled module"); } return id;}voidpossibly_define_exit_label (label) tree label;{ if (label) define_label (input_filename, lineno, munge_exit_label (label));}#define MAX_LOOK_AHEAD 2static enum terminal terminal_buffer[MAX_LOOK_AHEAD+1];YYSTYPE yylval;static YYSTYPE val_buffer[MAX_LOOK_AHEAD+1];/*enum terminal current_token, lookahead_token;*/#define TOKEN_NOT_READ dummy_last_terminal#ifdef __GNUC____inline__#endifstatic enum terminalPEEK_TOKEN(){ if (terminal_buffer[0] == TOKEN_NOT_READ) { terminal_buffer[0] = yylex(); val_buffer[0] = yylval; } return terminal_buffer[0];}#define PEEK_TREE() val_buffer[0].ttype#define PEEK_TOKEN1() peek_token_(1)#define PEEK_TOKEN2() peek_token_(2)static intpeek_token_ (i) int i;{ if (i > MAX_LOOK_AHEAD) fatal ("internal error - too much lookahead"); if (terminal_buffer[i] == TOKEN_NOT_READ) { terminal_buffer[i] = yylex(); val_buffer[i] = yylval; } return terminal_buffer[i];}static voidpushback_token (code, node) int code; tree node;{ int i; if (terminal_buffer[MAX_LOOK_AHEAD] != TOKEN_NOT_READ) fatal ("internal error - cannot pushback token"); for (i = MAX_LOOK_AHEAD; i > 0; i--) { terminal_buffer[i] = terminal_buffer[i - 1]; val_buffer[i] = val_buffer[i - 1]; } terminal_buffer[0] = code; val_buffer[0].ttype = node;}static voidforward_token_(){ int i; for (i = 0; i < MAX_LOOK_AHEAD; i++) { terminal_buffer[i] = terminal_buffer[i+1]; val_buffer[i] = val_buffer[i+1]; } terminal_buffer[MAX_LOOK_AHEAD] = TOKEN_NOT_READ;}#define FORWARD_TOKEN() forward_token_()/* Skip the next token. if it isn't TOKEN, the parser is broken. */voidrequire(token) enum terminal token;{ if (PEEK_TOKEN() != token) { char buf[80]; sprintf (buf, "internal parser error - expected token %d", (int)token); fatal(buf); } FORWARD_TOKEN();}intcheck_token (token) enum terminal token;{ if (PEEK_TOKEN() != token) return 0; FORWARD_TOKEN (); return 1;}/* return 0 if expected token was not found, else return 1.*/intexpect(token, message) enum terminal token; char *message;{ if (PEEK_TOKEN() != token) { if (pass == 1) error(message ? message : "syntax error"); return 0; } else FORWARD_TOKEN(); return 1;}/* define a SYNONYM __PROCNAME__ (__procname__) which holds the name of the current procedure. This should be quit the same as __FUNCTION__ in C */static voiddefine__PROCNAME__ (){ char *fname; tree string; tree procname; if (current_function_decl == NULL_TREE) fname = "toplevel"; else fname = IDENTIFIER_POINTER (DECL_NAME (current_function_decl)); string = build_chill_string (strlen (fname), fname); procname = get_identifier (ignore_case ? "__procname__" : "__PROCNAME__"); push_syndecl (procname, NULL_TREE, string);}/* Forward declarations. */static tree parse_expression ();static tree parse_primval ();static tree parse_mode PROTO((void));static tree parse_opt_mode PROTO((void));static tree parse_untyped_expr ();static tree parse_opt_untyped_expr ();static int parse_definition PROTO((int));static void parse_opt_actions ();static void parse_body PROTO((void));static tree parse_if_expression_body PROTO((void));static tree parse_opt_handler PROTO((void));static treeparse_opt_name_string (allow_all) int allow_all; /* 1 if ALL is allowed as a postfix */{ enum terminal token = PEEK_TOKEN(); tree name; if (token != NAME) { if (token == ALL && allow_all) { FORWARD_TOKEN (); return ALL_POSTFIX; } return NULL_TREE; } name = PEEK_TREE(); for (;;) { FORWARD_TOKEN (); token = PEEK_TOKEN(); if (token != '!') return name; FORWARD_TOKEN(); token = PEEK_TOKEN(); if (token == ALL && allow_all) return get_identifier3(IDENTIFIER_POINTER (name), "!", "*"); if (token != NAME) { if (pass == 1) error ("'%s!' is not followed by an identifier", IDENTIFIER_POINTER (name)); return name; } name = get_identifier3(IDENTIFIER_POINTER(name), "!", IDENTIFIER_POINTER(PEEK_TREE())); }}static treeparse_simple_name_string (){ enum terminal token = PEEK_TOKEN(); tree name; if (token != NAME) { error ("expected a name here"); return error_mark_node; } name = PEEK_TREE (); FORWARD_TOKEN (); return name;}static treeparse_name_string (){ tree name = parse_opt_name_string (0); if (name) return name; if (pass == 1) error ("expected a name string here"); return error_mark_node;}static treeparse_defining_occurrence (){ if (PEEK_TOKEN () == NAME) { tree id = PEEK_TREE(); FORWARD_TOKEN (); return id; } return NULL;}/* Matches: <name_string> Returns if pass 1: the identifier. Returns if pass 2: a decl or value for identifier. */static treeparse_name (){ tree name = parse_name_string (); if (pass == 1 || ignoring) return name; else { tree decl = lookup_name (name); if (decl == NULL_TREE) { error ("`%s' undeclared", IDENTIFIER_POINTER (name)); return error_mark_node; } else if (TREE_CODE (TREE_TYPE (decl)) == ERROR_MARK) return error_mark_node; else if (TREE_CODE (decl) == CONST_DECL) return DECL_INITIAL (decl); else if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) return convert_from_reference (decl); else return decl; } }static treeparse_optlabel(){ tree label = parse_defining_occurrence(); if (label != NULL) expect(COLON, "expected a ':' here"); return label;}static voidparse_semi_colon (){ enum terminal token = PEEK_TOKEN (); if (token == SC) FORWARD_TOKEN (); else if (pass == 1) (token == END ? pedwarn : error) ("expected ';' here"); label = NULL_TREE;}static voidparse_opt_end_label_semi_colon (start_label) tree start_label;{ if (PEEK_TOKEN() == NAME) { tree end_label = parse_name_string (); check_end_label (start_label, end_label); } parse_semi_colon ();}static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -