Project Oscar |
Previous: Analyse syntaxique et recouvrement
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.