Surlignage du code FORTH en PHP

publication: 22 juin 2022 / mis à jour 23 juin 2022

Read this page in english

 


Appel à collaboration

Vous développez des montages, simples ou complexes avec ESP32 et ESP32forth.

Partagez-les ici sur ce site.

ESP32forth ne pourra se développer qu'avec la collaboration active de toutes les bonnes volontés.

Vos montages peuvent aider d'autres développeurs.

Les montages des autres développeurs peuvent vous aider.

Pour proposer un article ou un montage, cliquez ici


Préambule

Très tôt, dans ma longue carrière de programmeur informatique, j'ai apprécié les éditeurs de code source qui surlignent la syntaxe du code source. Certains de ces éditeurs de code savent s'adapter au langage de programmation utilisé.

Plus tard, en écrivant des articles traitant de programmation, sur des blogs, puis sur mes sites web, j'ai utilisé GesHi, une librairie puissante, mais complexe.

Le souci, avec GesHi, c'est qu'il ne traite pas le code FORTH. J'ai bien réussi à créer des scripts adaptés au langage FORTH pour GesHi, mais ces scripts avaient toujours quelques défauts:

Ici, GesHi détecte le mot begin dans le mot MDNS.BEGIN.

Après analyse, GesHi traite le code FORTH caractère par caractère et considère les caractères . et - comme des opérateurs de code.

GesHi représente plus de 4000 lignes de code en PHP. Un code complexe et peu factorisé. On sent la patte de plusieurs programmeurs qui ont chacun rajouté des couches.

Code complet disponible ici:

php/blob/main/Forth.php

Un nouvel analyseur de code pour FORTH

J'étais confronté à plusieurs choix:

Il s'avère que je maitrise parfaitement la programmation en PHP. J'ai donc commencé par faire un test très simple: exploser un code FORTH avec PHP:

/**
 * Explode FORTH source code in array of keywords
 * @param type $code
 */
private function explodeSource($code) {
    $lines = explode( "\n", str_replace("\r", "", $code));
    $this->keySource = array();
    foreach ($lines AS $line) {
        $this->keySource[] = explode(" ", $line);
    }
}

Le résultat était tout simplement ce que je recherchais. Cette fonction explodeSource découpe chaque ligne en tableau de lignes. La seconde boucle découpe le contenu de chaque ligne en tableau en prenant comme séparateur le caractère espace. Le résultat est restitué dans un tableau $this->keySource.

C'est ce qui m'a décidé à créer mon propre analyseur de code FORTH en PHP. J'ai réalisé un surligneur de code FORTH en deux soirées à peine....

Définir les liste de mots FORTH

Sur mon site web, les mots FORTH sont stockés en base de données. Voici comment est réalisée l'injection des listes de mots FORTH dans un tableau $this->keywords:

    /**
     * fetch all forth words from database
     */
    private function getKeywords() {
        $Glossaire = new Application_Model_Glossaire;
        $this->keywords[0] = $Glossaire->getListeMotsOrdinaires();
        $this->keywords[1] = $Glossaire->getListeMotsDefinition();
        $this->keywords[2] = $Glossaire->getListeMotsStructure();
        $this->keywords[3] = $Glossaire->getVariablesConstantes();
        $this->keywords[4] = $Glossaire->getListeMotsVocabulaires();
        //$motsDefered    = $Glossaire->getListeMotsDefered();
        $Registers = new Application_Model_Registers;
        $this->keywords[5] = $Registers->getListeRegistres();
    }

Sur votre site web, vous pouvez définir vos listes de cette manière si vous ne souhaitez pas exploiter une base de données:

    /**
     * fetch all forth words from database
     */
    private function getKeywords() {
        $Glossaire = new Application_Model_Glossaire;
        $this->keywords[0] = array('drop', 'dup', 'rot', 'over', 'swap');
        $this->keywords[1] = array(':', ';', 'constant', 'variable');
        $this->keywords[2] = array('if','else','then');
        $this->keywords[3] = array('base');
        $this->keywords[4] = array('forth');
    }

Avec cette méthode, on définit différentes catégories de mots FORTH. Ceci permet de surligner le code FORTH avec des styles différents.

Définition des styles

On définit un autre tableau contenant les différents styles pour surligner le code FORTH:

    /**
     * define all styles for decoration
     * @var array
     */
    var $outStyle = array(
            0 => 'color: #0000ff;',                         // normal words
            1 => 'color: red; font-weight: bold;',          // definitions words
            2 => 'color: black; background-color: yellow;', // structure words
            3 => 'color: #ff00ff; font-weight: bold;',      // constants
            4 => 'color: black; font-weight: bold; background-color: #d7d7ff',  // vocs
        'bin' => 'color: #7f00dd;',     // binaries values
        'dec' => 'color: #0000dd;',     // decimal values
        'hex' => 'color: #003ffd;',     // hexadecimal values
    );

Dans ce code, nous avons trois clés bin dec et hex. Ces clés sont utilisées pour décorer des valeurs numériques en binaire, décimal ou hexadécimal.

Décoration d'un mot FORTH

La décoration d'un mot FORTH fonctionne par paliers successifs:

A chaque palier, on sort de la fonction par return. Si aucune condition n'est remplie on renvoie le mot sans décoration, suivi d'un caractère espace.

    /**
     * highlight FORTH code
     * @param string $word
     */
    private function styliseWord($word) {
        if ($this->commentFlag == TRUE) {
            return $word ." ";
        }
        // test if  $word is a binary value
        $re = '/^[0-1]{8}/is';
        preg_match($re, $word, $matches, PREG_OFFSET_CAPTURE, 0);
        if (!empty($matches)) {
            return '<abbr style="' . $this->outStyle['bin'] . '" title="binary byte">' 
                   . $word . '</abbr> ';
        }
        // test if $word is a decimal value
        $re = '/^\d{1,}/is';
        preg_match($re, $word, $matches, PREG_OFFSET_CAPTURE, 0);
        if (!empty($matches)) {
            return '<abbr style="' . $this->outStyle['dec'] . '" title="number">' 
                   . $word . '</abbr> ';
        }
        // test if $word is a hexadecimal value
        $re = '/^\$[a-f0-9]{1,}/is';
        preg_match($re, $word, $matches, PREG_OFFSET_CAPTURE, 0);
        if (!empty($matches)) {
            return '<abbr style="' . $this->outStyle['hex'] 
                   . '" title="hexadecimal value">' . $word . '</abbr> ';
        }
        // if it's the word \ tag comment
        if (ord($word) == 92) {
            $this->commentFlag = TRUE;
            return '<span style="color: #808080; font-style: italic;">' . $word ." ";
        }
        // test if  $word is a FORTH word
        foreach ($this->keywords AS $level => $listeMots) {
            if (in_array(strtoupper($word), $listeMots)) {
                return $this->linkifyWord($word, $level);
            }
        }
        return $word ." ";
    }

La décoration d'un mot FORTH qui est défini dans la liste des mots FORTH s'effectue de cette manière en PHP:

    /**
     * array of external links
     * @var array
     */
    var $outlink = array(
        0 => 'help/index-esp32/word/',
        1 => 'help/index-esp32/word/',
        2 => 'help/index-esp32/word/',
        3 => 'help/index-esp32/word/',
        4 => 'help/index-esp32/word/',
        5 => 'help/reg-esp32/word/',
    );
 
    /**
     * include FORTH word in an external link
     * @param string $word
     * @param mixed  $level
     * @return string
     */
    private function linkifyWord($word, $level) {
        if ($this->enable_keyword_links) {
            return '<a href="' . $this->outlink[$level] . base64_encode($word) 
                   . '" style="' . $this->outStyle[$level] . '">' . $word . '</a> ';
        }
        return '<abbr style="' . $this->outStyle[$level] . '">' . $word . '</abbr> ';
    }

On définit une liste de liens dans le tableau $outlink. Ici, ce sont des liens internes propres à mon site web. Il est facile de définir des liens vers des sites externes:

    /**
     * array of external links
     * @var array
     */
    var $outlink = array(
        0 => 'https://forth-standard.org/standard/core/DUP',
        1 => 'https://forth-standard.org/standard/core/DUP',
        2 => 'https://forth-standard.org/standard/core/DUP',
        3 => 'https://forth-standard.org/standard/core/DUP',
        4 => 'https://forth-standard.org/standard/core/DUP',
    );

Reconstitution du code FORTH décoré

Pour reconstruire notre code FORTH décoré, on part du tableau $this->keySource. Ce tableau a été rempli par explodeSource. On lit ce tableau item par item. Si on rencontre un item vide, on concatène un espace simple. Dans le cas contraire, on décore l'item selon les conditions de la fonction styliseWord.

    /**
     * Generate highlighted FORTH source code
     * @return string
     */
    private function generateOutsource() {
        $outSource = "";
        foreach ($this->keySource AS $line) {
            foreach ($line AS $word) {
                if (strlen($word)==0) {
                    $outSource .= " ";
                }   else {
                    $outSource .= $this->styliseWord($word);
                }
            }
            if ($this->commentFlag == TRUE) {
                $this->commentFlag = FALSE;
                $outSource .= "</span>";
            }
            $outSource .= "
";
        }
        return $outSource;
    }

Voici comment exploiter le code PHP permettant de surligner le code FORTH. Le code PHP doit être chargé préalablement par include ou la fonction autoload de PHP:

<?php $forthStr = <<<EOT
DEFINED? --random [if] forget --random  [then] 
create --random 
 
\ Random number data 
$3FF75144 constant RNG_DATA_REG     \ Read Only ESP32 register 
 
\ get 32 bits random b=number 
: rnd  ( -- x ) 
    RNG_DATA_REG L@ 
  ;
EOT;
echo $Forth->sourceForView($forthStr); ?>

Le résultat est celui attendu:

DEFINED? --random [if] forget --random  [then]  
create --random  
 
\ Random number data  
$3FF75144 constant RNG_DATA_REG     \ Read Only ESP32 register  
   
\ get 32 bits random b=number  
: rnd  ( -- x )  
    RNG_DATA_REG L@  
  ; 

Conclusion

Si on se réfère au seul contenu du code de gesHi, le surlignage de code semble une tâche ardue. Et c'en est effectivement une si on construit une usine à gaz.

Ici, avec moins de 200 lignes de code, en PHP, j'ai développé, en quelques heures, un surligneur de code FORTH qui fonctionne bien mieux que le code de gesHi sur lequel j'ai passé des dizaines de journées à tenter d'en comprendre toutes les subtilités.

Reste la question de l'intérêt de surligner le code FORTH...

Ce qui m'a intéressé, avec GesHi, c'est que nativement, si on surligne du code PHP, il est possible d'activer des liens externes de documentation.

C'est cet aspect de GesHi qui me semble avoir un énorme intérêt pour FORTH. Car vous aurez beau documenter un programme, rien ne vaut un accès direct à des explications sur n'importe quel mot du vocabulaire FORTH.

Dans les codes sources diffusés ici, tous les mots de ESP32forth qui sont documentés sont affichés avec une coloration syntaxique et un lien hypertexte donnant accès direct à la documentation de ce mot.

Car, si on veut que FORTH intéresse des programmeurs, il me semble essentiel de faciliter la compréhension du code. Et, sauf erreur, aucun autre site web de développeur FORTH n'a encore donnée un accès aussi simple à la documentation du code FORTH au travers de la coloration syntaxique.

Un mot pour Peter FORTH:

Peter.

Vous m'avez bloqué de votre groupe FORTH2020 quand j'ai présenté cette méthode de surlignage du code FORTH.

Vous m'avez également bloqué d'autres groupes dès que j'intervenais pour présenter FORTH. Votre blog ESP32FORTH est indigent. Mal construit. Il gagnerait en lisibilité à exploiter mon code PHP.

Alors mettez votre égo de coté. Si vous pensez vraiment oeuvrer dans l'intérêt du langage FORTH, Cessez cette atitude enfantine envers moi.


Legal: site web personnel sans commerce / personal site without seling