Voici un petit souligneur syntaxique que j'ai écrit en 2 jours, là je l'ai configuré de telle facon qu'il analyse le code Delphi, mais il est très facilement modifiable pour supporter d'autres langages tels que le VB, le C/C++ etc.
Il suffit juste de bien configurer toutes les variables globales. Tout est configurable, y compris les couleurs et le style, les mots clés, les séparateurs de mots, les délimiteurs de chaines, les délimiteurs de commentaires, les délimiteurs d'instructions préprocesseur, etc.
Source / Exemple :
<html>
<head>
<title>Souligneur Syntaxique Delphi</title>
</head>
<body>
<?php
/**
- Souligneur syntaxique Delphi
- Peut facilement être adapté pour d'autres langages (vb, c, c++...)
- Il suffit de modifier le contenu des variables
*
// On limite le temps d'execution à 15 secondes
// (pour éviter de freezer la machine avec un code trop gros)
set_time_limit(15);
/****************************************************************/
/* Les variables qui définissent le comportement de l'analyseur */
/****************************************************************/
$case_sensitive = false; // Langage sensible à la case ou pas
$tokdelimiters = " []()=+-/*:;,.\n\t\r "; // Les délimiteurs de mots
/***************************************************/
/* Les couleurs associées à chaque type de données */
/***************************************************/
$colorkeyword = "";
$colortext = "";
$colorstring = "#000080";
$colorcomment = "#000080";
$colorsymbol = "";
$colornumber = "#000080";
$colorpreproc = "#008000";
/*************************************************/
/* Les styles donnés pour chaque type de données */
/*************************************************/
$stylekeyword = array("<b>", "</b>");
$styletext = array("", "");
$stylestring = array("", "");
$stylecomment = array("<i>", "</i>");
$stylesymbol = array("", "");
$stylenumber = array("", "");
$stylepreproc = array("<i>", "</i>");
/*****************/
/* Les mots clés */
/*****************/
$keywords = array(
'unit',
'interface',
'implementation',
'initialization',
'finalization',
'uses',
'type',
'var',
'begin',
'end',
'with',
'do',
'function',
'procedure',
'property',
'to',
'as',
'is',
'while',
'loop',
'for',
'repeat',
'until',
'use',
'class',
'private',
'protected',
'public',
'published',
'record',
'packed',
'case',
'of',
'const',
'array',
'try',
'finally',
'except',
'message',
'if',
'then',
'else',
'out',
'nil',
'string',
'constructor',
'destructor',
'library',
'set',
'inherited',
'object',
'overload',
'override',
'virtual',
'abstract',
'read',
'write',
'default',
'program',
'absolute',
'asm',
'external',
'stdcall',
'resourcestring',
'downto',
'exports',
'inline',
'raise',
'goto',
'label',
'dispinterface',
'file',
'threadvar',
'not',
'or',
'and',
'xor',
'mod',
'shl',
'shr',
'div'
);
/***********************************/
/* Les délimiteurs de commentaires */
/***********************************/
$commentdelimiters = array(
array("//", "\n"),
array("{", "}"),
array("(*", "*)")
);
/********************************************/
/* Les délimiteurs de chaines de caractères */
/********************************************/
$stringdelimiters = array(
array("'", "'")
);
/********************************************************/
/* Les délimiteurs d'instructions pour le préprocesseur */
/********************************************************/
$preprocdelimiters = array(
array("(*\$", "*)"),
array("{\$", "}")
);
/////////////////////////////////////////////////////////////////////////////////////////
// Le code en lui-même
/////////////////////////////////////////////////////////////////////////////////////////
/************************************************************************/
/* Renvoie vrai si un caractère est visible et peut être mis en couleur */
/************************************************************************/
function visiblechar($char) {
$inviblechars = " \t\n\r ";
return (!is_integer(strpos($inviblechars, $char)));
}
/************************************************************/
/* Formatte un mot d'une manière spéciale (couleur + style) */
/************************************************************/
function formatspecialtok($tok, $color, $style)
{
if (empty($color)) return sprintf("%s$tok%s", $style[0], $style[1]);
return sprintf("%s<font color=\"%s\">$tok</font>%s", $style[0], $color, $style[1]);
}
/*******************************************************************/
/* Recherche un élément dans un tableau sans se soucier de la case */
/*******************************************************************/
function array_search_case($needle, $array)
{
if (!is_array($array)) return false;
if (empty($array)) return false;
foreach($array as $index=>$string)
if (strcasecmp($needle, $string) == 0) return intval($index);
return false;
}
/*****************************************************/
/* Analyse un mot et le renvoie de manière formattée */
/*****************************************************/
function analyseword($tok)
{
global $keywords;
global $case_sensitive;
global $colorkeyword;
global $colornumber;
global $colortext;
global $stylekeyword;
global $stylenumber;
global $styletext;
// Si c'est un nombre
if (($tok[0] == '$') || ($tok[0] == '#') || ($tok == (string)intval($tok)))
return formatspecialtok($tok, $colornumber, $stylenumber);
// Si c'est vide, on renvoie une chaine vide
if (empty($tok)) return $tok;
// Si c'est un mot clé
if ((($case_sensitive) && (is_integer(array_search($tok, $keywords, FALSE)))) ||
((!$case_sensitive) && (is_integer(array_search_case($tok, $keywords)))))
return formatspecialtok($tok, $colorkeyword, $stylekeyword);
// Sinon, on renvoie le mot sans formattage
return formatspecialtok($tok, $colortext, $styletext);
}
/***************************************************/
/* On regarde si on ne tombe pas sur un délimiteur */
/***************************************************/
function parsearray($array, $color = "#000080", $style = array("<i>", "</i>"))
{
global $code;
global $newcode;
global $char;
global $tok;
global $i;
global $codelength;
// On effectue quelques vérifications
if (!is_array($array)) return false;
if (!strlen($code)) return false;
if (!sizeof($array)) return false;
// On va essayer de comparer le caractère courrant avec le 1°
// caractère de chaque premier délimiteur
foreach($array as $delimiterarray) {
$delimiter1 = $delimiterarray[0];
// Si le 1° char correspond
if ($char == $delimiter1[0]) {
$match = true;
// On va tenter de comparer tous les autres caractères
// Pour vérifier qu'on a bien le délimiteur complet
for ($j = 1; ($j < strlen($delimiter1)) && $match; $j++) {
$match = ($code[$i + $j] == $delimiter1[$j]);
} // for
// Si on l'a en entier
if ($match) {
$delimiter2 = $delimiterarray[1];
// Alors on recherche le délimiteur de fin
$delimiterend = strpos($code, $delimiter2, $i + strlen($delimiter1));
// Si on ne trouve pas le délimiteur de fin, on prend tout le fichier
if (!is_integer($delimiterend)) $delimiterend = strlen($code);
// Maintenant qu'on a tout, on analyse le mot avant le délimiteur, s'il existe
if (!empty($tok)) {
$newcode .= analyseword($tok);
$tok = "";
}
// Ensuite, on place le texte contenu entre les délimiteurs
$newcode .= formatspecialtok(substr($code, $i, $delimiterend - $i + strlen($delimiter2)), $color, $style);
// On replace l'indice au bon endroit
$i = $delimiterend + strlen($delimiter2);
// Enfin on récupère le caractère en cours
if ($i > $codelength) $char = null;
else $char = $code[$i];
// On précise qu'on a trouvé
return true;
} //if
} // if
} // foreach
return false;
}
/******************************/
/* On traite les cas spéciaux */
/******************************/
function parsearrays()
{
global $preprocdelimiters;
global $commentdelimiters;
global $stringdelimiters;
global $colorpreproc;
global $colorcomment;
global $colorstring;
global $stylepreproc;
global $stylecomment;
global $stylestring;
$haschanged = true;
// A chaque changement, on redemarre la boucle entière
while($haschanged){
// On regarde si on ne tombe pas sur un délimiteur de commentaire
$haschanged = parsearray($preprocdelimiters, $colorpreproc, $stylepreproc);
if (!$haschanged) {
// On regarde si on ne tombe pas sur un délimiteur de commentaire
$haschanged = parsearray($commentdelimiters, $colorcomment, $stylecomment);
if (!$haschanged) {
// Ou de chaine de caractère
$haschanged = parsearray($stringdelimiters, $colorstring, $stylestring);
} // if
} // if
} // while
} // parsearrays
/***************************/
/* Analyse un code complet */
/***************************/
function analysecode()
{
global $code; // Le code reçu du formulaire
global $newcode; // Le nouveau code généré
global $tok; // Le mot en train d'être découpé
global $char; // Le caractère en cours
global $i; // La position en cours dans le code
global $codelength; // La longueur de la chaine de code
global $commentdelimiters;
global $stringdelimiters;
global $preprocdelimiters;
global $tokdelimiters;
global $colorsymbol;
global $stylesymbol;
// On initialise les variables
$newcode = "";
$tok = "";
$char = null;
$codelength = strlen($code);
for ($i = 0; $i < $codelength; $i++) {
$char = $code[$i];
// On regarde si on tombe sur un cas spécial
parsearrays();
// On regarde si on est arrivé au bout de la chaine
if ($char == null) return $newcode;
// On a fini d'analyser les commentaires, on regarde si on a un mot complet
if (is_integer(strpos($tokdelimiters, $char))) {
// On tombe sur un délimiteur, on coupe le mot
$newcode .= analyseword($tok);
// On formatte le délimiteur
if (visiblechar($char)) $newcode .= formatspecialtok($char, $colorsymbol, $stylesymbol);
else $newcode .= $char;
// On remet à 0 le mot en cours
$tok = "";
}
else {// On n'a pas de mot complet, on complete le mot
$tok .= $char;
}
} // for
// On regarde si on arrive au bout du code
if (!empty($tok)) $newcode .= analyseword($tok);
return $newcode;
}
/**********************/
/* On analyse le code */
/**********************/
if (isset($code)) {
// On retire les \ devant les '
$code = stripslashes($code);
// On analyse le code
$newcode = analysecode();
print("<h2>Code mis en valeur</h2>");
print("<pre>$newcode</pre>");
}
print("<hr>");
?>
<form action="<?php print("
http://$HTTP_HOST$PHP_SELF");?>" method="POST">
Texte à analyser:<br>
<textarea name="code" cols="80" rows="20">
<?php
print($code);
// Juste pour les tests, à retirer par la suite
// On ajoute un exemple de code
if (!isset($code)) {
?>
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'Salut';
Tag := 3;
end;
<?php
}
?>
</textarea>
<br>
<input type="submit" value="analyser">
</form>
</body>
</html>
Conclusion :
Le code est assez rapide: sur mon P4 1.7 Ghz, j'arrive à analyser le fichier Messages.pas de Delphi 7 (1847 lignes de code) en 8 secondes... En revanche, chez mon hébergeur (Amen), au bout de 15 secondes l'analyse n'était pas encore terminée...
J'ai mis une limite d'execution de 15 secondes au début du fichier pour éviter de bouffer tout le temps processeur.
Ce petit bout de code peut être très utile si vous faites un site sur la programmation avec des morceaux de code...
N'hésitez pas à apporter vos critiques et idées d'amélioration...
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.