📄 io.c
字号:
return SUCCESS;}/* Free a gfc_filepos structure. */voidgfc_free_filepos (gfc_filepos * fp){ gfc_free_expr (fp->unit); gfc_free_expr (fp->iomsg); gfc_free_expr (fp->iostat); gfc_free (fp);}/* Match elements of a REWIND, BACKSPACE, ENDFILE, or FLUSH statement. */static matchmatch_file_element (gfc_filepos * fp){ match m; m = match_etag (&tag_unit, &fp->unit); if (m != MATCH_NO) return m; m = match_out_tag (&tag_iomsg, &fp->iomsg); if (m != MATCH_NO) return m; m = match_out_tag (&tag_iostat, &fp->iostat); if (m != MATCH_NO) return m; m = match_ltag (&tag_err, &fp->err); if (m != MATCH_NO) return m; return MATCH_NO;}/* Match the second half of the file-positioning statements, REWIND, BACKSPACE, ENDFILE, or the FLUSH statement. */static matchmatch_filepos (gfc_statement st, gfc_exec_op op){ gfc_filepos *fp; match m; fp = gfc_getmem (sizeof (gfc_filepos)); if (gfc_match_char ('(') == MATCH_NO) { m = gfc_match_expr (&fp->unit); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) goto syntax; goto done; } m = match_file_element (fp); if (m == MATCH_ERROR) goto done; if (m == MATCH_NO) { m = gfc_match_expr (&fp->unit); if (m == MATCH_ERROR) goto done; if (m == MATCH_NO) goto syntax; } for (;;) { if (gfc_match_char (')') == MATCH_YES) break; if (gfc_match_char (',') != MATCH_YES) goto syntax; m = match_file_element (fp); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) goto syntax; }done: if (gfc_match_eos () != MATCH_YES) goto syntax; if (gfc_pure (NULL)) { gfc_error ("%s statement not allowed in PURE procedure at %C", gfc_ascii_statement (st)); goto cleanup; } new_st.op = op; new_st.ext.filepos = fp; return MATCH_YES;syntax: gfc_syntax_error (st);cleanup: gfc_free_filepos (fp); return MATCH_ERROR;}trygfc_resolve_filepos (gfc_filepos * fp){ RESOLVE_TAG (&tag_unit, fp->unit); RESOLVE_TAG (&tag_iostat, fp->iostat); RESOLVE_TAG (&tag_iomsg, fp->iomsg); if (gfc_reference_st_label (fp->err, ST_LABEL_TARGET) == FAILURE) return FAILURE; return SUCCESS;}/* Match the file positioning statements: ENDFILE, BACKSPACE, REWIND, and the FLUSH statement. */matchgfc_match_endfile (void){ return match_filepos (ST_END_FILE, EXEC_ENDFILE);}matchgfc_match_backspace (void){ return match_filepos (ST_BACKSPACE, EXEC_BACKSPACE);}matchgfc_match_rewind (void){ return match_filepos (ST_REWIND, EXEC_REWIND);}matchgfc_match_flush (void){ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: FLUSH statement at %C") == FAILURE) return MATCH_ERROR; return match_filepos (ST_FLUSH, EXEC_FLUSH);}/******************** Data Transfer Statements *********************/typedef enum{ M_READ, M_WRITE, M_PRINT, M_INQUIRE }io_kind;/* Return a default unit number. */static gfc_expr *default_unit (io_kind k){ int unit; if (k == M_READ) unit = 5; else unit = 6; return gfc_int_expr (unit);}/* Match a unit specification for a data transfer statement. */static matchmatch_dt_unit (io_kind k, gfc_dt * dt){ gfc_expr *e; if (gfc_match_char ('*') == MATCH_YES) { if (dt->io_unit != NULL) goto conflict; dt->io_unit = default_unit (k); return MATCH_YES; } if (gfc_match_expr (&e) == MATCH_YES) { if (dt->io_unit != NULL) { gfc_free_expr (e); goto conflict; } dt->io_unit = e; return MATCH_YES; } return MATCH_NO;conflict: gfc_error ("Duplicate UNIT specification at %C"); return MATCH_ERROR;}/* Match a format specification. */static matchmatch_dt_format (gfc_dt * dt){ locus where; gfc_expr *e; gfc_st_label *label; where = gfc_current_locus; if (gfc_match_char ('*') == MATCH_YES) { if (dt->format_expr != NULL || dt->format_label != NULL) goto conflict; dt->format_label = &format_asterisk; return MATCH_YES; } if (gfc_match_st_label (&label) == MATCH_YES) { if (dt->format_expr != NULL || dt->format_label != NULL) { gfc_free_st_label (label); goto conflict; } if (gfc_reference_st_label (label, ST_LABEL_FORMAT) == FAILURE) return MATCH_ERROR; dt->format_label = label; return MATCH_YES; } if (gfc_match_expr (&e) == MATCH_YES) { if (dt->format_expr != NULL || dt->format_label != NULL) { gfc_free_expr (e); goto conflict; } dt->format_expr = e; return MATCH_YES; } gfc_current_locus = where; /* The only case where we have to restore */ return MATCH_NO;conflict: gfc_error ("Duplicate format specification at %C"); return MATCH_ERROR;}/* Traverse a namelist that is part of a READ statement to make sure that none of the variables in the namelist are INTENT(IN). Returns nonzero if we find such a variable. */static intcheck_namelist (gfc_symbol * sym){ gfc_namelist *p; for (p = sym->namelist; p; p = p->next) if (p->sym->attr.intent == INTENT_IN) { gfc_error ("Symbol '%s' in namelist '%s' is INTENT(IN) at %C", p->sym->name, sym->name); return 1; } return 0;}/* Match a single data transfer element. */static matchmatch_dt_element (io_kind k, gfc_dt * dt){ char name[GFC_MAX_SYMBOL_LEN + 1]; gfc_symbol *sym; match m; if (gfc_match (" unit =") == MATCH_YES) { m = match_dt_unit (k, dt); if (m != MATCH_NO) return m; } if (gfc_match (" fmt =") == MATCH_YES) { m = match_dt_format (dt); if (m != MATCH_NO) return m; } if (gfc_match (" nml = %n", name) == MATCH_YES) { if (dt->namelist != NULL) { gfc_error ("Duplicate NML specification at %C"); return MATCH_ERROR; } if (gfc_find_symbol (name, NULL, 1, &sym)) return MATCH_ERROR; if (sym == NULL || sym->attr.flavor != FL_NAMELIST) { gfc_error ("Symbol '%s' at %C must be a NAMELIST group name", sym != NULL ? sym->name : name); return MATCH_ERROR; } dt->namelist = sym; if (k == M_READ && check_namelist (sym)) return MATCH_ERROR; return MATCH_YES; } m = match_etag (&tag_rec, &dt->rec); if (m != MATCH_NO) return m; m = match_out_tag (&tag_iomsg, &dt->iomsg); if (m != MATCH_NO) return m; m = match_out_tag (&tag_iostat, &dt->iostat); if (m != MATCH_NO) return m; m = match_ltag (&tag_err, &dt->err); if (m == MATCH_YES) dt->err_where = gfc_current_locus; if (m != MATCH_NO) return m; m = match_etag (&tag_advance, &dt->advance); if (m != MATCH_NO) return m; m = match_out_tag (&tag_size, &dt->size); if (m != MATCH_NO) return m; m = match_ltag (&tag_end, &dt->end); if (m == MATCH_YES) { if (k == M_WRITE) { gfc_error ("END tag at %C not allowed in output statement"); return MATCH_ERROR; } dt->end_where = gfc_current_locus; } if (m != MATCH_NO) return m; m = match_ltag (&tag_eor, &dt->eor); if (m == MATCH_YES) dt->eor_where = gfc_current_locus; if (m != MATCH_NO) return m; return MATCH_NO;}/* Free a data transfer structure and everything below it. */voidgfc_free_dt (gfc_dt * dt){ if (dt == NULL) return; gfc_free_expr (dt->io_unit); gfc_free_expr (dt->format_expr); gfc_free_expr (dt->rec); gfc_free_expr (dt->advance); gfc_free_expr (dt->iomsg); gfc_free_expr (dt->iostat); gfc_free_expr (dt->size); gfc_free (dt);}/* Resolve everything in a gfc_dt structure. */trygfc_resolve_dt (gfc_dt * dt){ gfc_expr *e; RESOLVE_TAG (&tag_format, dt->format_expr); RESOLVE_TAG (&tag_rec, dt->rec); RESOLVE_TAG (&tag_advance, dt->advance); RESOLVE_TAG (&tag_iomsg, dt->iomsg); RESOLVE_TAG (&tag_iostat, dt->iostat); RESOLVE_TAG (&tag_size, dt->size); e = dt->io_unit; if (gfc_resolve_expr (e) == SUCCESS && (e->ts.type != BT_INTEGER && (e->ts.type != BT_CHARACTER || e->expr_type != EXPR_VARIABLE))) { gfc_error ("UNIT specification at %L must be an INTEGER expression or a " "CHARACTER variable", &e->where); return FAILURE; } if (e->ts.type == BT_CHARACTER) { if (gfc_has_vector_index (e)) { gfc_error ("Internal unit with vector subscript at %L", &e->where); return FAILURE; } } if (e->rank && e->ts.type != BT_CHARACTER) { gfc_error ("External IO UNIT cannot be an array at %L", &e->where); return FAILURE; } if (dt->err) { if (gfc_reference_st_label (dt->err, ST_LABEL_TARGET) == FAILURE) return FAILURE; if (dt->err->defined == ST_LABEL_UNKNOWN) { gfc_error ("ERR tag label %d at %L not defined", dt->err->value, &dt->err_where); return FAILURE; } } if (dt->end) { if (gfc_reference_st_label (dt->end, ST_LABEL_TARGET) == FAILURE) return FAILURE; if (dt->end->defined == ST_LABEL_UNKNOWN) { gfc_error ("END tag label %d at %L not defined", dt->end->value, &dt->end_where); return FAILURE; } } if (dt->eor) { if (gfc_reference_st_label (dt->eor, ST_LABEL_TARGET) == FAILURE) return FAILURE; if (dt->eor->defined == ST_LABEL_UNKNOWN) { gfc_error ("EOR tag label %d at %L not defined", dt->eor->value, &dt->eor_where); return FAILURE; } } /* Check the format label actually exists. */ if (dt->format_label && dt->format_label != &format_asterisk && dt->format_label->defined == ST_LABEL_UNKNOWN) { gfc_error ("FORMAT label %d at %L not defined", dt->format_label->value, &dt->format_label->where); return FAILURE; } return SUCCESS;}/* Given an io_kind, return its name. */static const char *io_kind_name (io_kind k){ const char *name; switch (k) { case M_READ: name = "READ"; break; case M_WRITE: name = "WRITE"; break; case M_PRINT: name = "PRINT"; break; case M_INQUIRE: name = "INQUIRE"; break; default: gfc_internal_error ("io_kind_name(): bad I/O-kind"); } return name;}/* Match an IO iteration statement of the form: ( [<IO element> ,] <IO element>, I = <expr>, <expr> [, <expr> ] ) which is equivalent to a single IO element. This function is mutually recursive with match_io_element(). */static match match_io_element (io_kind k, gfc_code **);static matchmatch_io_iterator (io_kind k, gfc_code ** result){ gfc_code *head, *tail, *new; gfc_iterator *iter; locus old_loc; match m; int n; iter = NULL; head = NULL; old_loc = gfc_current_locus; if (gfc_match_char ('(') != MATCH_YES) return MATCH_NO; m = match_io_element (k, &head); tail = head; if (m != MATCH_YES || gfc_match_char (',') != MATCH_YES) { m = MATCH_NO; goto cleanup; } /* Can't be anything but an IO iterator. Build a list. */ iter = gfc_get_iterator (); for (n = 1;; n++) { m = gfc_match_iterator (iter, 0); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_YES) { gfc_check_do_variable (iter->var->symtree); break; } m = match_io_element (k, &new); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) { if (n > 2) goto syntax; goto cleanup; } tail = gfc_append_code (tail, new); if (gfc_match_char (',') != MATCH_YES) { if (n > 2) goto syntax; m = MATCH_NO; goto cleanup; } } if (gfc_match_char (')') != MATCH_YES) goto syntax; new = gfc_get_code (); new->op = EXEC_DO; new->ext.iterator = iter; new->block = gfc_get_code (); new->block->op = EXEC_DO; new->block->next = head; *result = new; return MATCH_YES;syntax: gfc_error ("Syntax error in I/O iterator at %C"); m = MATCH_ERROR;cleanup: gfc_free_iterator (iter, 1); gfc_free_statements (head); gfc_current_locus = old_loc; return m;}/* Match a single element of an IO list, which is either a single expression or an IO Iterator. */static matchmatch_io_element (io_kind k, gfc_code ** cpp){ gfc_expr *expr; gfc_code *cp; match m; expr = NULL; m = match_io_iterator (k, cpp); if (m == MATCH_YES) return MATCH_YES; if (k == M_READ) { m = gfc_match_variable (&expr, 0); if (m == MATCH_NO) gfc_error ("Expected variable in READ statement at %C"); } else { m = gfc_match_expr (&expr); if (m == MATCH_NO) gfc_error ("Expected expression in %s statement at %C", io_kind_name (k)); } if (m == MATCH_YES) switch (k) { case M_READ: if (expr->symtree->n.sym->attr.intent == INTENT_IN) { gfc_error ("Variable '%s' in input list at %C cannot be INTENT(IN)", expr->symtree->n.sym->name); m = MATCH_ERROR; } if (gfc_pure (NULL) && gfc_impure_variable (expr->symtree->n.sym) && current_dt->io_unit->ts.type == BT_CHARACTER) { gfc_error ("Cannot read to variable '%s' in PURE procedure at %C", expr->symtree->n.sym->name); m = MATCH_ERROR; } if (gfc_check_do_variable (expr->symtree)) m = MATCH_ERROR; break; case M_WRITE: if (current_dt->io_unit->ts.type == BT_CHARACTER && gfc_pure (NULL) && current_dt->io_unit->expr_type == EXPR_VARIABLE && gfc_impure_variable (current_dt->io_unit->symtree->n.sym)) { gfc_error ("Cannot write to internal file unit '%s' at %C inside a " "PURE procedure", current_dt->io_unit->symtree->n.sym->name); m = MATCH_ERROR; } break; default: break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -