Diferencias entre un AST y una ASR¶
Tomemos un código Fortran simple:
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
())]
()
)]
[(Assignment
0
c
(- (+ a b) d)
()
)
(Assignment
0
r
(* c a)
()
)]
[]
[]
)]
)
El AST no tiene información semántica, pero tiene nodos para representar declaraciones tales como integer, intent(in) :: a
. Variables tales como a
son representadas por un nodo Name
, y aún no están conectadas a sus declaraciones.
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.
.false.
),
b:
(Variable
2
b
[]
In
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
.false.
),
c:
(Variable
2
c
[]
Local
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
.false.
),
d:
(Variable
2
d
[]
Local
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
.false.
),
r:
(Variable
2
r
[]
ReturnVar
()
()
Default
(Integer 4)
()
Source
Public
Required
.false.
.false.
)
})
f
(FunctionType
[(Integer 4)
(Integer 4)]
(Integer 4)
Source
Implementation
()
.false.
.false.
.false.
.false.
.false.
[]
.false.
)
[]
[(Var 2 a)
(Var 2 b)]
[(Assignment
(Var 2 c)
(IntegerBinOp
(IntegerBinOp
(Var 2 a)
Add
(Var 2 b)
(Integer 4)
()
)
Sub
(Var 2 d)
(Integer 4)
()
)
()
)
(Assignment
(Var 2 r)
(IntegerBinOp
(Var 2 c)
Mul
(Var 2 a)
(Integer 4)
()
)
()
)]
(Var 2 r)
Public
.false.
.false.
()
)
})
[]
)
La ASR tiene toda la información semántica (tipos, etc.), nodos como Function
tienen una tabla de símbolos y no tienen ningún nodo de declaración. Variables son únicamente punteros para la tabla de símbolos.
The ASR can also be exported in JSON, including source file name, line and column information: lfortran example.f90 --show-asr --json
Discusión¶
El anterior fué un ejemplo simple. Las cosas se vuelven mas evidentes para ejemplos más complicados, tales como:
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 puede representar todos las declaraciones use
y el bloque interface
, y mantiene las cosas semánticamente consistentes.
ASR, por otro lado, realiza un seguimiento de c_desc1_int32
, c_desc1_t
y f2b_c_wrapper
en la tabla de símbolos y sabe que están definidos en el módulo gfort_interop
, y así ASR no tiene ninguno de estos nodos de declaración.
Al convertir de ASR a AST, LFortran creará automática y correctamente todos los nodos de declaración AST apropiados.