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

y verifiquemos en que se parecen AST y ASR.

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) ())] [])])

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.

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 [] [(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) Source Public Implementation () .false. .false. .false. .false. .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.

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.