Travailler moins ca veut surtout dire passer plus de temps pour que
le chose fonctionne mieux. Passer peu de temps à developper c'est
avoir beaucoup de temps pour faire des tests unitaires et des
validation fonctionnelle. Et c'est fort appréciable.
> Blague à part, ce que tu dis sur la génération d'un parser HTTP à
> partir de l'EBNF m'interresse.
Et moi dont, malheureusement je ne le génère pas a partir de
l'EBNF, ce que je génère c'est un 'parser.yacc' et un 'lexer.lex'
issus de template. Voici comment cela se passe :
Première étape définir ce qui nous intéresse, c'est à dire mettre
dans un fichier server_definition.txt la syntaxe suivante non
exhaustive pour simplifier:
GET data
POST data
"connection:" CONNECTION data
"accept:" ACCEPT data
"accept-encoding:" ACCEPTENCODING data
"cache-control:" CACHECONTROL data
"pragma:" PRAGMA data
Voila c'est la liste de ce que mon parser va comprendre.
Maintenant générons les différents fichiers:
sh> gen_yacc
Désormais j'ai un fichier parser.yacc qui sait que CONNECTION
prend 1 argument
sh> gen_lex
Désormais je dispose d'un lexer.lex qui sait que la token
CONNECTION c'est "connection:"
sh> gen_files
Désormais dans le répertoire commands/ j'ai les fonctions
suivantes: cmd_get.c, cmd_post.c, cmd_connection.c, cmd_accept.c,
cmd_acceptencoding.c, cmd_cachecontrol.c, cmd_pragma.c.
Chacune ne seront appelées que si la grammaire est correcte.
Derniere étape:
sh> make
Je dipose maintenant d'un binaire qui comprends
server_definition.txt.
Le but final est bien sur de pas partir de server_definition.txt
mais de l'EBNF contenu dans la RFC.
Ce n'est qu'une premier étape car vous pouvez bien imaginer que il
reste un peu de parsing a faire dans les fonction cmd_xxx.
L'exemple typique c'est
GET /url HTTP/1.1.
Car mon parseur va appeler cmd_get avec comme paramètre
"/url/ HTTP/1.1"
je suis donc dans l'obligation de découper, cependant et vous me
l'accorderez facilement, ce découpage n'a rien de très compliqué.
La difficulté du parseur HTTP c'est que les valeurs peuvent
s'étendre sur plusieurs lignes, en effet la valeur d'un header
n'est pas terminée tant qu'on n'as pas trouver un autre header ou
alors la fin des headers '\r\n\r\n'.
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
peut s'ecrire
Accept-encoding: gzip;q=1.0,
identity;q=0.5,
*;q=0
C'est une des raisons pour lesquelles j'utilise de ''templates''.
Un pour le lexer et un pour le parser.
[^] # Re: Salaud !
Posté par forc3 . En réponse au journal Générateur de générateur de 'parser'.. Évalué à 1.
le chose fonctionne mieux. Passer peu de temps à developper c'est
avoir beaucoup de temps pour faire des tests unitaires et des
validation fonctionnelle. Et c'est fort appréciable.
> Blague à part, ce que tu dis sur la génération d'un parser HTTP à
> partir de l'EBNF m'interresse.
Et moi dont, malheureusement je ne le génère pas a partir de
l'EBNF, ce que je génère c'est un 'parser.yacc' et un 'lexer.lex'
issus de template. Voici comment cela se passe :
Première étape définir ce qui nous intéresse, c'est à dire mettre
dans un fichier server_definition.txt la syntaxe suivante non
exhaustive pour simplifier:
Voila c'est la liste de ce que mon parser va comprendre.
Maintenant générons les différents fichiers:
sh> gen_yacc
Désormais j'ai un fichier parser.yacc qui sait que CONNECTION
prend 1 argument
sh> gen_lex
Désormais je dispose d'un lexer.lex qui sait que la token
CONNECTION c'est "connection:"
sh> gen_files
Désormais dans le répertoire commands/ j'ai les fonctions
suivantes: cmd_get.c, cmd_post.c, cmd_connection.c, cmd_accept.c,
cmd_acceptencoding.c, cmd_cachecontrol.c, cmd_pragma.c.
Chacune ne seront appelées que si la grammaire est correcte.
Derniere étape:
sh> make
Je dipose maintenant d'un binaire qui comprends
server_definition.txt.
Le but final est bien sur de pas partir de server_definition.txt
mais de l'EBNF contenu dans la RFC.
Ce n'est qu'une premier étape car vous pouvez bien imaginer que il
reste un peu de parsing a faire dans les fonction cmd_xxx.
L'exemple typique c'est
GET /url HTTP/1.1.
Car mon parseur va appeler cmd_get avec comme paramètre
"/url/ HTTP/1.1"
je suis donc dans l'obligation de découper, cependant et vous me
l'accorderez facilement, ce découpage n'a rien de très compliqué.
La difficulté du parseur HTTP c'est que les valeurs peuvent
s'étendre sur plusieurs lignes, en effet la valeur d'un header
n'est pas terminée tant qu'on n'as pas trouver un autre header ou
alors la fin des headers '\r\n\r\n'.
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
peut s'ecrire
Accept-encoding: gzip;q=1.0,
identity;q=0.5,
*;q=0
C'est une des raisons pour lesquelles j'utilise de ''templates''.
Un pour le lexer et un pour le parser.