Analyse van een skelet

Wanneer de parser van SPIP een skelet analyseert, vertaalt het de syntaxis in een woordenschat die de compiler kent en begrijpt. We zouden dan kunnen zeggen dat de parser een bepaalde taal (de syntaxis van SPIP) vertaalt, die we een "concrete syntaxis" noemen, in een precieze taal die we een "abstracte syntaxis" noemen. Dit wordt gedefinieerd door PHP objecten in het ecrire/puclic/interfaces.php bestand.

Met deze pagina-analyse maakt de parser een tabel die het beschrijft, opeenvolgend en recursief, door gebruik te maken van de woordenschat die door de compiler wordt meegeleverd (de objecten die tekst, velden, lussen, voorwaarden, idiomen, insluitingen, polyglots).

Om het wat duidelijker te maken, kijken we naar de tabellen die wordt gegenereerd door enkele voorbeelden.

Een tekst

Skelet:

  1. Eenvoudige tekst

Gegenereerde tabel: (output met print_r)

array (
  0 => 
  Texte::__set_state(array(
     'type' => 'texte',
     'texte' => 'Eenvoudige tekst
',
     'avant' => NULL,
     'apres' => '',
     'ligne' => 1,
  )), 
)

De tabel geeft aan dat het eerst gelezen element op de pagina (key 0) een "texte" element is, beginnend op regel 1, met als tekststring "Eenvoudige tekst".

Een baken

Skelet:

  1. [ervoor(#VAL)erna]

We kunnen uit de gegenereerde tabel hieronder lezen dat het eerste element op de pagina een veld is ("champ" in het Frans) (een tag), dat zijn naam "VAL" is, dat deze niet in een lus zit (anders zou de id_loop gedefinieerd worden), en dat wat in de optionele sectie vóór het baken een "texte" element is met de tekststring "ervoor".

Gegenereerde tabel:

array (
  0 => 
  Champ::__set_state(array(
     'type' => 'champ',
     'nom_champ' => 'VAL',
     'nom_boucle' => '',
     'avant' => 
    array (
      0 => 
      Texte::__set_state(array(
         'type' => 'texte',
         'texte' => 'ervoor',
         'avant' => NULL,
         'apres' => '',
         'ligne' => 1,
      )),
    ),
     'after' => 
    array (
      0 => 
      Texte::__set_state(array(
         'type' => 'texte',
         'texte' => 'erna',
         'avant' => NULL,
         'apres' => '',
         'ligne' => 1,
      )),
    ),
     'etoile' => '',
     'param' => 
    array (
    ),
     'fonctions' => 
    array (
    ),
     'id_boucle' => NULL,
     'boucles' => NULL,
     'type_requete' => NULL,
     'code' => NULL,
     'interdire_scripts' => true,
     'descr' => 
    array (
    ),
     'ligne' => 1,
  )),
  1 => 
  Texte::__set_state(array(
     'type' => 'texte',
     'texte' => '
',
     'avant' => NULL,
     'apres' => '',
     'ligne' => 1,
  )),
)

Een lus

We bekijken nog een voorbeeld van een lus met behulp van een baken, wat iets gecompliceerder is omdat het een circulaire in de gegenereerde tabel impliceert. Kijk naar dit eenvoudige skelet segment:

Template:

<BOUCLE_a(ARTICLES){id_article=3}>
#TITRE
</BOUCLE_a>

Deze lus selecteert artikel 3 en moet de titel van het artikel weergeven. Als we de paginatabel zouden proberen te tonen, zou dit uiteindelijk een recursiefout genereren. De illustratie laat zien dat het tweede element dat in de lus wordt gelezen een veld ("champ" in het Frans) of baken met de naam "TITRE" is. Dit veld bevat een verwijzing naar de lus waarin het is gedefinieerd ('boucles'=>array(....)). Deze lus bevat het baken dat behoort tot de lus die het baken bevat die behoort tot de lus ....

Deel van de gegenereerde tabel

array (
  0 => 
  Boucle::__set_state(array(
     'type' => 'boucle',
     'id_boucle' => '_a',
     'id_parent' => '',
     'avant' => 
    array (
    ),
     'milieu' => 
    array (
      0 => 
      Texte::__set_state(array(
         'type' => 'texte',
         'texte' => '
',
         'avant' => NULL,
         'apres' => '',
         'ligne' => 1,
      )),
      1 => 
      Champ::__set_state(array(
         'type' => 'champ',
         'nom_champ' => 'TITRE',
         'nom_boucle' => '',
         'avant' => NULL,
         'apres' => NULL,
         'etoile' => '',
         'param' => 
        array (
        ),
         'fonctions' => 
        array (
        ),
         'id_boucle' => '_a',
         'boucles' => 
        array (
          '_a' => 
          Boucle::__set_state(array(
             'type' => 'boucle',
             'id_boucle' => '_a',
             'id_parent' => '',
             'avant' => 
            array (
            ),
             'milieu' => 
            array (
              0 => 
              Texte::__set_state(array(
                 'type' => 'texte',
                 'texte' => '
',
                 'avant' => NULL,
                 'apres' => '',
                 'ligne' => 1,
              )),
              1 => 
              Champ::__set_state(array(
                 'type' => 'champ',
                 'nom_champ' => 'TITRE',
                 'nom_boucle' => '',
                 'avant' => NULL,
                 'apres' => NULL,
                 'etoile' => '',
                 'param' => 
                array (
                ),
                 'fonctions' => 
                array (
                ),
                 'id_boucle' => '_a',
                 'boucles' => 
                array (
                  '_a' => 
                  Boucle::__set_state(array(
...

Waarom deze referenties?

Heel eenvoudigweg omdat ze dan gebruikt worden voor het berekenen van de bakens. Wanneer een baken wordt berekend, wordt een deel van deze tabel als parameter doorgegeven (de beroemde $p die we vaak zullen tegenkomen). Dit deel heeft simpelweg betrekking op de eigenschappen van het baken. Om eigenschappen uit de bijgaande lus op te halen, is het enige wat nodig is (dankzij deze referenties) om de parameter $p->boucles[$p->id_boucle] aan te roepen.

Auteur hanjo Gepubliceerd op:

Vertalingen: English, français, Nederlands