program expression;
	uses
		Getclick;

	const
		Taille = 14; {cotˇ d'une case dans le dessin}
		MargeX = 2; {coordonnˇes du point d'origine du texte relativement}
		MargeY = 10;{au coin supˇrieur gauche de la case qui le contient}


	type
		Typecle = char;
		TypeNoeud = (Operateur, Variable, Constante);
		Arbre = ^Noeud;
		Noeud = record
				genre: TypeNoeud;
				val: char;
				filsG, filsD: Arbre;
			end;

	var
		e, f: Arbre;
		p: point;

	function CreerArbre (genr: TypeNoeud; valeur: char; g, d: Arbre): Arbre;
		var
			expression: Arbre;
	begin
		new(expression);
		with expression^ do
			begin
				genre := genr;
				val := valeur;
				filsD := d;
				filsG := g
			end;
		CreerArbre := expression
	end;

	function CopierArbre (e: Arbre): Arbre;
		var
			expression: Arbre;
	begin
		if e = nil then
			expression := nil
		else
			begin
				with e^ do
					expression := CreerArbre(genre, val, CopierArbre(filsG), CopierArbre(filsD));
				CopierArbre := expression;
			end;
	end;

	function Derive (e: Arbre; x: char): Arbre;
		var
			der: Arbre;
			deragauche, deradroite: Arbre;
	begin
		if e = nil then
			der := nil
		else
			begin
				case e^.genre of
					Constante: 
						der := CreerArbre(Constante, '0', nil, nil);
					Variable: 
						if e^.val = x then
							der := CreerArbre(Constante, '1', nil, nil)
						else
							der := CreerArbre(Constante, '0', nil, nil);
					Operateur: 
						case e^.val of
							'+': 
								der := CreerArbre(Operateur, '+', Derive(e^.filsG, x), Derive(e^.filsD, x));
							'*': 
								begin
									deradroite := CreerArbre(Operateur, '*', e^.filsG, Derive(e^.filsD, x));
									deragauche := CreerArbre(Operateur, '*', Derive(e^.filsG, x), e^.filsD);
									der := CreerArbre(Operateur, '+', deragauche, deradroite);
								end;
						end;
				end;
			end;
		Derive := der;
	end;

{----------------------------------partie dessin d'un arbre-expression-------------------------------}
	procedure dessinelem (x, y: integer; s: Typecle);
{dessin d'un carre pour representer un noeud comportant}
{des cles ayant au plus deux caracteres}
		var
			r: rect;
	begin
		SetRect(r, x, y, x + Taille, y + Taille);
		EraseRect(r);
		FillRect(r, white);
		MoveTo(x + MargeX, y + MargeY);
		WriteDraw(s : 2);
		FrameRect(r);
	end;

	function arbrevide (e: Arbre): boolean;
	begin
		arbrevide := (e = nil)
	end;

	procedure Dessin (e: Arbre);
		var
			r: rect;
			dx, dy, y, xmin, xrac, xmax: integer;

		procedure dessinrec (e: Arbre; y, xmin: integer; var xrac, xmax: integer);
			var
				xxmin, xxrac, xxmax: integer;
		begin
			if arbrevide(e) then
			else
				begin
					if not arbrevide(e^.filsG) then
						begin
							xxmin := xmin;
							dessinrec(e^.filsG, y + dy, xxmin, xxrac, xxmax);
							xrac := xxmax + dx;
							moveto(xxrac, y + dy);
							lineto(xrac, y);
							dessinelem(xxrac - 2 - MargeX, y + dy - MargeY, e^.filsG^.val);
						end
					else
						xrac := xmin;
					if not arbrevide(e^.filsD) then
						begin
							xxmin := xrac + dx;
							dessinrec(e^.filsD, y + dy, xxmin, xxrac, xxmax);
							xmax := xxmax;
							moveto(xxrac, y + dy);
							lineto(xrac, y);
							dessinelem(xxrac - 2 - MargeX, y + dy - MargeY, e^.filsD^.val);
						end
					else
						xmax := xrac;
				end;
		end;

	begin
		SetRect(r, 20, 40, 700, 400);
		SetDrawingRect(r);
		ShowDrawing;
		dx := 30;
		dy := 30;
		y := 10;
		xmin := 10;
		dessinrec(e, y, xmin, xrac, xmax);
		if not arbrevide(e) then
			dessinelem(xrac - 2 - MargeX, y - MargeY, e^.val);
	end;
{-------------------------------------------------------------------------------}

begin
	e := CreerArbre(Constante, '1', nil, nil);
	e := CreerArbre(Operateur, '+', CreerArbre(Variable, 'x', nil, nil), e);
	e := CreerArbre(Operateur, '*', CreerArbre(Variable, 'y', nil, nil), e);
	e := CreerArbre(Operateur, '*', CreerArbre(Constante, '3', nil, nil), e);
	Dessin(e);
	GetClick(p);
	f := Derive(e, 'x');
	Dessin(f);
	GetClick(p);
	f := Derive(e, 'y');
	Dessin(f);
end.