⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parse.c

📁 gcc-fortran,linux使用fortran的编译软件。很好用的。
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Main parser.   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006   Free Software Foundation, Inc.   Contributed by Andy VaughtThis file is part of GCC.GCC is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.GCC is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public Licensealong with GCC; see the file COPYING.  If not, write to the FreeSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA02110-1301, USA.  */#include "config.h"#include "system.h"#include <setjmp.h>#include "gfortran.h"#include "match.h"#include "parse.h"/* Current statement label.  Zero means no statement label.  Because   new_st can get wiped during statement matching, we have to keep it   separate.  */gfc_st_label *gfc_statement_label;static locus label_locus;static jmp_buf eof_buf;gfc_state_data *gfc_state_stack;/* TODO: Re-order functions to kill these forward decls.  */static void check_statement_label (gfc_statement);static void undo_new_statement (void);static void reject_statement (void);/* A sort of half-matching function.  We try to match the word on the   input with the passed string.  If this succeeds, we call the   keyword-dependent matching function that will match the rest of the   statement.  For single keywords, the matching subroutine is   gfc_match_eos().  */static matchmatch_word (const char *str, match (*subr) (void), locus * old_locus){  match m;  if (str != NULL)    {      m = gfc_match (str);      if (m != MATCH_YES)	return m;    }  m = (*subr) ();  if (m != MATCH_YES)    {      gfc_current_locus = *old_locus;      reject_statement ();    }  return m;}/* Figure out what the next statement is, (mostly) regardless of   proper ordering.  The do...while(0) is there to prevent if/else   ambiguity.  */#define match(keyword, subr, st)				\    do {                                                        \      if (match_word(keyword, subr, &old_locus) == MATCH_YES)	\        return st;						\      else							\        undo_new_statement ();                                  \    } while (0);static gfc_statementdecode_statement (void){  gfc_statement st;  locus old_locus;  match m;  int c;#ifdef GFC_DEBUG  gfc_symbol_state ();#endif  gfc_clear_error ();	/* Clear any pending errors.  */  gfc_clear_warning ();	/* Clear any pending warnings.  */  if (gfc_match_eos () == MATCH_YES)    return ST_NONE;  old_locus = gfc_current_locus;  /* Try matching a data declaration or function declaration. The      input "REALFUNCTIONA(N)" can mean several things in different      contexts, so it (and its relatives) get special treatment.  */  if (gfc_current_state () == COMP_NONE      || gfc_current_state () == COMP_INTERFACE      || gfc_current_state () == COMP_CONTAINS)    {      m = gfc_match_function_decl ();      if (m == MATCH_YES)	return ST_FUNCTION;      else if (m == MATCH_ERROR)	reject_statement ();      gfc_undo_symbols ();      gfc_current_locus = old_locus;    }  /* Match statements whose error messages are meant to be overwritten     by something better.  */  match (NULL, gfc_match_assignment, ST_ASSIGNMENT);  match (NULL, gfc_match_pointer_assignment, ST_POINTER_ASSIGNMENT);  match (NULL, gfc_match_st_function, ST_STATEMENT_FUNCTION);  match (NULL, gfc_match_data_decl, ST_DATA_DECL);  match (NULL, gfc_match_enumerator_def, ST_ENUMERATOR);  /* Try to match a subroutine statement, which has the same optional     prefixes that functions can have.  */  if (gfc_match_subroutine () == MATCH_YES)    return ST_SUBROUTINE;  gfc_undo_symbols ();  gfc_current_locus = old_locus;  /* Check for the IF, DO, SELECT, WHERE and FORALL statements, which     might begin with a block label.  The match functions for these     statements are unusual in that their keyword is not seen before     the matcher is called.  */  if (gfc_match_if (&st) == MATCH_YES)    return st;  gfc_undo_symbols ();  gfc_current_locus = old_locus;  if (gfc_match_where (&st) == MATCH_YES)    return st;  gfc_undo_symbols ();  gfc_current_locus = old_locus;  if (gfc_match_forall (&st) == MATCH_YES)    return st;  gfc_undo_symbols ();  gfc_current_locus = old_locus;  match (NULL, gfc_match_do, ST_DO);  match (NULL, gfc_match_select, ST_SELECT_CASE);  /* General statement matching: Instead of testing every possible     statement, we eliminate most possibilities by peeking at the     first character.  */  c = gfc_peek_char ();  switch (c)    {    case 'a':      match ("allocate", gfc_match_allocate, ST_ALLOCATE);      match ("allocatable", gfc_match_allocatable, ST_ATTR_DECL);      match ("assign", gfc_match_assign, ST_LABEL_ASSIGNMENT);      break;    case 'b':      match ("backspace", gfc_match_backspace, ST_BACKSPACE);      match ("block data", gfc_match_block_data, ST_BLOCK_DATA);      break;    case 'c':      match ("call", gfc_match_call, ST_CALL);      match ("close", gfc_match_close, ST_CLOSE);      match ("continue", gfc_match_continue, ST_CONTINUE);      match ("cycle", gfc_match_cycle, ST_CYCLE);      match ("case", gfc_match_case, ST_CASE);      match ("common", gfc_match_common, ST_COMMON);      match ("contains", gfc_match_eos, ST_CONTAINS);      break;    case 'd':      match ("deallocate", gfc_match_deallocate, ST_DEALLOCATE);      match ("data", gfc_match_data, ST_DATA);      match ("dimension", gfc_match_dimension, ST_ATTR_DECL);      break;    case 'e':      match ("end file", gfc_match_endfile, ST_END_FILE);      match ("exit", gfc_match_exit, ST_EXIT);      match ("else", gfc_match_else, ST_ELSE);      match ("else where", gfc_match_elsewhere, ST_ELSEWHERE);      match ("else if", gfc_match_elseif, ST_ELSEIF);      match ("enum , bind ( c )", gfc_match_enum, ST_ENUM);      if (gfc_match_end (&st) == MATCH_YES)	return st;      match ("entry% ", gfc_match_entry, ST_ENTRY);      match ("equivalence", gfc_match_equivalence, ST_EQUIVALENCE);      match ("external", gfc_match_external, ST_ATTR_DECL);      break;    case 'f':      match ("flush", gfc_match_flush, ST_FLUSH);      match ("format", gfc_match_format, ST_FORMAT);      break;    case 'g':      match ("go to", gfc_match_goto, ST_GOTO);      break;    case 'i':      match ("inquire", gfc_match_inquire, ST_INQUIRE);      match ("implicit", gfc_match_implicit, ST_IMPLICIT);      match ("implicit% none", gfc_match_implicit_none, ST_IMPLICIT_NONE);      match ("interface", gfc_match_interface, ST_INTERFACE);      match ("intent", gfc_match_intent, ST_ATTR_DECL);      match ("intrinsic", gfc_match_intrinsic, ST_ATTR_DECL);      break;    case 'm':      match ("module% procedure% ", gfc_match_modproc, ST_MODULE_PROC);      match ("module", gfc_match_module, ST_MODULE);      break;    case 'n':      match ("nullify", gfc_match_nullify, ST_NULLIFY);      match ("namelist", gfc_match_namelist, ST_NAMELIST);      break;    case 'o':      match ("open", gfc_match_open, ST_OPEN);      match ("optional", gfc_match_optional, ST_ATTR_DECL);      break;    case 'p':      match ("print", gfc_match_print, ST_WRITE);      match ("parameter", gfc_match_parameter, ST_PARAMETER);      match ("pause", gfc_match_pause, ST_PAUSE);      match ("pointer", gfc_match_pointer, ST_ATTR_DECL);      if (gfc_match_private (&st) == MATCH_YES)	return st;      match ("program", gfc_match_program, ST_PROGRAM);      if (gfc_match_public (&st) == MATCH_YES)	return st;      break;    case 'r':      match ("read", gfc_match_read, ST_READ);      match ("return", gfc_match_return, ST_RETURN);      match ("rewind", gfc_match_rewind, ST_REWIND);      break;    case 's':      match ("sequence", gfc_match_eos, ST_SEQUENCE);      match ("stop", gfc_match_stop, ST_STOP);      match ("save", gfc_match_save, ST_ATTR_DECL);      break;    case 't':      match ("target", gfc_match_target, ST_ATTR_DECL);      match ("type", gfc_match_derived_decl, ST_DERIVED_DECL);      break;    case 'u':      match ("use% ", gfc_match_use, ST_USE);      break;    case 'w':      match ("write", gfc_match_write, ST_WRITE);      break;    }  /* All else has failed, so give up.  See if any of the matchers has     stored an error message of some sort.  */  if (gfc_error_check () == 0)    gfc_error_now ("Unclassifiable statement at %C");  reject_statement ();  gfc_error_recovery ();  return ST_NONE;}#undef match/* Get the next statement in free form source.  */static gfc_statementnext_free (void){  match m;  int c, d, cnt;  gfc_gobble_whitespace ();  c = gfc_peek_char ();  if (ISDIGIT (c))    {      /* Found a statement label?  */      m = gfc_match_st_label (&gfc_statement_label);      d = gfc_peek_char ();      if (m != MATCH_YES || !gfc_is_whitespace (d))	{	  gfc_match_small_literal_int (&c, &cnt);	  if (cnt > 5)	    gfc_error_now ("Too many digits in statement label at %C");	  	  if (c == 0)	    gfc_error_now ("Statement label at %C is zero");	  do	    c = gfc_next_char ();	  while (ISDIGIT(c));	  if (!gfc_is_whitespace (c))	    gfc_error_now ("Non-numeric character in statement label at %C");	}      else	{	  label_locus = gfc_current_locus;	  gfc_gobble_whitespace ();	  if (gfc_match_eos () == MATCH_YES)	    {	      gfc_warning_now		("Ignoring statement label in empty statement at %C");	      gfc_free_st_label (gfc_statement_label);	      gfc_statement_label = NULL;	      return ST_NONE;	    }	}    }  return decode_statement ();}/* Get the next statement in fixed-form source.  */static gfc_statementnext_fixed (void){  int label, digit_flag, i;  locus loc;  char c;  if (!gfc_at_bol ())    return decode_statement ();  /* Skip past the current label field, parsing a statement label if     one is there.  This is a weird number parser, since the number is     contained within five columns and can have any kind of embedded     spaces.  We also check for characters that make the rest of the     line a comment.  */  label = 0;  digit_flag = 0;  for (i = 0; i < 5; i++)    {      c = gfc_next_char_literal (0);      switch (c)	{	case ' ':	  break;	case '0':	case '1':	case '2':	case '3':	case '4':	case '5':	case '6':	case '7':	case '8':	case '9':	  label = label * 10 + c - '0';	  label_locus = gfc_current_locus;	  digit_flag = 1;	  break;          /* Comments have already been skipped by the time we get	     here so don't bother checking for them.  */	default:	  gfc_buffer_error (0);	  gfc_error ("Non-numeric character in statement label at %C");	  return ST_NONE;	}    }  if (digit_flag)    {      if (label == 0)	gfc_warning_now ("Zero is not a valid statement label at %C");      else	{	  /* We've found a valid statement label.  */	  gfc_statement_label = gfc_get_st_label (label);	}    }  /* Since this line starts a statement, it cannot be a continuation     of a previous statement.  If we see something here besides a     space or zero, it must be a bad continuation line.  */  c = gfc_next_char_literal (0);  if (c == '\n')    goto blank_line;  if (c != ' ' && c!= '0')    {      gfc_buffer_error (0);      gfc_error ("Bad continuation line at %C");      return ST_NONE;    }  /* Now that we've taken care of the statement label columns, we have     to make sure that the first nonblank character is not a '!'.  If     it is, the rest of the line is a comment.  */  do    {      loc = gfc_current_locus;      c = gfc_next_char_literal (0);    }  while (gfc_is_whitespace (c));  if (c == '!')    goto blank_line;  gfc_current_locus = loc;  if (gfc_match_eos () == MATCH_YES)    goto blank_line;  /* At this point, we've got a nonblank statement to parse.  */  return decode_statement ();blank_line:  if (digit_flag)    gfc_warning ("Statement label in blank line will be " "ignored at %C");  gfc_advance_line ();  return ST_NONE;}/* Return the next non-ST_NONE statement to the caller.  We also worry   about including files and the ends of include files at this stage.  */static gfc_statementnext_statement (void){  gfc_statement st;  gfc_new_block = NULL;  for (;;)    {      gfc_statement_label = NULL;      gfc_buffer_error (1);      if (gfc_at_eol ())	{	  if (gfc_option.warn_line_truncation	      && gfc_current_locus.lb->truncated)	    gfc_warning_now ("Line truncated at %C");	  gfc_advance_line ();	}      gfc_skip_comments ();      if (gfc_at_end ())	{	  st = ST_NONE;	  break;	}      st =	(gfc_current_form == FORM_FIXED) ? next_fixed () : next_free ();      if (st != ST_NONE)	break;    }  gfc_buffer_error (0);  if (st != ST_NONE)    check_statement_label (st);  return st;}/****************************** Parser ***********************************//* The parser subroutines are of type 'try' that fail if the file ends   unexpectedly.  *//* Macros that expand to case-labels for various classes of   statements.  Start with executable statements that directly do   things.  */#define case_executable case ST_ALLOCATE: case ST_BACKSPACE: case ST_CALL: \  case ST_CLOSE: case ST_CONTINUE: case ST_DEALLOCATE: case ST_END_FILE: \  case ST_GOTO: case ST_INQUIRE: case ST_NULLIFY: case ST_OPEN: \  case ST_READ: case ST_RETURN: case ST_REWIND: case ST_SIMPLE_IF: \  case ST_PAUSE: case ST_STOP: case ST_WRITE: case ST_ASSIGNMENT: \  case ST_POINTER_ASSIGNMENT: case ST_EXIT: case ST_CYCLE: \  case ST_ARITHMETIC_IF: case ST_WHERE: case ST_FORALL: \  case ST_LABEL_ASSIGNMENT: case ST_FLUSH/* Statements that mark other executable statements.  */#define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: case ST_IF_BLOCK: \  case ST_WHERE_BLOCK: case ST_SELECT_CASE/* Declaration statements */#define case_decl case ST_ATTR_DECL: case ST_COMMON: case ST_DATA_DECL: \  case ST_EQUIVALENCE: case ST_NAMELIST: case ST_STATEMENT_FUNCTION: \  case ST_TYPE: case ST_INTERFACE/* Block end statements.  Errors associated with interchanging these   are detected in gfc_match_end().  */#define case_end case ST_END_BLOCK_DATA: case ST_END_FUNCTION: \                 case ST_END_PROGRAM: case ST_END_SUBROUTINE/* Push a new state onto the stack.  */static voidpush_state (gfc_state_data * p, gfc_compile_state new_state, gfc_symbol * sym){  p->state = new_state;  p->previous = gfc_state_stack;  p->sym = sym;  p->head = p->tail = NULL;  p->do_variable = NULL;  gfc_state_stack = p;}/* Pop the current state.  */static voidpop_state (void){  gfc_state_stack = gfc_state_stack->previous;}/* Try to find the given state in the state stack.  */trygfc_find_state (gfc_compile_state state){  gfc_state_data *p;  for (p = gfc_state_stack; p; p = p->previous)    if (p->state == state)      break;  return (p == NULL) ? FAILURE : SUCCESS;}/* Starts a new level in the statement list.  */static gfc_code *new_level (gfc_code * q){  gfc_code *p;  p = q->block = gfc_get_code ();  gfc_state_stack->head = gfc_state_stack->tail = p;  return p;}/* Add the current new_st code structure and adds it to the current   program unit.  As a side-effect, it zeroes the new_st.  */static gfc_code *add_statement (void){  gfc_code *p;  p = gfc_get_code ();  *p = new_st;  p->loc = gfc_current_locus;  if (gfc_state_stack->head == NULL)    gfc_state_stack->head = p;  else    gfc_state_stack->tail->next = p;  while (p->next != NULL)    p = p->next;  gfc_state_stack->tail = p;  gfc_clear_new_st ();  return p;}/* Frees everything associated with the current statement.  */static voidundo_new_statement (void){  gfc_free_statements (new_st.block);  gfc_free_statements (new_st.next);  gfc_free_statement (&new_st);  gfc_clear_new_st ();}/* If the current statement has a statement label, make sure that it   is allowed to, or should have one.  */static voidcheck_statement_label (gfc_statement st){  gfc_sl_type type;  if (gfc_statement_label == NULL)    {      if (st == ST_FORMAT)	gfc_error ("FORMAT statement at %L does not have a statement label",		   &new_st.loc);      return;    }  switch (st)    {    case ST_END_PROGRAM:    case ST_END_FUNCTION:    case ST_END_SUBROUTINE:    case ST_ENDDO:    case ST_ENDIF:    case ST_END_SELECT:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -