Declare variables anywhere

Would be more comfortable, but probably less logical: One does not want to apply any implicit settings to the names which are imported from modules via use, as they should use the implicit settings of their defining module. Therefore, it makes sense to me to declare implicit whatever only after the module imports, and then it will be consistently applied to all variables declared further down.

1 Like

Hello, after my test, this does not seem to be a bug. Because j in the parent variable domain is not assigned an initial value, and it happens that the memory state of the program causes j = 2 in the parent variable domain, you can assign j in the block to other values, such as 4, you can prove this !

@kargl Here comes my demos:

program main_2

    integer :: i = 21, j
    
    print *, j
    
    block
        integer :: j    
        j = 4
    end block
    
    print *, j    

end program main_2

Itā€™s just that j in the parent variable domain has not been assigned an initial value, and its value happens to be 2. It is not the value of j in the block that affects it.

Links

Scope in BLOCK - END BLOCK (google.com)

I ran your code in the gcc bugzilla, but I still canā€™t understand that it is a bug.
It normally obeys the variable implicit declaration
.



@kargl From the different results of ifort and gfortran, I seem to understand what you mean, which is surprising!
It seems that ifort and gfortran have an ambiguity about implicit declarations containing block.

ā€¦ ā€¦ Picture display is also a way of presentation :lying_face:
Online Compiler: Compiler Explorer (godbolt.org)

program foo
    call block1
    print *
    call block2
    print *, "Normal exit."
end program foo
!
! For an implicitly declared variable (e.g., i and j here), the
! scope of the variable is from the inclusive scoping unit.  That
! is, 'j = 1' in block1 is implicitly declared to be in the
! namespace of block1.  In addition, the implicitly declared 'i'
! in block bah is also in the namespace of block1.
!
subroutine block1
    j = 1
    bah: block
        i = 42
        j = 42
    end block bah
    if (i /= 42) print *, 1, i  ! i should be 42
    if (j /= 42) print *, 2, j
end subroutine block1
!
! In the following 'i' has an implicit declaration in the scope
! of block2.  The explicit declaration of 'i' in block bah means
! that this 'i' has the scope of bah.
!
subroutine block2
    i = 1
    j = 1
    bah: block
        integer i
        i = 42
        j = 42
        if (i /= 42) print *, 3, i
        if (j /= 42) print *, 4, j
    end block bah
    if (i /= 1) print *, 5, i
    if (j /= 42) print *, 6, j
end subroutine block2

I have not yet seen a Fortran compiler that can compile source code displayed in a picture :wink: .

There is another way of saying that we should always write implicit none. When we do not write, the specific problems that arise may be determined by the compiler. (I donā€™t know. If anyone are interested, you can check the Fortran standard)

If there is a description in the standard that can prove that this is a bug, I think it is the best.
When the standard lacks instructions and different implementations of the compiler, it may not be a bug.

I just want to show that the results are different, nothing more. And forgot to post the source code. :flushed:

@zoziha ,

So, to add to your understanding, the bug in gfortran can be illustrated by the following 5-liner:

   block
      j = 42
   end block
   print *, "j = ", j, "; expected is 42"
end

C:\temp>gfortran p.f90 -o p.exe

C:\temp>p.exe
j = 1 ; expected is 42

Two other compilers work as expected:

  • Intel Fortran

C:\temp>ifort /standard-semantics /check:uninit p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.4.0 Build 20210910_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.

Microsoft (R) Incremental Linker Version 14.29.30040.0
Copyright (C) Microsoft Corporation. All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
j = 42 ; expected is 42

  • NAG Fortran

C:\temp>type p.f90
block
j = 42
end block
print *, "j = ", j, ā€œ; expected is 42ā€
end

C:\temp>nagfor p.f90 -o p.exe
NAG Fortran Compiler Release 7.0(Yurakucho) Build 7048
[NAG Fortran Compiler normal termination]

C:\temp>p.exe
j = 42 ; expected is 42

C:\temp>

1 Like

Although the results are inconsistent, I am not sure that this is a bug. Whoever is interested can consult the Fortran standard. After all, there are some attributes that can be determined by the compiler, such as:

  1. format ā€œ(g0)ā€
    Add format_string routine to format other types to strings by St-Maxwell Ā· Pull Request #444 Ā· fortran-lang/stdlib Ā· GitHub
  2. allocatable array in heap
    [stdlib_linalg] Add zeros, ones function. by zoziha Ā· Pull Request #478 Ā· fortran-lang/stdlib Ā· GitHub

To avoid this problem, we need now try to implicit none.

program main
    implicit none
    call block1
    call block2
    write(*,*)"exit"
end program main

subroutine block1
    implicit none
    integer::i,j
    j=1
    bah:block
        i=42
        j=42
    end block bah
    if(i/=42)write(*,*) '1',i
    if(j/=42)write(*,*) '2',j
end subroutine block1

subroutine block2
    implicit none
    integer::i,j
    i=1
    j=1
    bah:block
        integer::i
        i=42
        j=42
        if(i/=42)write(*,*) '3',i
        if(j/=42)write(*,*) '4',j
    end block bah
    if(i/=1)write(*,*)  '5',i
    if(j/=42)write(*,*) '6',j
end subroutine block2

Itā€™s a pity that almost 4 years and 3 major versions later it is still there, not fixed. Unless it is fixed in gcc 12 which I have no access to.

You donā€™t expect an ordinary Fortran (!) user to contribute to a compiler of ~1 million LOC written in C and (now mostly, as I read) C++, do you? :slight_smile:

I agree with @kargl on that. I am a physicist too and never had a compiler course either.

As a community we really have to start contributing to our open source compilers. There is no other way. Many people here already do.

All the open source Fortran compilers are written in C or C++. They differ in details how they are constructed.

However, if you want to contribute to a runtime library, the LFortranā€™s runtime library is written in Fortran. We are looking for contributors.

5 Likes

Things have to arrive soon at a stage where the Fortran compilers are bootstrapped in Fortran itself. This will lead to two immediate benefits:

  1. The number of contributors will increase considerably I predict, possibly even by orders of magnitude.
  2. There will be better appreciation for the needless, near asinine limitations in the language standard with various aspects (e.g., no built-in intrinsic string type) and there will be stronger support and direction to enhance the language.
2 Likes

Yeah, it would indeed help. But as I said, itā€™s hard enough to deliver a compiler in any language, so I chose the easiest path forward, which is C++ for me. If I did it in Fortran, I would fail.

Which books on compilers do the compiler writers recommend? The book by Aho et al. is famous but also 1000 pages long.

Yes, Flang and LFortran are written in a similar way, front end, middle end, backend.

For LFortran, the middle end representation is called ASR (Abstract Semantic Representation), and it has several backends, such as lowering to LLVM.

The frontend has a parser (currently using Bison) that creates an AST (or reports a syntax error), and then there is a layer that transforms AST to ASR, which collects all the errors and warnings.

The part that can possibly be in Fortran is the AST to ASR translation. The AST and ASR nodes are generated, so we could generate a Fortran representation. But it would still be only a small part of the compiler.

One could possibly write Fortran API for LLVM, and then also the ASR->LLVM could be in Fortran.

We could write a Fortran backend to Bison (lot of work) or create a new parser in pure Fortran (also a lot of work).

We could write a Fortran backend to re2c (lot of work), or write a tokenizer in Fortran.

But at some point, given that all the tools for compiler writing are in C or C++, itā€™s just better to stick to those languages and at least the whole compiler is written in one language, which has many engineering advantages. If itā€™s going to be a mix of C or C++ and Fortran, it only adds to the engineering complexity.

If we give up LLVM, LFortran also has a direct x86 (and weā€™ll add arm) backend. That one could be written in Fortran in principle. But it doesnā€™t do any optimizations, so itā€™s going to be slow to execute (but fast to compile).

And finally, there is performance of compilation. I have spent a lot of time ensuring the C++ implementation is very fast. We use a custom allocator, and allocate C style structs ourselves. I donā€™t know how to do that in Fortran. And so it is going to be slow. The rest of C++ language features that we use can probably be emulated with C macros (ugly, but it would do the job).

We could have an LFortran language extension that would allow to effectively deal with derived types using a linear allocator and also extend the language to do whatever else we need. We could even do it in some way so that the Fortran parts of the compiler still compiles with other compilers, but when recompiled with LFortran we would get the speed.

But this is no easy task, an order of magnitude larger than just using C++. My goal is to deliver a compiler, actually deliver. I have to focus on that.

If however there is anybody (such as you @FortranFan) that would like to work on it in Fortran, I am happy to generate the Fortran AST and ASR nodes in Fortran. I can figure out how to link with the C++ compiler, and maybe you can write an ASR->ASR optimization pass, in Fortran. I think that is doable (although as I said, it adds complexity to the compiler, but if there is community interest and weā€™ll get contributors, it might be worth it). Just let me know.

We have serialization and deserialization (automatically generated) for the ASR. So we could save it to a file, then we load it (in Fortran), do some optimization, and save it back to a file. That way it is independent of LFortran, and we can add hooks to execute some passes that way. Slower, but it would not be complicated (as long as it is optional, invoked with some command line option). If there is anybody interested, let me know.

Thanks ā€“ Holub has made his book and code available. It has 3.5 stars on Amazon.

1 Like

The compiler design book with the best Amazon rating is Cooper and Torczon, ā€œEngineering a Compiler, 2nd Editionā€. Its slightly shorter than Aho et alā€™s Dragon Book, and reputedly better organized.

3 Likes

The errata for ā€œEngineering a Compilerā€ is small but exists.
https://www.cs.rice.edu/~keith/Errata.html