📄 io.c
字号:
switch (t) { case FMT_COMMA: goto format_item; case FMT_RPAREN: level--; if (level < 0) goto finished; goto between_desc; case FMT_COLON: case FMT_SLASH: goto optional_comma; case FMT_END: error = unexpected_end; goto syntax; default: if (gfc_notify_std (GFC_STD_GNU, "Extension: Missing comma at %C") == FAILURE) return FAILURE; goto format_item_1; }optional_comma: /* Optional comma is a weird between state where we've just finished reading a colon, slash or P descriptor. */ t = format_lex (); switch (t) { case FMT_COMMA: break; case FMT_RPAREN: level--; if (level < 0) goto finished; goto between_desc; default: /* Assume that we have another format item. */ saved_token = t; break; } goto format_item;extension_optional_comma: /* As a GNU extension, permit a missing comma after a string literal. */ t = format_lex (); switch (t) { case FMT_COMMA: break; case FMT_RPAREN: level--; if (level < 0) goto finished; goto between_desc; case FMT_COLON: case FMT_SLASH: goto optional_comma; case FMT_END: error = unexpected_end; goto syntax; default: if (gfc_notify_std (GFC_STD_GNU, "Extension: Missing comma at %C") == FAILURE) return FAILURE; saved_token = t; break; } goto format_item;syntax: /* Something went wrong. If the format we're checking is a string, generate a warning, since the program is correct. If the format is in a FORMAT statement, this messes up parsing, which is an error. */ if (mode != MODE_STRING) gfc_error ("%s in format string at %C", error); else { gfc_warning ("%s in format string at %C", error); /* TODO: More elaborate measures are needed to show where a problem is within a format string that has been calculated. */ } rv = FAILURE;finished: return rv;}/* Given an expression node that is a constant string, see if it looks like a format string. */static voidcheck_format_string (gfc_expr * e){ mode = MODE_STRING; format_string = e->value.character.string; check_format ();}/************ Fortran 95 I/O statement matchers *************//* Match a FORMAT statement. This amounts to actually parsing the format descriptors in order to correctly locate the end of the format string. */matchgfc_match_format (void){ gfc_expr *e; locus start; if (gfc_current_ns->proc_name && gfc_current_ns->proc_name->attr.flavor == FL_MODULE) { gfc_error ("Format statement in module main block at %C."); return MATCH_ERROR; } if (gfc_statement_label == NULL) { gfc_error ("Missing format label at %C"); return MATCH_ERROR; } gfc_gobble_whitespace (); mode = MODE_FORMAT; format_length = 0; start = gfc_current_locus; if (check_format () == FAILURE) return MATCH_ERROR; if (gfc_match_eos () != MATCH_YES) { gfc_syntax_error (ST_FORMAT); return MATCH_ERROR; } /* The label doesn't get created until after the statement is done being matched, so we have to leave the string for later. */ gfc_current_locus = start; /* Back to the beginning */ new_st.loc = start; new_st.op = EXEC_NOP; e = gfc_get_expr(); e->expr_type = EXPR_CONSTANT; e->ts.type = BT_CHARACTER; e->ts.kind = gfc_default_character_kind; e->where = start; e->value.character.string = format_string = gfc_getmem(format_length+1); e->value.character.length = format_length; gfc_statement_label->format = e; mode = MODE_COPY; check_format (); /* Guaranteed to succeed */ gfc_match_eos (); /* Guaranteed to succeed */ return MATCH_YES;}/* Match an expression I/O tag of some sort. */static matchmatch_etag (const io_tag * tag, gfc_expr ** v){ gfc_expr *result; match m; m = gfc_match (tag->spec, &result); if (m != MATCH_YES) return m; if (*v != NULL) { gfc_error ("Duplicate %s specification at %C", tag->name); gfc_free_expr (result); return MATCH_ERROR; } *v = result; return MATCH_YES;}/* Match a variable I/O tag of some sort. */static matchmatch_vtag (const io_tag * tag, gfc_expr ** v){ gfc_expr *result; match m; m = gfc_match (tag->spec, &result); if (m != MATCH_YES) return m; if (*v != NULL) { gfc_error ("Duplicate %s specification at %C", tag->name); gfc_free_expr (result); return MATCH_ERROR; } if (result->symtree->n.sym->attr.intent == INTENT_IN) { gfc_error ("Variable tag cannot be INTENT(IN) at %C"); gfc_free_expr (result); return MATCH_ERROR; } if (gfc_pure (NULL) && gfc_impure_variable (result->symtree->n.sym)) { gfc_error ("Variable tag cannot be assigned in PURE procedure at %C"); gfc_free_expr (result); return MATCH_ERROR; } *v = result; return MATCH_YES;}/* Match I/O tags that cause variables to become redefined. */static matchmatch_out_tag(const io_tag *tag, gfc_expr **result){ match m; m = match_vtag(tag, result); if (m == MATCH_YES) gfc_check_do_variable((*result)->symtree); return m;}/* Match a label I/O tag. */static matchmatch_ltag (const io_tag * tag, gfc_st_label ** label){ match m; gfc_st_label *old; old = *label; m = gfc_match (tag->spec, label); if (m == MATCH_YES && old != 0) { gfc_error ("Duplicate %s label specification at %C", tag->name); return MATCH_ERROR; } return m;}/* Do expression resolution and type-checking on an expression tag. */static tryresolve_tag (const io_tag * tag, gfc_expr * e){ if (e == NULL) return SUCCESS; if (gfc_resolve_expr (e) == FAILURE) return FAILURE; if (e->ts.type != tag->type && tag != &tag_format) { gfc_error ("%s tag at %L must be of type %s", tag->name, &e->where, gfc_basic_typename (tag->type)); return FAILURE; } if (tag == &tag_format) { if (e->expr_type == EXPR_CONSTANT && (e->ts.type != BT_CHARACTER || e->ts.kind != gfc_default_character_kind)) { gfc_error ("Constant expression in FORMAT tag at %L must be " "of type default CHARACTER", &e->where); return FAILURE; } /* If e's rank is zero and e is not an element of an array, it should be of integer or character type. The integer variable should be ASSIGNED. */ if (e->symtree == NULL || e->symtree->n.sym->as == NULL || e->symtree->n.sym->as->rank == 0) { if (e->ts.type != BT_CHARACTER && e->ts.type != BT_INTEGER) { gfc_error ("%s tag at %L must be of type %s or %s", tag->name, &e->where, gfc_basic_typename (BT_CHARACTER), gfc_basic_typename (BT_INTEGER)); return FAILURE; } else if (e->ts.type == BT_INTEGER && e->expr_type == EXPR_VARIABLE) { if (gfc_notify_std (GFC_STD_F95_DEL, "Obsolete: ASSIGNED variable in FORMAT tag at %L", &e->where) == FAILURE) return FAILURE; if (e->symtree->n.sym->attr.assign != 1) { gfc_error ("Variable '%s' at %L has not been assigned a " "format label", e->symtree->n.sym->name, &e->where); return FAILURE; } } return SUCCESS; } else { /* if rank is nonzero, we allow the type to be character under GFC_STD_GNU and other type under GFC_STD_LEGACY. It may be assigned an Hollerith constant. */ if (e->ts.type == BT_CHARACTER) { if (gfc_notify_std (GFC_STD_GNU, "Extension: Character array in FORMAT tag at %L", &e->where) == FAILURE) return FAILURE; } else { if (gfc_notify_std (GFC_STD_LEGACY, "Extension: Non-character in FORMAT tag at %L", &e->where) == FAILURE) return FAILURE; } return SUCCESS; } } else { if (e->rank != 0) { gfc_error ("%s tag at %L must be scalar", tag->name, &e->where); return FAILURE; } if (tag == &tag_iomsg) { if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: IOMSG tag at %L", &e->where) == FAILURE) return FAILURE; } if (tag == &tag_iostat && e->ts.kind != gfc_default_integer_kind) { if (gfc_notify_std (GFC_STD_GNU, "Fortran 95 requires default " "INTEGER in IOSTAT tag at %L", &e->where) == FAILURE) return FAILURE; } if (tag == &tag_size && e->ts.kind != gfc_default_integer_kind) { if (gfc_notify_std (GFC_STD_GNU, "Fortran 95 requires default " "INTEGER in SIZE tag at %L", &e->where) == FAILURE) return FAILURE; } if (tag == &tag_convert) { if (gfc_notify_std (GFC_STD_GNU, "Extension: CONVERT tag at %L", &e->where) == FAILURE) return FAILURE; } } return SUCCESS;}/* Match a single tag of an OPEN statement. */static matchmatch_open_element (gfc_open * open){ match m; m = match_etag (&tag_unit, &open->unit); if (m != MATCH_NO) return m; m = match_out_tag (&tag_iomsg, &open->iomsg); if (m != MATCH_NO) return m; m = match_out_tag (&tag_iostat, &open->iostat); if (m != MATCH_NO) return m; m = match_etag (&tag_file, &open->file); if (m != MATCH_NO) return m; m = match_etag (&tag_status, &open->status); if (m != MATCH_NO) return m; m = match_etag (&tag_e_access, &open->access); if (m != MATCH_NO) return m; m = match_etag (&tag_e_form, &open->form); if (m != MATCH_NO) return m; m = match_etag (&tag_e_recl, &open->recl); if (m != MATCH_NO) return m; m = match_etag (&tag_e_blank, &open->blank); if (m != MATCH_NO) return m; m = match_etag (&tag_e_position, &open->position); if (m != MATCH_NO) return m; m = match_etag (&tag_e_action, &open->action); if (m != MATCH_NO) return m; m = match_etag (&tag_e_delim, &open->delim); if (m != MATCH_NO) return m; m = match_etag (&tag_e_pad, &open->pad); if (m != MATCH_NO) return m; m = match_ltag (&tag_err, &open->err); if (m != MATCH_NO) return m; m = match_etag (&tag_convert, &open->convert); if (m != MATCH_NO) return m; return MATCH_NO;}/* Free the gfc_open structure and all the expressions it contains. */voidgfc_free_open (gfc_open * open){ if (open == NULL) return; gfc_free_expr (open->unit); gfc_free_expr (open->iomsg); gfc_free_expr (open->iostat); gfc_free_expr (open->file); gfc_free_expr (open->status); gfc_free_expr (open->access); gfc_free_expr (open->form); gfc_free_expr (open->recl); gfc_free_expr (open->blank); gfc_free_expr (open->position); gfc_free_expr (open->action); gfc_free_expr (open->delim); gfc_free_expr (open->pad); gfc_free_expr (open->convert); gfc_free (open);}/* Resolve everything in a gfc_open structure. */trygfc_resolve_open (gfc_open * open){ RESOLVE_TAG (&tag_unit, open->unit); RESOLVE_TAG (&tag_iomsg, open->iomsg); RESOLVE_TAG (&tag_iostat, open->iostat); RESOLVE_TAG (&tag_file, open->file); RESOLVE_TAG (&tag_status, open->status); RESOLVE_TAG (&tag_e_access, open->access); RESOLVE_TAG (&tag_e_form, open->form); RESOLVE_TAG (&tag_e_recl, open->recl); RESOLVE_TAG (&tag_e_blank, open->blank); RESOLVE_TAG (&tag_e_position, open->position); RESOLVE_TAG (&tag_e_action, open->action); RESOLVE_TAG (&tag_e_delim, open->delim); RESOLVE_TAG (&tag_e_pad, open->pad); RESOLVE_TAG (&tag_convert, open->convert); if (gfc_reference_st_label (open->err, ST_LABEL_TARGET) == FAILURE) return FAILURE; return SUCCESS;}/* Match an OPEN statement. */matchgfc_match_open (void){ gfc_open *open; match m; m = gfc_match_char ('('); if (m == MATCH_NO) return m; open = gfc_getmem (sizeof (gfc_open)); m = match_open_element (open); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) { m = gfc_match_expr (&open->unit); if (m == MATCH_NO) goto syntax; if (m == MATCH_ERROR) goto cleanup; } for (;;) { if (gfc_match_char (')') == MATCH_YES) break; if (gfc_match_char (',') != MATCH_YES) goto syntax; m = match_open_element (open); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) goto syntax; } if (gfc_match_eos () == MATCH_NO) goto syntax; if (gfc_pure (NULL)) { gfc_error ("OPEN statement not allowed in PURE procedure at %C"); goto cleanup; } new_st.op = EXEC_OPEN; new_st.ext.open = open; return MATCH_YES;syntax: gfc_syntax_error (ST_OPEN);cleanup: gfc_free_open (open); return MATCH_ERROR;}/* Free a gfc_close structure an all its expressions. */voidgfc_free_close (gfc_close * close){ if (close == NULL) return; gfc_free_expr (close->unit); gfc_free_expr (close->iomsg); gfc_free_expr (close->iostat); gfc_free_expr (close->status); gfc_free (close);}/* Match elements of a CLOSE statement. */static matchmatch_close_element (gfc_close * close){ match m; m = match_etag (&tag_unit, &close->unit); if (m != MATCH_NO) return m; m = match_etag (&tag_status, &close->status); if (m != MATCH_NO) return m; m = match_out_tag (&tag_iomsg, &close->iomsg); if (m != MATCH_NO) return m; m = match_out_tag (&tag_iostat, &close->iostat); if (m != MATCH_NO) return m; m = match_ltag (&tag_err, &close->err); if (m != MATCH_NO) return m; return MATCH_NO;}/* Match a CLOSE statement. */matchgfc_match_close (void){ gfc_close *close; match m; m = gfc_match_char ('('); if (m == MATCH_NO) return m; close = gfc_getmem (sizeof (gfc_close)); m = match_close_element (close); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) { m = gfc_match_expr (&close->unit); if (m == MATCH_NO) goto syntax; if (m == MATCH_ERROR) goto cleanup; } for (;;) { if (gfc_match_char (')') == MATCH_YES) break; if (gfc_match_char (',') != MATCH_YES) goto syntax; m = match_close_element (close); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) goto syntax; } if (gfc_match_eos () == MATCH_NO) goto syntax; if (gfc_pure (NULL)) { gfc_error ("CLOSE statement not allowed in PURE procedure at %C"); goto cleanup; } new_st.op = EXEC_CLOSE; new_st.ext.close = close; return MATCH_YES;syntax: gfc_syntax_error (ST_CLOSE);cleanup: gfc_free_close (close); return MATCH_ERROR;}/* Resolve everything in a gfc_close structure. */trygfc_resolve_close (gfc_close * close){ RESOLVE_TAG (&tag_unit, close->unit); RESOLVE_TAG (&tag_iomsg, close->iomsg); RESOLVE_TAG (&tag_iostat, close->iostat); RESOLVE_TAG (&tag_status, close->status); if (gfc_reference_st_label (close->err, ST_LABEL_TARGET) == FAILURE) return FAILURE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -