unit variables;
(* Gestionnaire	de variables. *)

interface

type	TYPE_VARIABLES	= (
		VARIABLE_ENTIERE,
		VARIABLE_REELLE,
		VARIABLE_CHAINE
	);

	VARIABLE 	= ^RECORD_VARIABLE;

	RECORD_VARIABLE	= record
		identificateur	: string;
		lien		: VARIABLE;

		case type_variable : TYPE_VARIABLES of
			VARIABLE_ENTIERE	: (entier : integer);
			VARIABLE_REELLE		: (reel : real);
			VARIABLE_CHAINE		: (chaine : string);
	end;

procedure 	initialise_gestionnaire_variables;
procedure	termine_gestionnaire_variables;

function 	cree_variable_entiere (identificateur : string;
			entier : integer) : VARIABLE;
function 	cree_variable_reelle (identificateur : string;
			reel : real) : VARIABLE;
function 	cree_variable_chaine (identificateur : string;
			chaine : string) : VARIABLE;
function	cherche_variable (identificateur : string) : VARIABLE;

implementation

uses outils, interpreteur;

const	VALEUR_HASHAGE 	= 101;

var     initialise	: boolean;
	table_hashage	: array	[0 .. VALEUR_HASHAGE - 1] of VARIABLE;

procedure initialise_gestionnaire_variables;
(* Initialise le gestionnaire de variables en initialisant les listes
 * chain‚es du tableau de hashage … nil.
 *)

var	i 	: integer;

begin
	initialise := true;
	for i := 0 to VALEUR_HASHAGE - 1 do
		table_hashage[i] := nil;
end;

procedure termine_gestionnaire_variables;
(* Termine le gestionnaire de variables, d‚salloue toute la m‚moire prise par
 * les variables de la table de hashage.
 *)

var	i	: integer;
	v, lien	: VARIABLE;

begin
	if not initialise then begin
		writeln('Erreur Interne: ',
			'Gestionnaire de variables non initialis‚!');
		halt;
	end else begin
		initialise := false;
		for i := 0 to VALEUR_HASHAGE - 1 do begin
			v := table_hashage[i];
			while v	<> nil do begin
				lien :=	v^.lien;
				dispose(v);
				v := lien;
			end;
		end;
	end;
end;

function hash (identificateur : string) : word;
(* Calcul la valeur de hashage d'un identificateur en additionant les
 * valeurs ASCII de tous ses caractŠres	et en faisant le modulo	de la valeur
 * de hashage.
 *)

var	i	: integer;
	somme	: word;

begin
	somme := 0;
	for i := 1 to length(identificateur) do
		somme := somme + ord(identificateur[i]);
	hash :=	somme mod VALEUR_HASHAGE;
end;

procedure insere_variable (v : VARIABLE);
(* InsŠre la variable v	dans la	table de hashage qui est simplement chain‚e.
 * On ne peut pas d‚truire des variables en Basic (il n'y a pas	de
 * "collecteuse d'ordure"), si ce n'est	en terminant le gestionnaire de
 * variables, ce qui les d‚truit toutes.
 *)

var	h	: word;

begin
	h := hash(v^.identificateur);
	v^.lien	:= table_hashage[h];
	table_hashage[h] := v;
end;

function cree_variable_entiere (identificateur : string; entier : integer)
	: VARIABLE;
(* Cr‚e	une variable de	type entiŠre, l'insŠre dans la table de	hashage, et
 * renvoie un pointeur sur sa structure	de controle, ou	nil s'il n'y a pas
 * assez de m‚moire.  Cette fonction ne diffencie pas majuscule et minuscule.
 *)

var	v 	: VARIABLE;

begin
	identificateur := minuscule(identificateur);
	if maxavail < sizeof(RECORD_VARIABLE) then begin
		erreur_interpreteur := PAS_ASSEZ_MEMOIRE;
		cree_variable_entiere := nil;
	end else begin
		new(v);
		v^.type_variable := VARIABLE_ENTIERE;
		v^.identificateur := identificateur;
		v^.entier := entier;
		insere_variable(v);
		cree_variable_entiere := v;
	end;
end;

function cree_variable_reelle (identificateur : string; reel : real)
	: VARIABLE;
(* Cr‚e	une variable de	type r‚elle, l'insŠre dans la table de hashage,	et
 * renvoie un pointeur sur sa structure	de controle, ou	nil s'il n'y a pas
 * assez de m‚moire.  Cette fonction ne diffencie pas majuscule et minuscule.
 *)

var	v 	: VARIABLE;

begin
	identificateur := minuscule(identificateur);
	if maxavail < sizeof(RECORD_VARIABLE) then begin
		erreur_interpreteur := PAS_ASSEZ_MEMOIRE;
		cree_variable_reelle :=	nil;
	end else begin
		new(v);
		v^.type_variable := VARIABLE_REELLE;
		v^.identificateur := identificateur;
		v^.reel := reel;
		insere_variable(v);
		cree_variable_reelle :=	v
	end;
end;

function cree_variable_chaine (identificateur : string; chaine : string)
	: VARIABLE;
(* Cr‚e	une variable de	type chaine, l'insŠre dans la table de hashage,	et
 * renvoie un pointeur sur sa structure	de controle, ou	nil s'il n'y a pas
 * assez de m‚moire.  Cette fonction ne diffencie pas majuscule et minuscule.
 *)

var	v 	: VARIABLE;

begin
	identificateur := minuscule(identificateur);
	if maxavail < sizeof(RECORD_VARIABLE) then begin
		erreur_interpreteur := PAS_ASSEZ_MEMOIRE;
		cree_variable_chaine :=	nil;
	end else begin
		new(v);
		v^.type_variable := VARIABLE_CHAINE;
		v^.identificateur := identificateur;
		v^.chaine := chaine;
		insere_variable(v);
		cree_variable_chaine :=	v
	end;
end;

function cherche_variable (identificateur : string) : VARIABLE;
(* Cherche la variable identifi‚ par identificateur dans la table de hashage,
 * et renvoie un pointeur sur la structure de controle de celle-ci, ou nil si
 * elle n'existe pas.  Cette fonction ne diffencie pas caractŠres majuscules
 * et minuscules.
 *)

var	v 	: VARIABLE;

begin
	identificateur := minuscule(identificateur);
	v := table_hashage[hash(identificateur)];
	while (v <> nil) and (v^.identificateur	<> identificateur) do
		v := v^.lien;
	cherche_variable := v;
end;

begin
	initialise := false;
end.