next up previous Project Oscar

Next: Ecriture des grammaires attribuées Up: Exemple d'utilisation du système

Previous: Analyse syntaxique et recouvrement

Ecriture des grammaires attribuées pour l'analyse sémantique

Lorsque les erreurs signalées par les constructeurs de la partie lexico-syntaxique ont été corrigées, on peut commencer à écrire les diverses gramaires attribuées pour l'analyse sémantique.

La grammaire attribuée concernant les vérifications sémantiques sur le langage SIMPROC, est contenue dans le fichier ag_simproc-check.olga. Nous trouvons sa description ci-dessous.

attribute grammar simproc-check (simproc-in in PROGRAM;
                                 simproc-out out PROGRAM) : ($correct:bool) is

from simproc-types import all ;

attribute

{Attributs de travail}
{====================}
    compound $temp-st (BLOCK, DECLS, DECL) : symbol-table ;
    synthesized $correct1 (BLOCK, DECLS, DECL) : bool ;
    synthesized $correct2 (BLOCK, DECLS, DECL, STMT,
                           STMTS, EXPR, VAR, NUMBER) : bool ;
{Attributs exportés}
    synthesized $value () ;
    synthesized $op () ;
    global $symtab () { symbol-table} ;
    synthesized $correct () ;

{Les règles sémantiques}
{======================}

{Programme et bloc}
{=================}
where program -> BLOCK use
    $correct := $correct1 (BLOCK) & $correct2 (BLOCK) ;
    $h.temp-st (BLOCK) := empty-table ;
    $symtab (BLOCK) := $s.temp-st (BLOCK) ;
end where ;

where null-PROGRAM -> use
    $correct := false ;
end where ;

where block -> DECLS STMTS use
    $correct1 := $correct1 (DECLS) ;
    $correct2 := $correct2 (DECLS) &
		 $correct2 (STMTS) ;
    $s.temp-st := $s.temp-st (DECLS) ;
end where ;

where null-BLOCK -> use
    $correct1 := false ;
    $correct2 := false ;
end where ;

{Declarations}
{=============}
where decls -> DECL* use
    $correct1 := map left &
		     value true
		     other $correct1 (DECL)
		 end map ;
    $correct2 := map left &
		     value true
		     other $correct2 (DECL)
		 end map ;
    $h.temp-st (DECL) :=
			 {cette definition sert a donner un exemple pour
                           la construction <<case position>>; Elle aurait
                           pu etre generee automatiquement par les regles
                           par defaut}
			 case position is
			     first	: $h.temp-st ;
			     other	: $s.temp-st (DECL.left) ;
			 end case ;
end where ;

where null-DECLS -> use
    $correct1 := false ;
    $correct2 := false ;
end where ;

where int-decl -> ID declare
value
    correct : bool := if  $id (ID) = error-token then
			  false
		      elsif lookup-in-block ($id (ID),
					     $h.temp-st) then
			  message "Identifier already declared."
			  position ID
			  severity 2
			  value false
		      else
			  true
		      end if ;
use
    $correct1 := correct ;
    $correct2 := true ;
    $s.temp-st := if  correct then
		      insert ($id (ID),
			      varid,
			      $h.temp-st)
		  else
		      $h.temp-st
		  end if ;
end where ;

where array-decl -> ID NUMBER declare
value
    correct : bool := (if  $id (ID) = error-token then
			   false
		       elsif lookup-in-block ($id (ID),
					      $h.temp-st) then
			   message "Identifier already declared."
			   position ID
			   severity 2
			   value false
		       else
			   true
		       end if)
		       &
		      ($correct2 (NUMBER) and
		       if  int (string ($value (NUMBER))) = 0 then
			   message "Size cannot be null"
			   position NUMBER
			   severity 2
			   value false
		       else
			   true
		       end if)
		       ;
use
    $correct1 := correct ;
    $correct2 := true ;
    $s.temp-st := if  correct then
		      insert ($id (ID),
			      arrayid,
			      $h.temp-st)
		  else
		      $h.temp-st
		  end if ;
end where ;

where proc-decl -> ID1 ID2 ID3 BLOCK declare
value
    correct : bool := (if  $id (ID1) = error-token then
			   false
		       elsif lookup-in-block ($id (ID1),
					      $h.temp-st) then
			   message "Identifier already declared."
			   position ID.1
			   severity 2
			   value false
		       else
			   true
		       end if)
		       &
		      (if  ($id (ID2) = error-token)
			    or
			   ($id (ID3) = error-token)
			    then
			   false
		       elsif $id (ID2) = $id (ID3) then
			   message "Formal parameters may not have the same name."
			   position ID.3
			   severity 2
			   value false
		       else
			   true
		       end if)
		       ;
use
    $correct1 := correct ;
    $correct2 := $correct1 (BLOCK) &
		 $correct2 (BLOCK) ;
    $s.temp-st := if  correct then
		      insert ($id (ID1),
			      procid,
			      $h.temp-st)
		  else
		      $h.temp-st
		  end if ;
    $h.temp-st (BLOCK) := insert ($id (ID3),
				  refid,
				  insert ($id (ID2),
					  varid,
					  enter-block ($symtab [BLOCK]))) ;
    $symtab (BLOCK) := $s.temp-st (BLOCK) ;
end where ;

where null-DECL -> use
    $correct1 := false ;
    $correct2 := false ;
end where ;

{Instructions}
{============}
where stmt-list -> STMT+ use
    $correct2 := map left &
		     value true
		     other $correct2 (STMT)
		 end map ;
end where ;

where assign -> VAR EXPR use
    $correct2 := $correct2 (VAR) &
		 $correct2 (EXPR) ;
end where ;

where ifthenelse -> EXPR1 EXPR2 STMTS1 STMTS2 use
    $correct2 := $correct2 (EXPR1) &
		 $correct2 (EXPR2) &
		 $correct2 (STMTS1) &
		 $correct2 (STMTS2) ;
end where ;

where call -> ID EXPR VAR declare
value
    mode : mode := lookup ($id (ID),
			   $symtab [BLOCK]) ;
use
    $correct2 := (if  $id (ID) = error-token then
		      false
		  else
		      if  mode = error-mode then
			  message "Undeclared identifier."
			  position ID
			  severity 2
			  value false
		      elsif mode != procid then
			  message "Not a procedure."
			  position ID
			  severity 2
			  value false
		      else
			  true
		      end if
		  end if)
		  &
		 $correct2 (EXPR) &
		 $correct2 (VAR) ;
end where ;

where null-STMT -> use
    $correct2 := false ;
end where ;

where null-STMTS -> use
    $correct2 := false ;
end where ;

{Expressions et operateurs}
{=========================}
where bin-expr -> OP EXPR1 EXPR2 use
    $correct2 := $correct2 (EXPR1) &
		 $correct2 (EXPR2) &
		 $op (OP) != wrong-op ;
end where ;

where constant -> NUMBER use
end where ;

where used-var -> VAR use
end where ;

where null-EXPR -> use
    $correct2 := false ;
end where ;

where plus -> use
    $op := addition ;
end where ;

where minus -> use
    $op := subtraction ;
end where ;

where mul -> use
    $op := multiplication ;
end where ;

where div -> use
    $op := division ;
end where ;

where null-OP -> use
    $op := wrong-op ;
end where ;


{Variables}
{=========}
where null-VAR -> use
    $correct2 := false ;
end where ;

where simple-var -> ID use
    $correct2 := if  $id (ID) = error-token then
		     false
		 else
		     let
			 mode : mode := lookup ($id (ID),
						$symtab [BLOCK])
		     in
		     if	 mode = error-mode then
			 message "Undeclared identifier."
			 position ID
			 severity 2
			 value false
		     elsif (mode = varid)
			    or
			   (mode = refid)
			    then
			 true
		     else
			 message "Not a variable."
			 position ID
			 severity 2
			 value false
		     end if
		 end if ;
end where ;

where indexed-var -> ID EXPR use
    $correct2 := (if  $id (ID) = error-token then
		      false
		  else
		      let
			  mode : mode := lookup ($id (ID),
						 $symtab [BLOCK])
		      in
		      if  mode = error-mode then
			  message "Undeclared identifier."
			  position ID
			  severity 2
			  value false
		      elsif mode != arrayid then
			  message "Not an array."
			  position ID
			  severity 2
			  value false
		      else
			  true
		      end if
		  end if)
		  &
		 $correct2 (EXPR) ;
end where ;


{Nombres}
{=======}
where number -> use
    $correct2 := $text != error-token ;
    $value := if  $text = error-token then
		  token (string (0))
	      else
		  $text
	      end if ;
end where ;

where null-NUMBER -> use
    $correct2 := false ;
    $value := token (string (0)) ;
end where ;

where id -> use
end where ;

where null-ID -> use
end where ;

end grammar ;

Le module de déclaration de la grammaire précédente, se trouvre dans le fichier dec_simproc-check.olga. Il est donné ci-dessous :

declaration module simproc-check is

import grammar simproc-in;

function simproc-check (r:PROGRAM; r1:PROGRAM) : bool;

end module;

La grammaire simproc-check importe un module qui implémente une table de symboles, avec les fonctions de manipulation de cette table. Nous donnons ci-dessous, le contenu de ce module (fichier def_simproc-types.olga), ainsi que le contenu de son module de déclaration (fichier dec_simproc-types.olga).

definition module simproc-types is

{Implementation d'une table de symboles utilisant une liste lineaire}
{===================================================================}

const
    empty-table := symbol-table (block-element ()) ;
    offset-undefined := 0 ;
    error-element := element (error-token,
			      error-mode,
			      offset-undefined) ;

function lookup-in-block-mode (key : token ;
			       st : block-element) : mode is
    if	empty (st) then
	error-mode
    else
	let
	    element : element := head (st)
	in
	if  (element.key = key)
	     then
	    element.info
	else
	    lookup-in-block-mode (key,
				  tail (st))
	end if
    end if
end function { lookup }	 ;

function lookup (key : token ;
		 st : symbol-table) : mode is
    if	empty (st) then
	error-mode
    else
	let
	    mode : mode := lookup-in-block-mode (key,
						 head (st))
	in
	if  (mode = error-mode)
	     then
	    lookup (key,
		    tail (st))
	else
	    mode
	end if
    end if
end function { lookup }	 ;

function lookup-in-block (key : token ;
			  st : symbol-table) : bool is
    if	(lookup-in-block-mode (key,
			       head (st)) != error-mode)
	 then
	true
    else
	false
    end if
end function { lookup-in-block }  ;

function insert (key : token ;
		 info : mode ;
		 st : symbol-table) : symbol-table is
    symbol-table (block-element (element (key,
					  info,
					  offset-undefined),
				 head (st)),
		  st)
end function { insert }	 ;

function enter-block (st : symbol-table) : symbol-table is
    symbol-table (block-element (),
		  st)
end function { enter-block}  ;

end module ;

Le module de déclaration associé est donné ci-dessous.

declaration module simproc-types is

type
    mode = (varid,
	    refid,
	    arrayid,
	    procid,
	    error-mode) ;
    operator = (wrong-op,
		addition,
		subtraction,
		multiplication,
		division) ;
    element = record
		  key : token ;
		  info : mode ;
		  offset : int ;
	      end record ;
    block-element = list of element ;
    symbol-table = list of block-element ;

const
    empty-table : symbol-table ;
    error-element : element ;
    offset-undefined : int ;

function lookup-in-block (id : token ;
			  st : symbol-table) : bool ;

function lookup (id : token ;
		 st : symbol-table) : mode ;

function insert (id : token ;
		 info : mode ;
		 st : symbol-table) : symbol-table ;

function enter-block (st : symbol-table) : symbol-table ;

end module ;

La grammaire attribuée simproc-check est une grammaire attribuée procédurale (elle redécore l'arbre d'entrée sans créer de nouvel arbre). On peut voir dans l'en-tête de la grammaire, que l'arbre redécoré est décrit par la syntaxe attribuée abstraite simproc-out, contenue dans le fichier simproc-out.asx. Cette syntaxe est donnée ci-dessous :

grammar simproc-out is

import grammar simproc-base ;
from simproc-types import  all {Table des symboles et type operator} ;

root is PROGRAM ;

{Attributs}
{=========}
$symtab (BLOCK) : symbol-table ;
$op (OP) : operator ;
$value (NUMBER) : token { remplace $text }  ;
$id (ID) : token { le seul apparaissant aussi dans "simproc-in" }  ;
$correct (PROGRAM) : bool ;

end grammar ;

Nous sommes arrivés à la fin de la description de la phase de sémantique statique. Nous pouvons vérifier nos spécifications en relançant le script FNC2 et en exécutant les options D, K et C.



Web page maintained by Didier Parigot
Tue Aug 18 11:42:13 MET DST 1998