Salut les spipeurs,
J'étais en congés la semaine dernière, et je viens juste de me
réabonner, mais j'ai vu ce mail d'Antoine dans les archives.
J'ai un peu profité de ces congés pour avancer sur mon parser (et
beaucoup pour avancer sur ma véranda, mais c'est un autre débat).
J'ai maintenant une version qui marche, qui génère un squelette
apparemment identique à celui avec le parseur d'origine (à la
numérotation des boucles près => un diff est pas vide), et qui ne va
"que" 2 fois moins vite que l'original ...
Je pose ça dans un coin d'ici peu.
Remarques en vrac :
Heu, avant ça, juste une question : pourquoi placid ? c'est une
bonne idée, mais t'as trouvé un acronyme de la mort à coller dessus ?
Parseur Lourd Affreux Complètement Impossible à Débugger ?
- heu, peux-tu régler ton éditeur pour indenter avec des tabs ?
En fait, j'aime pô les indentations à 8 caractères, ça oblige à
élargir la fenêtre. Je préfère à 4, du coup, c'est un peu pénible
mais j'vais refaire une passe pour améliorer ça en disant à emacs de
faire des tab de 4 caractères (même si c'est contre ma religion
- ton parser a un problème majeur : il accroche sur des
caractères spécifiques plutôt que de chercher les structures
directement (oui, je sais, c'est comme ça qu'on fait (tm),
mais bon)
Si on veut généraliser un tout petit peu le système, on arrive
vite à une solution comme ça en fait.
- du coup, il est lent puisque le chevron "<" est très utilisé
en HTML...
Effectivement, ça vous dirait pas de changer de délimiteur pour
les squelette ? mais d'un autre coté, il s'agit là de millisecondes.
Sur un squelette comme article-dist v1.7a7 on passe de 125ms à 250ms
sur mon pc pour générer le tableau de boucles/champs/textes, c'est
quand même pas la mort, d'autant plus que ça n'est censé être fait que
quand il y a des modifs du squelette, c'est à dire presque jamais sur
un site en prod.
Pour info, les 250ms, c'est à peu près
- 100ms pour repérer les tokens
- 100ms pour créer la structure de boucles
- 50ms pour repasser dessus et créer les requêtes mysql associées.
(j'ai découvert microtime la semaine dernière
- on le rend beaucoup moins lent en utilisant preg_match (note
que le parser de spip lui, s'en passe plutôt bien, et que
preg_match n'est pas toujours dispo sous php3...)
Pour l'instant, j'ai essayé de rester "php3 compliant", ne serait-ce
que pour pouvoir comparer avec l'existant.
- d'autre part, toujours à cause du problème susnommé, tu
dois gérer une espèce de backtrack pour retrouver les textes
conditionnels avant
Pas vraiment, au contraire. Actuellement, on cherche un <BOUCLE et
ensuite on cherche un éventuel <B avant. Dans ma version, on cherche
<B ou <BOUCLE et c'est le premier des 2 qu'on trouve qui effectue la
création de l'objet boucle.
Par contre, là où c'est galère, c'est pour savoir quand on est
arrivé à la fin d'une boucle, puisqu'il n'y à pas forcément de /B ou
de //B.
- bugs potentiels : que se passe-t-il si j'écris
(#EMAIL) ? ce n'est pas un champ étendu, c'est juste un
champ que je veux afficher entre parenthèses
À vérifier, mais je crois que ça marche, même s'il y a un [ 3
kilomètres avant.
En fait je pensais adopter (dans l'éventualité où je bougerais
ma flemme et écrirais moi-même un tel machin) une méthode
plus adaptée à SPIP, c'est-à-dire :
- pas de langage de grammaire générique (enfin on peut,
mais pour SPIP ce n'est pas utile vu le peu de structures
différentes)
En fait, l'une des grosses modifs de cette semaine, c'est que j'ai
essayé d'isoler complètement l'outil de génération pour en faire un
produit GPL indépendant.
J'ai également changé le système d'analyse lexicale : je commence
par parser tout le buffer pour obtenir un tableau de tokens qu'il n'y
a plus qu'à parcourir pendant l'analyse syntaxique. Ça accélère pas
mal les choses.
- plutôt qu'un tableau de regexp, écrire une classe de
parsing dédiée pour chaque structure (class ParserChamp,
class ParserBoucle, etc.)
[...]
L'idée est séduisante (et pis c'est objet, ça va plaire à Marc ;-).
Mais ce qui est difficile à faire c'est de récupérer le cas ou
l'un des matchs retourne une position qui est au milieu du bloc isolé
par un autre match. Il faut savoir quand rappeler quel match, c'est
assez casse g.. à coder. J'avais pensé à faire ça à coup de strpos
à la place du strcspn, mais c'est vraiment tordu à suivre comme algo.
En fait, le parser actuel utilise une méthode complètement
différente : on isole les bornes d'un bloc (une boucle en l'occurence)
puis on parse l'intérieur de chaque sous bloc. Ma version avance dans le
code, empile les blocs et les dépile quand il rencontre des marqueurs de
fin. C'est vrai que c'est pas super adapté à ce type de syntaxe, mais
je pense que ton idée buterait sur les mêmes problèmes que moi.
En effet, on ne peut chercher un <B* que quand on connait le nom
du <BOUCLE associé. on mélange donc complètement les étapes lexicales
et syntaxiques.
La seule alternative, c'est de faire du vrai lex/yacc, mais on
passerait un temps fou à desosser du html pour rien.
De plus rien n'empêche
de les optimiser (voir par exemple utilisation de strpos
dans la détection de boucles du parser actuel), ce qui
est beaucoup plus difficile avec une abstraction du
matching dans la grammaire "générique".
Désormais, je génère un code qui fait un peu ça :
- strcspn pour trouver un caractère interessant
- si c'est un prefixe de regex, strcmp sur le début des regex pour
filtrer, puis ereg si ça ressemble à un truc bien.
Du coup, on n'appelle plus 6 ereg différents pour chaque tag html.
Sinon, y a t'il des gens très balaises en php ici ? c'est pour
savoir comment on pourrait optimiser le code en évitant les substr
à tour de bras notamment. Ma version est tout le temps obligée de
tailler des strings en tranches alors qu'il faudrait pas grand
chose pour l'éviter, mais j'sais pas trop comment php gère les
strings en interne.
À+, Pif.