OVH Cloud OVH Cloud

Interface d'un scanneur?

6 réponses
Avatar
SerGioGio
Bonjour,

Je suis en train d'implémenter un scanneur (ou lexeur autrement dit) et je
m'interroge sur l'interface à adopter.
Pour l'instant le scanneur a une méthode "int scan()" qui renvoie le type
(int) du token lu sur le flot d'entrée. L'objet scanneur a par ailleurs
d'autres méthodes comme "char* token() const" qui renvoie l'emplacement du
token lu, et "std::size_t token_length() const", qui retourne la longueur du
token lu.

Théoriquement, les tokens sont aggrégés pour former des structures plus
complexes (des "phrases") reconnues par le parseur. Le scanneur est en fait
un flot de tokens. Je me demande si il ne serait pas par conséquent
intéressant que le scanneur soit lui même un streambuf. J'ai donc pensé
dériver mon scanneur de "basic_streambuf<token, ? >". Mais justement
problèmes: que mettre à la place de "?". D'après la doc, il faut ici un
char_traits, donc il faudrait que j'écrive un char_traits pour token... ce
qui implique directement que mes tokens sont convertibles en "int" et
vice-versa. Or je ne vois pas comment je convertirai un token en int...

Voilà j'espère avoir été relativement clair... je cherche simplement une
solution "naturelle" d'interface pour un scanneur, et je m'interroge si
streambuf pourrait servir de base de départ.

Dávance merci pour vos suggestions,

SerGioGioGio

6 réponses

Avatar
kanze
SerGioGio wrote:

Je suis en train d'implémenter un scanneur (ou lexeur
autrement dit) et je m'interroge sur l'interface à adopter.

Pour l'instant le scanneur a une méthode "int scan()" qui
renvoie le type (int) du token lu sur le flot d'entrée.
L'objet scanneur a par ailleurs d'autres méthodes comme "char*
token() const" qui renvoie l'emplacement du token lu, et
"std::size_t token_length() const", qui retourne la longueur
du token lu.


Qu'il faut lire dans l'ordre ? Est-ce qu'il ne serait pas mieux
de mettre toutes les informations concernantes un token dans une
structure, et renvoyer ça, une fois pour tout.

Théoriquement, les tokens sont aggrégés pour former des
structures plus complexes (des "phrases") reconnues par le
parseur. Le scanneur est en fait un flot de tokens. Je me
demande si il ne serait pas par conséquent intéressant que le
scanneur soit lui même un streambuf.


Je ne crois pas. Un streambuf, c'est à flot de caractères. Un
token, c'est bien plus complexe qu'un « caractère ».

J'ai donc pensé dériver mon scanneur de
"basic_streambuf<token, ? >".

Mais justement problèmes: que mettre à la place de "?".


Pourquoi pas std::char_traits< token > ? Évidemment, il va
falloir que tu le spécialises.

D'après la doc, il faut ici un char_traits, donc il faudrait
que j'écrive un char_traits pour token... ce qui implique
directement que mes tokens sont convertibles en "int" et
vice-versa. Or je ne vois pas comment je convertirai un token
en int...


D'où est-ce que tu as qu'il faut que token soit convertible en
int ? Il faut en fait qu'il y a un « int_type », mais ça peut
être n'importe quoi -- il peut même être le même type que
char_type, à condition que sa valeur n'est pas un « caractère »
valable.

Voilà j'espère avoir été relativement clair... je cherche
simplement une solution "naturelle" d'interface pour un
scanneur, et je m'interroge si streambuf pourrait servir de
base de départ.


Je vois deux interfaces « naturelles » : un avec une fonction
get, qui renvoie le token suivant, et un autre qui expose tous
les caractèristiques du token (type, position, etc.), avec une
fonction « advance » pour l'avancer au token suivant.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
loufoque

Je suis en train d'implémenter un scanneur (ou lexeur autrement dit) et je
m'interroge sur l'interface à adopter.


Les outils existants pour créer ce genre de chose ne te conviennent pas ?

Avatar
Jean-Marc Bourguet
"SerGioGio" <nospam> writes:

Le scanneur est en fait un flot de tokens. Je me demande
si il ne serait pas par conséquent intéressant que le
scanneur soit lui même un streambuf. J'ai donc pensé
dériver mon scanneur de "basic_streambuf<token, ? >".


Si tu veux ce genre d'interface, je ferais plutôt un
itérateur du scanneur qu'un streambuf. Un streambuf c'est
très spécialisé pour des caractères.

Note que ça fait un interface très simple: prendre le token
courant (operator* ou get), et passer au token suivant
(operator++, ou next). Je suppose que tu utilises la
méthode très classique d'avoir un token marquant la fin de
la source. Tu peux t'amuser à complèter pour avoir
l'interface complète des itérateurs. Si tu en fais un
"forward iterator" plutôt qu'un "input iterator", tu as même
un moyen relativement élégant de permettre du backtracking.

C'est dans la classe Token que je stockerais le reste des
info (le type de token, la position, le lexeme, ...).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
SerGioGio

Je suis en train d'implémenter un scanneur (ou lexeur autrement dit) et
je m'interroge sur l'interface à adopter.


Les outils existants pour créer ce genre de chose ne te conviennent pas ?


J'utilise re2c http://re2c.org/ mais il faut quand même lui écrire pas mal
de code autour (c'est le prix de la flexibilité parait-il)

SerGioGioGio


Avatar
SerGioGio
Si tu veux ce genre d'interface, je ferais plutôt un
itérateur du scanneur qu'un streambuf. Un streambuf c'est
très spécialisé pour des caractères.



En fait j'imaginais également un itérateur grâce à istreambuf_iterator sur
mon streambuf.
Mais c'est sans doute me compliquer la vie pour rien.

SerGioGioGio

Avatar
SerGioGio
kanze wrote:
SerGioGio wrote:

Je suis en train d'implémenter un scanneur (ou lexeur
autrement dit) et je m'interroge sur l'interface à adopter.

Pour l'instant le scanneur a une méthode "int scan()" qui
[snip]


Qu'il faut lire dans l'ordre ? Est-ce qu'il ne serait pas mieux
de mettre toutes les informations concernantes un token dans une
structure, et renvoyer ça, une fois pour tout.



Effectivement. Je ne l'avais pas fait pour ne pas trop alourdir l'interface.

Théoriquement, les tokens sont aggrégés pour former des
structures plus complexes (des "phrases") reconnues par le
parseur. Le scanneur est en fait un flot de tokens. Je me
demande si il ne serait pas par conséquent intéressant que le
scanneur soit lui même un streambuf.


Je ne crois pas. Un streambuf, c'est à flot de caractères. Un
token, c'est bien plus complexe qu'un « caractère ».



En fait, je pensais pouvoir me servir de streambuf pour implémenter tout
type de buffer...
De plus j'aimais assez l'idée qu'une phrase est une suite de token qui est
une suite de caractères.
Mais je me rends maintenant compte que ça risque d'être violent à écrire...
sans apporter d'avantage mesurable.

J'ai donc pensé dériver mon scanneur de
"basic_streambuf<token, ? >".

Mais justement problèmes: que mettre à la place de "?".


Pourquoi pas std::char_traits< token > ? Évidemment, il va
falloir que tu le spécialises.

D'après la doc, il faut ici un char_traits, donc il faudrait
que j'écrive un char_traits pour token... ce qui implique
directement que mes tokens sont convertibles en "int" et
vice-versa. Or je ne vois pas comment je convertirai un token
en int...


D'où est-ce que tu as qu'il faut que token soit convertible en
int ? Il faut en fait qu'il y a un « int_type », mais ça peut
être n'importe quoi -- il peut même être le même type que
char_type, à condition que sa valeur n'est pas un « caractère »
valable.


Merci, je ne m'étais pas rendu compte que le int_type était un type
paramétrable!


Voilà j'espère avoir été relativement clair... je cherche
simplement une solution "naturelle" d'interface pour un
scanneur, et je m'interroge si streambuf pourrait servir de
base de départ.


Je vois deux interfaces « naturelles » : un avec une fonction
get, qui renvoie le token suivant, et un autre qui expose tous
les caractèristiques du token (type, position, etc.), avec une
fonction « advance » pour l'avancer au token suivant.