unit outils;
(* Divers outils. *)

interface

function	est_un_espace (c : char) : boolean;
function	est_un_nombre (c : char) : boolean;
function	est_une_lettre (c : char) : boolean;
function	est_alphanumerique (c :	char) :	boolean;

function 	minuscule (s : string) : string;

function	chaine_a_entier	(s : string; var e : integer) :	boolean;
function 	chaine_a_numero	(s : string; var n : word) : boolean;
function 	chaine_a_reel (s : string; var r : real) : boolean;

implementation

function est_un_espace (c : char) : boolean;
(* Si c	est un espace alors renvoie true.  Un espace est un espace (bien
 * entendu), une tabulation horizontal, ou un retour chariot.
 *)

begin
	est_un_espace := (c = #32) or (c = #9) or (c = #13);
end;

function est_un_nombre (c : char) : boolean;
(* Si c est un nombre (i.e. un caractŠre entre '0' … '9') alors renvoie true.
 *)

begin
	est_un_nombre := (c >= '0') and	(c <= '9');
end;

function est_une_lettre	(c : char) : boolean;
(* Si c est une lettre minuscule de 'a' … 'z' ou majuscule de 'A' … 'Z' alors
 * renvoie true.
 *)

begin
	est_une_lettre := ((c >= 'a') and (c <=	'z'))
		or ((c >= 'A') and (c <= 'Z'));
end;

function est_alphanumerique (c : char) : boolean;
(* Si c est une lettre ou un nombre d'aprŠs les conventions des fonctions
 * est_une_lettre et est_un_nombre alors renvoie true.
 *)

begin
	est_alphanumerique := est_une_lettre(c)	or est_un_nombre(c);
end;

function minuscule (s :	string)	: string;
(* Met en minuscule les lettres de la chaine s et renvoie le r‚sultat. *)

var	i 	: integer;
	temp	: string;

begin
	temp :=	'';

	for i := 1 to length(s)	do
		if (s[i] >= 'A') and (s[i] <= 'Z') then
			temp :=	temp + chr(ord(s[i]) - ord('A')	+ ord('a'))
		else
			temp :=	temp + s[i];

	minuscule := temp;
end;

function chaine_a_entier (s : string; var e : integer) : boolean;
(* Convertit la	chaine s, qui doit ˆtre	un lexŠme de type LITERAL_ENTIER, en
 * entier, le r‚sultat sera dans e.  Si chaine_a_entier renvoie true, alors
 * le r‚sultat est bien entre 0 et 32767, sinon il y a erreur.  Un entier sur
 * 16-bit est entre -32768 et 32767, or l'analyseur lexical ne sait lire que
 * des entiers non sign‚s, aussi pour simplifier l'analyseur syntaxique, on
 * ne prend pas en compte l'entier -32768.
 *)

var	i 	: integer;
	temp	: longint;

begin
	if length(s) > 5 then
		chaine_a_entier	:= false
	else begin
		temp :=	0;
		for i := 1 to length(s)	do
			temp :=	temp * 10 + ord(s[i]) -	ord('0');

		if temp	> 32767	then
			chaine_a_entier	:= false
		else begin
			e := temp;
			chaine_a_entier	:= true;
		end;
	end;
end;

function chaine_a_numero (s : string; var n : word) : boolean;
(* Convertit la	chaine s, lexŠme de type LITERAL_ENTIER, en num‚ro de ligne
 * n.  Si chaine_a_numero renvoie true, alors n est entre 0 et 65535, sinon
 * n est superieur … 65535 et est donc invalide.
 *)

var	i 	: integer;
	temp	: longint;

begin
	if length(s) > 5 then
		chaine_a_numero	:= false
	else begin
		temp :=	0;
		for i := 1 to length(s)	do
			temp :=	temp * 10 + ord(s[i]) -	ord('0');

		if temp	> 65535	then
			chaine_a_numero	:= false
		else begin
			n := temp;
			chaine_a_numero	:= true;
		end;
	end;
end;

function chaine_a_reel (s : string; var	r : real) : boolean;
(* Convertit la chaine s, un lexŠme de type LITERAL_REEL, en r‚el.  Cette
 * fonction, contrairement … chaine_a_entier, ne v‚rifie pas du tout la
 * validit‚ du r‚sultat, et renvoie donc de ce fait toujours true.  Il serait
 * n‚cessaire de la modifier, d'une part pour faire ces v‚rifications, mais
 * aussi pour que le r‚sultat renvoy‚ soit une conversion directe en nombre
 * flottant, et non pas le r‚sultat d'une suite d'op‚rations arithm‚tiques
 * sujets … des erreurs de pr‚cisions.
 *)

function puissance (n :	integer) : real;
(* Calcule 10^n	(avec une m‚thode simple mais lente), aucun test de validit‚,
 * si ce n'est que n < 38.
 *)

var	i	: integer;
	temp	: real;

begin
	temp :=	1.0;
	if n <=	38 then
		for i := 1 to n	do
			temp :=	temp * 10.0;
	puissance := temp;
end;

var	i		: integer;
	diviseur	: real;
	negatif		: boolean;
	n		: integer;

begin
	chaine_a_reel := true;

	i := 1;
	r := 0;
	while s[i] <> '.' do begin
		r := r * 10.0 +	ord(s[i]) - ord('0');
		i := i + 1;
	end;

	i := i + 1;	(* saute le point *)
	diviseur := 1.0;
	while (i <= length(s)) and (s[i] <> 'e') and (s[i] <> 'E') do begin
		diviseur := diviseur * 10.0;
		r := r + (ord(s[i]) - ord('0'))	/ diviseur;
		i := i + 1;
	end;

	if i <=	length(s) then begin
		i := i + 1;	(* saute le 'e'	ou 'E' *)
		if (s[i] = '+')	then begin
			i := i + 1;
			negatif	:= false;
		end else if (s[i] = '-') then begin
			i := i + 1;
			negatif	:= true;
		end else
			negatif	:= false;

		(* L'exposant ne peut avoir au plus que	2 chiffres car il
		 * doit	ˆtre entre -38 et +38, mˆme s'il est possible d'avoir
		 * un exposant de -39 avec Turbo Pascal.  L'exposant est
		 * suppos‚ nul en cas de problŠme.
		 *)

		n := 0;
		if length(s) - i + 1 > 2 then
			n := 0
		else
			while i	<= length(s) do	begin
				n := n * 10 + ord(s[i])	- ord('0');
				i := i + 1;
			end;

		if negatif then
			r := r / puissance(n)	(* l'exposant est n‚gatif *)
		else
			r := r * puissance(n);
	end;
end;

end.
