Unterschied zwischen AST und ASR¶

Nehmen wir einen einfachen Fortran-Code:

integer function f(a, b) result(r)
integer, intent(in) :: a, b
integer :: c, d
c = a + b - d
r = c * a
end function


and look at what the AST and ASR look like.

AST¶

[1]:

%%showast
integer function f(a, b) result(r)
integer, intent(in) :: a, b
integer :: c, d
c = a + b - d
r = c * a
end function

(TranslationUnit
[(Function
f
[(a)
(b)]
[(AttrType
TypeInteger
[]
()
()
None
)]
r
()
()
[]
[]
[]
[(Declaration
(AttrType
TypeInteger
[]
()
()
None
)
[(AttrIntent
In
)]
[(a
[]
[]
()
None
())
(b
[]
[]
()
None
())]
()
)
(Declaration
(AttrType
TypeInteger
[]
()
()
None
)
[]
[(c
[]
[]
()
None
())
(d
[]
[]
()
None
())]
()
)]
[(=
0
c
(- (+ a b) d)
()
)
(=
0
r
(* c a)
()
)]
[]
[]
)]
)


Der AST enthält keine semantischen Informationen, hat aber Knoten zur Darstellung von Deklarationen wie integer, intent(in) :: a. Variablen wie a werden durch einen Name Knoten dargestellt und sind noch nicht mit ihren Deklarationen verbunden.

The AST can also be exported in JSON, including source file name, line and column information: lfortran example.f90 --show-ast --json

ASR¶

[2]:

%%showasr
integer function f(a, b) result(r)
integer, intent(in) :: a, b
integer :: c, d
c = a + b - d
r = c * a
end function

(TranslationUnit
(SymbolTable
1
{
f:
(Function
(SymbolTable
2
{
a:
(Variable
2
a
[]
In
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
),
b:
(Variable
2
b
[]
In
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
),
c:
(Variable
2
c
[]
Local
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
),
d:
(Variable
2
d
[]
Local
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
),
r:
(Variable
2
r
[]
ReturnVar
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
)
})
f
(FunctionType
[(Integer 4)
(Integer 4)]
(Integer 4)
Source
Implementation
()
.false.
.false.
.false.
.false.
.false.
[]
.false.
)
[]
[(Var 2 a)
(Var 2 b)]
[(=
(Var 2 c)
(IntegerBinOp
(IntegerBinOp
(Var 2 a)
Add
(Var 2 b)
(Integer 4)
()
)
Sub
(Var 2 d)
(Integer 4)
()
)
()
)
(=
(Var 2 r)
(IntegerBinOp
(Var 2 c)
Mul
(Var 2 a)
(Integer 4)
()
)
()
)]
(Var 2 r)
Public
.false.
.false.
()
)
})
[]
)


Die ASR enthält alle semantischen Informationen (Typen usw.), Knoten wie Function haben eine Symboltabelle und keine Deklarationsknoten. Variablen sind einfach Zeiger auf die Symboltabelle.

The ASR can also be exported in JSON, including source file name, line and column information: lfortran example.f90 --show-asr --json

Diskussion¶

Das obige Beispiel war ein einfaches. Bei komplizierteren Beispielen, wie z. B. dem folgenden, werden die Dinge deutlicher:

integer function f2b(a) result(r)
use gfort_interop, only: c_desc1_int32
integer, intent(in) :: a(:)
interface
integer function f2b_c_wrapper(a) bind(c, name="__mod1_MOD_f2b")
use gfort_interop, only: c_desc1_t
type(c_desc1_t), intent(in) :: a
end function
end interface
r = f2b_c_wrapper(c_desc1_int32(a))
end function


AST muss alle use Anweisungen und den interface Block repräsentieren und die Dinge semantisch konsistent halten.

ASR hingegen verfolgt die c_desc1_int32, c_desc1_t und f2b_c_wrapper in der Symboltabelle und weiß, dass sie im Modul gfort_interop definiert sind, so dass ASR keinen dieser Deklarationsknoten hat.

Bei der Konvertierung von ASR nach AST erstellt LFortran alle entsprechenden AST-Deklarationsknoten automatisch und korrekt.