See /src/grammar/for90.y for all accepted grammar
- You can rename keyword parameter in
interface
block - You can use anonymous grammar structures
- Declaration/specification is not forced before any other statements According to Fortran standard, declaration/specification(sudh as variable declarations and interfaces) statements must before all executable constructs(2.3.1) However, there's no such restriction in this translator
All implied-do will be translated in to struct ImpliedDo
:
ImpliedDo(int D, fsize_t * fr, fsize_t * to, F func )
- This implied-do loop has
D
layers, the outmost layer is layer 0, the innermost layer is layer (D - 1) - Layer
i
loops in range[fr[i], to[i]]
F func
should have signature like[&](fsize_t * current){return X}
, wherecurrent
points to a sizeD
array giving current index of each loop layer
R916 io-implied-do is ( io-implied-do-object-list , io-implied-do-control ) R917 io-implied-do-object is input-item or output-item R918 io-implied-do-control is do-variable = scalar-numeric-expr , scalar-numeric-expr [ , scalar-numeric-expr ]
io-implied-do will also be translated into a ImpliedDo
, for details of this struct ref implied-do
auto make_implieddo(const fsize_t(&_lb)[D], const fsize_t(&_to)[D], F func);
auto make_implieddo(fsize_t * _lb, fsize_t * _to, F func);
For input function like forreadfree
and forread
, the io-implied-do-object-list
must be a variable(R914), so F f
must return left-value.
For output function like forwritefree
and forwrite
, the io-implied-do-object-list
must be a expr(R915), so F f
can return anything.
Here is a simple Fortran's io-implied-do demo
WRITE(2,*) ((A(I,J),B(I),J=1,i),I=2,10)
And this will be transformed into
forwritefree(get_file(2), make_implieddo({2}, {10}, [&](const fsize_t * current_i){
return [&](fsize_t i){
return make_implieddo({i, 1}, {i, i}, [&](const fsize_t * current_j){
return [&](fsize_t i, fsize_t j){
return make_iostuff(make_tuple(a(INOUT(i), INOUT(j)), b(INOUT(i))));
}(current_j[0], current_j[1]);
});
}(current_i[0]);
}));
To understand this code, several stuffs are worth learning:
IOStuff
wraps a list of input-item-list
or output-item-list
inside an io-implied-do.
IOStuff
can be built from a std::tuple
, with make_iostuff
template<typename ... Types>
IOStuff<Types...> make_iostuff(const std::tuple<Types...> & _tp) {
return IOStuff<Types...>(_tp);
}
Read/write a IOStuff
is to read/write every element of IOStuff
in order
IOFormat has basic form, IOFormat(const std::string & s, int rev_start, int rev_end)
, in which rev_start
and rev_end
is optional.
-
formatter
is generated from Fortran's format -
reversion_start
is a value computed by compiler, it shows index of beginning of the repeat string (ref. 10.3), whilereversion_end
shows this end of repeat string
WRITE(2,"(I)\n") 1,2,3,4,5
Will be translated into
forwrite(get_file(2), IOFormat{"%d", 0, 2}, 1, 2, 3, 4, 5);
See brief/array.md
Fortran | C++ |
---|---|
INTEGER(unspecified kind) | int |
INTEGER(kind = 1) | int8_t |
INTEGER(kind = 2) | int16_t |
INTEGER(kind = 8) | int32_t |
INTEGER(kind = 1) | int64_t |
REAL(unspecified kind) | double |
REAL(kind <= 4) | float |
REAL(kind = 4) | double |
REAL(kind = 8) | long double |
LOGICAL | bool |
COMPLEX | struct forcomplex |
CHARACTER | std::string |
array | farray<T> |
Fortran | C++ |
---|---|
INTEGER() |
to_int |
REAL() |
to_double |
FLOAT() |
to_double |
LOGICAL() |
to_bool |
COMPLEX() |
to_forcomplex |
CHAR() |
to_string |
- Variable names in Fortran are case-insensitive, and their names will be translated into lower case.
- Variable names that conflicts with C++ keywords and standard library functions will be renamed with a
R_
surfix
Common blocks, can be accessed by any of the scoping units in an executable program
Common statement | C++ |
---|---|
INTEGER::A; COMMON A |
int & a = G.a |
INTEGER::B; COMMON /COMMON_NAME/ B |
int & b = COMMON_NAME.b |
COMMON C |
T & c = G.c |
COMMON /COMMON_NAME/ D |
T & c = COMMON_NAME.c |
Where T conform to Fortran's implicit type deduction(refer Fortran 77 standard support for detail) Each commom block will be create a singleton struct
struct{
T1 _1;
T2 _2;
/* common variables */
}COMMON_NAME;
If this common block is an unamed block, COMMON_NAME
is by default G
- Remove all definition of local variables which is also in parameter list
- Optional parameter: instead of c-style optional parameter, wrap optional parameters with
foroptional<T>
, functionforpresent
functions aspresent
function in Fortran90 - Keyword/named parameter: C++ don't support keyword parameters, all keyword parameter will be reorganized in normal paramtable
"functions" delcared in interface will be generated as a std::function<...>
clause
For example
subroutine proc(a, b, fun)
interface
function fun(x,y) result (fun_result)
integer,intent(in)::x, y
integer::fun_result
end function
end interface
integer,intent(in)::a, b
print *, fun(a, b)
end subroutine
Will be translated into
void proc(const int & a, const int & b, std::function<int(const int &, const int &)> fun)
{
forprintfree(fun(INOUT(a), INOUT(b)));
return ;
}
The INTENT (IN) attribute specifies that the dummy argument must not be redefined or become undefined during the execution of the procedure.
The INTENT (OUT) attribute specifies that the dummy argument must be defined before a reference to the dummy argument is made within the procedure and any actual argument that becomes associated with such a dummy argument must be definable. On invocation of the procedure, such a dummy argument becomes undefined.
The INTENT (INOUT) attribute specifies that the dummy argument is intended for use both to receive data from and to return data to the invoking scoping unit. Any actual argument that becomes associated with such a dummy argument must be definable.
If no INTENT attribute is specified for a dummy argument, its use is subject to the limitations of the associated actual argument (12.5.2.1, 12.5.2.2, 12.5.2.3).
The intent
, parameter
, save
specification generate codes following rules:
Intent | Parameter | Save | C++ | Argument passing pattern |
---|---|---|---|---|
/ | / | / | T && |
INOUT(v) |
any | / | save | static |
INOUT(v) |
any | parameter | save | static const |
INOUT(v) |
any | parameter | / | const T |
INOUT(v) |
in | any | / | const T & |
INOUT(v) |
out | any | / | T & |
INOUT(v) |
inout | any | / | T && |
INOUT(v) |
By implementation, INOUT(v)
is simply std::move(v)
, it just convert a T &
to T &&
, so it can be accepted by a T &&
function. You must make sure v
will not be destructed before you no long need it and v
is an left value before you use &(INOUT(v))
.
Currently, all arguments are passed by pattern INOUT
-
According to R311, defined operators should have NO digits in their names
This rule is necessary, considering
2.e2.0
is float, not a operatore2
with two operands2
and0
Fortran intrinsic operators | C++ |
---|---|
.and. |
&& |
.or. |
` |
.eqv. |
!(A^B) |
.neqv. |
^ |
.eq. |
== |
.neq. |
!= |
.gt. |
> |
.ge. |
>= |
.lt. |
< |
.le. |
<= |
CFortranTranslator can accept both fixed form and free form code.
CFortranTranslator WON'T handle fixed/free part of the code respectively
-
Comments(ref 3.3.2.1 Fixed form commentary)
Under any condition lines begin with
C
orc
are comments -
Continuation(ref 3.3.2.3 Fixed form statement continuation)
THIS DO NOT CONFORM TO FORTRAN90 STANDARD
Under any condition lines is continuation when
- Begin with 5 BLANKS(not in standard) and position 6 is not blank, or,
- (Not in standard)Begin with 1 TAB(in this case 1 TAB can consider to be equal to 5 blanks) and the next character is not blank or TAB
All implicit variables will have their definitions generated in target code. Because of the 3-phase strategy
Not all parameters in a paramtable
need to be declared explicitly in the function body, if the parameter
-
Used in both
paramtable
and the function bodyFortran 90 standard
-
Used only in
paramtable
Implicit definition conforming to Fortran77 standard
Fortran77 does not specify intent, target code will follow the strategy:
Fortran | C++ |
---|---|
literals(right value) | T && |
left value | T & |
Fortran | C++ |
---|---|
min |
min_n |
max |
max_n |
Fortran | C++ |
---|---|
* | stdin /stdout |
5 | stdin |
6 | stdout |
id | get_file(id) |
string | |
Fortran | C++ |
---|---|
open |
foropenfile |
close |
forclosefile |
rewind |
forrewind |
backspace |
forbackspace |
Fortran | C++ |
---|---|
* and (*,*) |
forscanfree /forprintfree |
(*,formatter) |
forscan /forprint |
(device_id,*) |
forreadfree /forwritefree |
(device_id,formatter) |
forread /forwrite |