#=head1 NAME

C<Parse::Token> - Définition des tokens utilisés par C<Parse::Lex>

#=head1 SYNOPSIS

	require 5.005;

	use Parse::Lex;
	@token = qw(
	    ADDOP    [-+]
	    INTEGER  [1-9][0-9]*
	   );

	$lexer = Parse::Lex->new(@token);
	$lexer->from(\*DATA);

	$content = $INTEGER->next;
	if ($INTEGER->status) {
	  print "$content\n";
	}
	$content = $ADDOP->next;
	if ($ADDOP->status) {
	  print "$content\n";
	}
	if ($INTEGER->isnext(\$content)) {
	  print "$content\n";
	}
	__END__
	1+2

#=head1 DESCRIPTION

La classe C<Parse::Token> et ses dérivées permettent de définir les
tokens utilisés par C<Parse::Lex> ou C<Parse::LexEvent>.

La création des tokens peut se faire au moyen des méthodes C<new()> ou
C<factory()>.  La méthode C<Lex::new()> du package C<Parse::Lex> crée
indirectement des instances des tokens à reconnaître.

Les méthodes C<next()> ou C<isnext()> du package C<Parse::Token>
permettent d'interfacer l'analyseur lexical avec un analyseur
syntaxique de type récursif descendant. Pour un interfaçage avec
C<byacc> voir le package C<Parse::YYLex>.

L'inclusion de C<Parse::Token> se fait indirectement par un C<use
Parse::Lex> ou C<use Parse::LexEvent>.

#=head1 Méthodes

#=over 4

#=item action

Retourne la fonction anonyme définie dans l'objet C<Parse::Token>.	

#=item factory LIST

#=item factory ARRAY_REF

La méthode C<factory(LIST)> crée et retourne une liste de tokens à
partir d'une liste de spécifications incluant par token : un nom, une
expression régulière et éventuellement une fonction anonyme. La liste
peut inclure des objets de la classe C<Parse::Token> ou d'une classe
qui en dérive.

C<factory(ARRAY_REF)> permet de créer des tokens à partir de
spécifications de type attribut-valeur :

	Parse::Token->factory([Type => 'Simple', 
                               Name => 'EXAMPLE', 
			       Regex => '.+']);

C<Type> indique le type de chaque token à créer (le préfixe de package 
n'est pas indiqué).

C<factory()> crée une série de tokens mais n'importe pas ces tokens
dans le package d'appel.

On pourra pas exemple écrire :

	%keywords = 
	  qw (
	      PROC  undef
	      FUNC  undef
	      RETURN undef
	      IF    undef
	      ELSE  undef
	      WHILE undef
	      PRINT undef
	      READ  undef
	     );
	@tokens = Parse::Token->factory(%keywords);

et installer ces tokens dans une table des symboles de la manière
suivante :

	foreach $name (keys %keywords) {
	  ${$name} = pop @tokens;
	  $symbol{"\L$name"} = [${$name}, ''];
	}

C<${$name}> est l'instance token.

Lors de la phase d'analyse lexicale on pourra utiliser les tokens de
la manière suivante :

	qw(IDENT [a-zA-Z][a-zA-Z0-9_]*),  sub {		      
	   $symbol{$_[1]} = [] unless defined $symbol{$_[1]};
	   my $type = $symbol{$_[1]}[0];
	   $lexer->setToken((not defined $type) ? $VAR : $type);
	   $_[1];  # THE TOKEN TEXT
	 }

Ce qui permet d'indiquer que tout symbole dont le type est inconnu est
une variable.

Dans cet exemple nous avons utilisé C<$_[1]> qui correspond au texte
reconnu par l'expression régulière.  Ce texte associé au token doit
être retourné par la fonction anonyme.

#=item get EXPR

Permet d'obtenir la valeur de l'attribut résultant de l'évaluation
d'EXPR.  Il est également possible d'utiliser le nom de l'attribut
comme nom de méthode.

#=item getText

Retourne la chaîne de caractères reconnue au moyen de l'objet
C<Parse::Token>.

Synonyme de la méthode C<text()>.

#=item isnext EXPR

#=item isnext

Retourne le statut du token. La chaîne consommée est disponible dans
EXPR s'il s'agit d'une référence à un scalaire.

#=item name

Retourne le nom du token.

#=item next

Active la recherche du token défini par l'expression régulière
contenue dans l'objet. Si ce token est reconnu sur le flot de
caractère à analyser alors C<next()> retourne la chaîne trouvée et met le
statut de l'objet à vrai.

#=item new SYMBOL_NAME, REGEXP, SUB

#=item new SYMBOL_NAME, REGEXP

Crée un objet de type C<Parse::Token::Simple> ou
C<Parse::Token::Segmented>. Les arguments de la méthode C<new()> sont
dans l'ordre : un nom symbolique, une expression régulière et
éventuellement une fonction anonyme.  Les sous-classes de
C<Parse::Token> permettent une spécification des tokens au moyen d'une
liste d'attribut-valeurs.

REGEXP est soit une expression régulière simple, soit une référence à
un tableau contenant de une à trois expressions régulières.  Dans le
permier cas l'instance appartient à la classe C<Parse::Token::Simple>
Dans le second cas l'instance appartient à la classe
C<Parse::Token::Segmented>.  Les tokens de ce type permettent de
reconnaître des structures de type chaîne de caractères délimitée par
des guillemets, des commentaires d'un programme C, etc.  Les
expressions régulières sont utilisées pour reconnaître :

1. le début du token, 

2. le "corps" du token, si cette seconde expression est absente
C<Parse::Lex> utilise C<(?:.*?)>,

3. la fin du token, si cette dernière expression est absente on
utilise la première.  La fin du token ne peut être à cheval sur
plusieurs enregistrements.

Exemple.

	  qw(STRING), [qw(" (?:[^"\\\\]+|\\\\(?:.|\n))* ")],

Les expressions régulières peuvent reconnaître des chaînes multilignes
délimitées par des guillemets, sachant que le contre-oblique est
utilisé pour littéraliser les guillemets qui apparaissent au sein de
la chaîne. Remarquez le quadruplement du contre-oblique.

Voici une variante de l'exemple précédent qui utilise l'option C<s>
pour inclure la nouvelle-ligne dans les caractères reconnus par "C<.>" :

	  qw(STRING), [qw(" (?s:[^"\\\\]+|\\\\.)* ")],

(Remarques. Il est possible d'écrire des expressions régulières plus
performantes en terme de temps d'exécution, mais ce n'est pas notre
objectif ici, voir I<Mastering Regular Expressions>.)

La fonction anonyme est exécutée au moment ou le token est reconnu par
l'analyseur lexical. Cette fonction possède deux arguments : C<$_[0]>
contient l'instance de token, C<$_[1]> contient la chaîne reconnue par
l'expression régulière. Le scalaire retourné par la fonction anonyme
définit la chaîne de caractères placée dans l'instance token.

Dans la fonction anonyme vous pouvez utiliser les variables
positionnelles C<$1>, C<$2>, ... qui correspondent aux parenthèses
placées dans l'expression régulière.

#=item regexp

Retourne l'expression régulière définie dans l'objet C<Parse::Token>.

#=item set LISTE

Permet de décorer un token au moyen d'une liste d'attribut-valeurs.

Un nom d'attribut peut être utilisé comme nom de méthode.

#=item setText EXPR

La valeur de EXPR définit la chaîne de caractères associée au 
token.

Synonyme de la méthode C<text(EXPR)>.

#=item status EXPR

#=item status

Indique si la dernière recherche du token a réussie ou échouée.
C<status EXPR> permet de forcer le statut à la valeur dénotée
par EXPR.

#=item text EXPR

#=item text

C<text()> Retourne la chaîne de caractères reconnue au moyen du
token. La valeur de EXPR permet de définir la chaîne de caractères
associée au token.

#=item trace OUTPUT 

#=item trace 

Méthode de classe qui active/désactive une trace de l'analyse
lexicale. 

C<OUTPUT> peut être un nom de fichier ou une référence à un
filehandle vers laquelle la trace va être dirigée.

#=back

#=head1 Sous-classes de Parse::Token

Des sous-classes de la classe C<Parse::Token> sont en cours de
définition. Elles permettent de reconnaître des structures
particulières comme, par exemple, les chaînes de caractères entre
guillemets, les commentaires C, etc. Voici les sous-classes sur
lesquelles je travaille actuellement :

C<Parse::Token::Action> : permet d'insérer des expressions Perl entre
deux tokens de l'analyseur lexical.

C<Parse::Token::Simple> : les tokens de cette classe sont définis au
moyen d'une seule expression régulière.

C<Parse::Token::Segmented> : les tokens de cette classe sont définis au
moyen de trois expressions régulières. La lecture de nouvelles données
est automatique.

C<Parse::Token::Delimited> : permet de reconnaître, par exemple, des
commentaires C.

C<Parse::Token::Quoted> : permet de reconnaître, par exemple, des
chaînes de caractères entre guillemets.

C<Parse::Token::Nested> : permet de reconnaître des structures
imbriquées, telles que les expressions parenthésées. NON DéFINIE.

La création de ces classes est récente et comporte sans aucun doute
des bugs. 

#=head2 Parse::Token::Action 

Les tokens de la classe C<Parse::Token::Action> permettent d'insérer
des expressions Perl quelconque au sein d'un analyseur lexical.  Une
expression peut être utilisée par exemple pour imprimer des variables
internes à l'analyseur :

#=over 

#=item *

C<$LEX_BUFFER> : contenu du buffer à analyser

#=item *

C<$LEX_LENGTH> : longueur de la chaîne de caractères en cours d'analyse

#=item *

C<$LEX_RECORD> : numéro de l'enregistrement en cours d'analyse

#=item *

C<$LEX_OFFSET> : nombre de caractère déjà consommés depuis le début de
l'analyse

#=item *

C<$LEX_POS> : position atteinte par l'analyse en nombre de caractères
depuis le début du buffer.

#=back

Le constructeur de la classe accepte les attributs suivants : 

#=over 

#=item *

C<Name> : le nom du token

#=item * 

C<Expr> : une expression Perl 

#=back

Exemple :

	$ACTION = new Parse::Token::Action(
				      Name => 'ACTION',
				      Expr => q!print "LEX_POS: $LEX_POS\n" .
				      "LEX_BUFFER: $LEX_BUFFER\n" .
				      "LEX_LENGTH: $LEX_LENGTH\n" .
				      "LEX_RECORD: $LEX_RECORD\n" .
				      "LEX_OFFSET: $LEX_OFFSET\n" 
				      ;!,
				     );

#=head2 Parse::Token::Simple

Le constructeur de la classe accepte les attributs suivants : 

#=over

#=item * 

C<Handler> : la valeur indique un nom fonction à appeler lors d'une
analyse conduite par un analyseur de la classe C<Parse::LexEvent>.

#=item * 

C<Name> : la valeur associée est le nom du token.

#=item * 

C<Regex> : La valeur associée est une expression régulière
correspondant au motif à reconnaître.

#=item * 

C<ReadMore> : si la valeur associée est 1, la reconnaissance du token
se poursuit après la lecture d'un nouvel enregistrement.  Les chaînes
reconnues sont concaténées. Cet attribut n'a d'effet que lors de
l'analyse d'un flot de caractères.

#=item * 

C<Sub> : la valeur associée doit être une fonction anonyme à exécuter
à l'issue de la reconnaissance du token. Cette fonction n'est utilisée
qu'avec les analyseurs de la classe C<Parse::Lex> ou C<Parse::CLex>.

#=back

Exemple.
      new Parse::Token::Simple(Name => 'remainder', 
			       Regex => '[^/\'\"]+', 
			       ReadMore => 1);

#=head2 Parse::Token::Segmented

La définition de ces tokens comporte trois expressions
régulières. Lors de l'analyse d'un flot de données, de nouvelles
données sont lues tant que la fin du token n'est pas atteinte.

Le constructeur de la classe accepte les attributs suivants : 

#=over

#=item * 

C<Handler> : la valeur indique un nom fonction à appeler lors d'une
analyse conduite par un analyseur de la classe C<Parse::LexEvent>.

#=item * 

C<Name> : la valeur associée est le nom du token.

#=item * 

C<Regex> : La valeur associée doit être une référence à un tableau qui 
contient trois expressions régulières.

#=item * 

C<Sub> : la valeur associée doit être une fonction anonyme à exécuter
à l'issue de la reconnaissance du token. Cette fonction n'est utilisée
avec les analyseurs de la classe C<Parse::Lex> ou C<Parse::CLex>.

#=back

#=head2 Parse::Token::Quoted

C<Parse::Token::Quoted> est une sous-classe de
C<Parse::Token::Segmented>. Elle permet de reconnaître des chaînes de
caractères entre guillemets ou apostrophes.

Exemples.

      ---------------------------------------------------------
	Début	Fin	Littéralisation
      ---------------------------------------------------------
	'	'	''		
	"	"	""		
	"	"	\		
      ---------------------------------------------------------

Le constructeur de la classe accepte les attributs suivants : 

#=over

#=item * 

C<End> : La valeur associée est une expression régulière permettant
de reconnaître la fin du token.

#=item * 

C<Escape> : La valeur associée indique le caractère utilisé pour
littéralisater le délimiteur. Par défaut on considère qu'un doublement
du caractère de fin littéralise ce caractère.

#=item * 

C<Handler> : la valeur indique un nom fonction à appeler lors d'une
analyse conduite par un analyseur de la classe C<Parse::LexEvent>.

#=item * 

C<Name> : la valeur associée est le nom du token.

#=item * 

C<Start> : La valeur associée est une expression régulière permettant
de reconnaître le début du token.

#=item * 

C<Sub> : la valeur associée doit être une fonction anonyme à exécuter
à l'issue de la reconnaissance du token. Cette fonction n'est utilisée
avec les analyseurs de la classe C<Parse::Lex> ou C<Parse::CLex>.

#=back

Exemple.
      new Parse::Token::Quoted(Name => 'squotes', 
			       Handler => 'string',
			       Escape => '\\',
			       Quote => qq!\'!, 
			      );

#=head2 Parse::Token::Delimited

C<Parse::Token::Delimited> est une sous-classe de
C<Parse::Token::Segmented>. Elle permet, par exemple, de reconnaître
des commentaires C.

Exemples.

      ---------------------------------------------------------
	Début	Fin	Contrainte
			Sur le contenu	
      ---------------------------------------------------------
	/*	*/			Commentaire C
	<!--	-->	Pas de '--'	Commentaire XML
	<!--	-->	           	Commentaire SGML
	<?  ?>				Processing instruction
					en SGML/XML
      ---------------------------------------------------------

Le constructeur de la classe accepte les attributs suivants : 

#=over 4

#=item * 

C<End> : La valeur associée est une expression régulière permettant
de reconnaître la fin du token.

#=item * 

C<Handler> : la valeur indique un nom fonction à appeler lors d'une
analyse conduite par un analyseur de la classe C<Parse::LexEvent>.

#=item * 

C<Name> : la valeur associée est le nom du token.

#=item * 

C<Start> : La valeur associée est une expression régulière permettant
de reconnaître le début du token.

#=item * 

C<Sub> : la valeur associée doit être une fonction anonyme à exécuter
à l'issue de la reconnaissance du token. Cette fonction n'est utilisée
avec les analyseurs de la classe C<Parse::Lex> ou C<Parse::CLex>.

#=back

Exemple.
      new Parse::Token::Delimited(Name => 'comment',
				  Start => '/[*]', 
				  End => '[*]/'
				 );

#=head2 Parse::Token::Nested - Non définie

Exemples.

      ----------------------------------------------------------
	Début	Fin	Contrainte
			Sur le contenu	
      ----------------------------------------------------------
	(	)			Symbolic Expressions
	{	}			Rich Text Format Groups
      ----------------------------------------------------------


#=head1 BUGS

L'implémentation des sous-classes de tokens n'est pas complète pour
les analyseurs de la classe C<Parse::CLex>. Je n'ai d'ailleurs pas
trop envi de le faire, sachant qu'une implémentation pour les classes
C<Parse::Lex> et C<Parse::LexEvent> ne paraît tout à fait suffisante.

#=head1 AUTEUR

Philippe Verdret

#=head1 REMERCIEMENTS

La version 2.0 doit beaucoup aux suggestions de Vladimir Alexiev.
Ocrat a largement contribué à l'amélioration de cette documentation.
Merci également aux nombreuses personnes qui m'ont fait des remarques
et parfois envoyés des corrections de bugs.

#=head1 REFERENCES

Friedl, J.E.F. Mastering Regular Expressions. O'Reilly & Associates
1996.

Mason, T. & Brown, D. - Lex & Yacc. O'Reilly & Associates, Inc. 1990.

#=head1 COPYRIGHT

Copyright (c) 1995-1999 Philippe Verdret. All rights reserved.
This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

#=cut
