MATH FOR DELPHI ET MATH IN DELPHI: UNE BIBLIOTHÈQUE, UN ÉDITEUR ET UN ANALYSEUR

JnBiz Messages postés 18 Date d'inscription mardi 18 avril 2006 Statut Membre Dernière intervention 30 mai 2006 - 24 mai 2006 à 17:05
cs_zm Messages postés 9 Date d'inscription vendredi 10 février 2006 Statut Membre Dernière intervention 4 août 2012 - 17 nov. 2011 à 23:20
cs_zm Messages postés 9 Date d'inscription vendredi 10 février 2006 Statut Membre Dernière intervention 4 août 2012
17 nov. 2011 à 23:20
les packages sont compatible avec delphi 2010 et delphi xe.
le package OTAExpress non
pascal555 Messages postés 2 Date d'inscription mardi 18 décembre 2007 Statut Membre Dernière intervention 27 décembre 2007
27 déc. 2007 à 10:36
Grand merci à toi FORMAN
J'inclue les fonctions ci-dessus en supplément des composants de base.
Merci encore de ton aide.
Bon développement pour l'année qui vient.
Pascal
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
26 déc. 2007 à 23:40
Un exemple de fonction qui crée une fonction mathématique à partir d'un chaine (peut-être qu'il y a des erreurs de syntaxe, j'écris de mémoire et je n'ai pas testé).

function CreateFunction(s:string;NameSpace:TMathNameSpace=nil):TVariantProcObject;
var
m:TMathExecuter;
begin
GCurrentNameSpace:=NameSpace;
try
try
m:=TMathExecuter.Create(s); {Ici la chaine de caractères de l'expression mathématique est utilisée}
Result:=m.Execute(nil);
finally
m.Destroy;
end;
finally
GCurrentNameSpace:=nil;
end;
end;

Exemple d'utilisation:

var
f:TVariantProcObject;
NS:TMathNameSpace;
VarX,VarY,VarZ:TMathVar;
begin
NS:=TMathNameSpace.Create(nil); {On crée un TMathNameSpace}
VarX:=NS.Vars.Add; {On définit 3 variables supplémentaires dans le TMathNameSpace}
VarY:=NS.Vars.Add;
VarZ:=NS.Vars.Add;
VarX.Name:='x'; {On définit le nom des 3 variables}
VarY.Name:='y';
VarZ.Name:='z';
f:=CreateFunction('x*y+z^2',NS); {On compile une expression mathématique qui utilise les variables du namespace}
VarX.Value:=1; {On attribue des valeurs aux 3 variables}
VarY.Value:=2;
VarZ.Value:=3;
ShowMessage(IntToStr(f.Execute)); {Affiche la valeur de 1*2+3^2 c'est à dire 11}
VarX.Value:=0; {On attribue 3 autres valeurs aux variables}
VarY.Value:=10;
VarZ.Value:=100;
ShowMessage(f.Execute); {Affiche la valeur de 0*10+10^2 c'est à dire 100}
f.Destroy; {On détruit la formule compilée}
NS.Destroy; {On détruit le TMathNameSpace}
end;
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
26 déc. 2007 à 23:24
@Pascal555: désolé j'ai manqué ta question. Je n'ai pas écrit les composants pour faire directement ce que tu dis: en effet, pourquoi passer par l'évaluation d'une chaine de caractères alors qu'il suffit de taper directement la formule dans le code? L'idée était de laisser l'utilisateur entrer lui-même la formule (en particulier pour avoir accès aux erreurs de syntaxe dans le source). Ainsi il suffit d'avoir disposé (sur une fiche par exemple) un TMathFormula (muni éventuellement d'un TMathNameSpace) et lorsque l'utilisateur clique dessus la formule est changée (avec ce qu'il a tapé, et la garantie que la formule est syntaxiquement valide). Ensuite, il suffit d'appeler la méthode Execute du TMathFormula pour avoir le résultat (sous forme d'un variant).

Il est quand même possible de parser et exécuter une chaine de caractères contenant une formule ainsi:

function EvalString(s:string):Variant; {À la place de Variant on peut mettre Integer ou Double par exemple}
var
m:TMathExecuter;
f:TVariantProcObject;
begin
GCurrentNameSpace:=MathNameSpace1; {Pas obligatoire, un TMathNameSpace est utilisé ici pour pouvoir utiliser éventuellement les fonctions usuelles et des variables/fonctions supplémentaires. Sinon, faire GCurrentNameSpace:=nil;}
try
try
m:=TMathExecuter.Create(s); {Ici la chaine de caractères de l'expression mathématique est utilisée}
f:=m.Execute(nil);
try
Result:=f.Execute;
finally
f.Destroy;
end;
finally
m.Destroy;
end;
finally
GCurrentNameSpace:=nil;
end;
end;

L'objet f qui est utilisé dans cette fonction est une formule compilée. Puisqu'on ne l'utilise qu'une fois, on le détruit aussitôt après, mais il est possible de le garder en mémoire et de l'utiliser plusieurs fois: ainsi on pourrait mettre comme chaine de caractère une fonction qui dépend d'une variable (exemple: 'cos(x)+x^3+2*x^2+5') à condition d'avoir défini la variable x dans le TMathNameSpace utilisé, dans ce cas il suffira d'attribuer une valeur à x (dans le TMathNameSpace) et losqu'on fera f.Execute, la valeur de x sera automatiquement substituée.
cs_zm Messages postés 9 Date d'inscription vendredi 10 février 2006 Statut Membre Dernière intervention 4 août 2012
23 déc. 2007 à 17:46
merçi Forman
J'ai réussi à installer les packages delphi 7 et BDS 2006
et j'ai tester les exemples avec D7 et BDS 2006 ,las compitiont et l'execution c'est dérouler sant problémes
pascal555 Messages postés 2 Date d'inscription mardi 18 décembre 2007 Statut Membre Dernière intervention 27 décembre 2007
18 déc. 2007 à 23:43
Formidable travail sincérement !
Mais je n'arrive pas à trouver la fonction simple qui permet d'envoyer les opérations en récupérant le résultat.
exemple : result=CALCUL(5+1);
Si tu peux m'aider, tu serais génial.
Mais tu l'ai déjà.
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
1 nov. 2006 à 16:58
D'accord je vois ce que tu veux dire, je croyais que tu me demandais comment définir de nouvelles fonctions à plusieurs variables.

Pour ajoutter des variables supplémentaires, c'est pareil (tu peux regarder l'exemple du zip qui trace une courbe, j'utilise ce principe-là). Il faut utiliser la propriété Vars d'un TMathNameSpace (qui est aussi un descendant de TCollection) et ajoutter des TMathVar dedans (là encore, tu peux faire ça pendant le design dans l'inspecteur d'objet, ou pendant l'exécution). Par exemple tu peux ajoutter 2 TMathVar dans la liste qui s'appelent x et y. Ensuite, lorsque tu compiles une expression mathématique, avant d'exécuter le résultat, tu peux changer la valeur de x et y comme ceci:

MathNameSpace.Vars[0].Value:=2; { là x vaut 2 }
MathNameSpace.Vars[1].Value:=-1.5; { là y vaut -1.5 }

c'est le même principe que j'utilise pour tracer la courbe (sauf que je ne modifie qu'une seule variable). Lorsque tu as une formule compilée (de type TVariantProcObject) obtenue avec un TMathCompiler par exemple, cet objet a une méthode Execute qui retourne un Variant (la valeur de l'expression) et si tu modifies x et y avant de l'appeler, tu peux ainsi avoir une fonction qui dépend de ces 2 variables.
tybman Messages postés 5 Date d'inscription jeudi 2 octobre 2003 Statut Membre Dernière intervention 31 octobre 2006
31 oct. 2006 à 18:09
Peux tu réaliser un exemple de "parsage" pour fonction de deux variable si c'est pas trop te demander
Merci de ta réponse
tybman Messages postés 5 Date d'inscription jeudi 2 octobre 2003 Statut Membre Dernière intervention 31 octobre 2006
31 oct. 2006 à 16:57
J'ai plus ou moins compris supposons que je veuille calculer dans un MathCalculatorHistory à partir d'un syntaxHighlightMemo
Exp(x)*y+1

Je fais comment???
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
31 oct. 2006 à 14:51
Bien sûr c'est possible. Le composant TMathNameSpace sert à cela: il suffit de rajoutter une TMathFunc dans sa propriété Funcs (qui est un descendant de TCollection).

Un TMathFunc a une propriété Name: le nom de la fonction et 5 événements:
-procedure OnCalcValue(Sender: TObject; const Params: array of TVariantProcObject; var Value: Variant);
cet événement est utilisé pour calculer la valeur retournée par la fonction. Par exemple si on veut faire une fonction Sum(x,y) qui renvoie le résultat de la somme de x et y il suffit de faire:
Value:=Params[0].Execute+Params[1].Execute;

-procedure OnCheckParams(Sender: TObject; Params: array of TVariantProcObject; AdditionalVars: TStrings);
cet événement est utilisé pendant la compilation d'une expression pour vérifier que le nombre et la nature des paramètres passés à la fonction sont valides. Il suffit de déclencher une exception (si possible avec un message explicite) dans le cas contraire, et le message sera affiché dans le TCompileErrorManager comme une erreur de compilation. Par défaut la propriété ParamCount sert à définir un nombre de paramètres fixes pour les fonctions qui ont toujours le même nombre de paramètres, et dans ce cas-là il n'est pas nécessaire de vérifier le nombre des paramètres, le système s'en charge tout seul.
Par exemple la fonction Cos:
ParamCount=1, pas besoin de définir OnCheckParams
Autre exemple la fonction Max(x1,x2,...,xn) avec un nombre de paramètres variable:
ParamCount=0, il suffit juste de vérifier dans OnCheckParams que High(Params)>-1 (c'est à dire que la fonction est appelée avec au moins un paramètre)

Le paramètre AdditionalVars est utilisé pour les variables formelles. Par exemple:
Sum(i,1,10,i^2) qui calcule la somme pour i variant de 1 à 10 de i²: on vérifie d'abord que le premier paramètre de la fonction Sum est une variable, et on l'ajoutte à AdditionalVars en tant que variable à portée locale à l'intérieur de l'appel de la fonction.


-procedure OnCustomCreateBox(Sender: TObject; Display: TMathDisplay; Params: array of TVariantProcObject; var Box: TBox);
Utilisé pour définir un affichage personalisé de la fonction dans les formules mathématiques. Si cet événement n'est pas défini, la fonction est simplement notée f(...)
Par exemple la fonction Sum a un affichage personalisé (avec le symbole sigma).

-procedure OnForceSupPriority(Sender: TObject; SupObject: TVariantProcObject; Params: array of TVariantProcObject; var Force: Boolean);
Utilisé pour définir des priorités opératoires pour l'attribution de parenthèses. Par défaut, aucune parenthèse n'est ajouttée autour de l'appel de fonction, mais certaines fonctions personalisées (comme Sum) en ont besoin.

-procedure OnJump(Sender: TObject);
Cet événement est appelé lorsque l'utilisateur a cliqué sur le nom de la fonction dans l'éditeur. Cela sert à afficher un fichier d'aide par exemple.
tybman Messages postés 5 Date d'inscription jeudi 2 octobre 2003 Statut Membre Dernière intervention 31 octobre 2006
31 oct. 2006 à 11:55
Bonjour,
Je trouve ce code incroyable, le top, rien à dire.
Juste une question sur le parser est il possible de gérer une fonction de plusieurs variables ?(l'évaluer)
yvessimon Messages postés 637 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 9 janvier 2017
3 août 2006 à 08:47
Merci

L'extraction se fait normalement

Salutations
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
2 août 2006 à 16:43
J'ai uploadé un nouveau fichier zip, cette fois-ci c'est un vrai .zip (j'ai dû modifier la qualité des images pour que ça ne dépasse pas la limite des 1MO pour le site). Tu devrais pouvoir ouvrir celui-ci sans problème, mais la qualité des captures est assez mauvaise... :-(
yvessimon Messages postés 637 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 9 janvier 2017
2 août 2006 à 13:44
Bonjour,

Après plusieurs essais d'extraction je n'arrive a avoir le programme même en modifiant zip par rar.

Quelle méthode utiliser ou sur quel système ?

Salutations
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
30 mai 2006 à 20:52
>JnBiz: je vais faire une version "light" de OTAExpress, je la poste bientôt et elle devrait s'installer pour Delphi 5,6 et 7 (mais avant je ne sais pas).

Après, le seul composant qui pourrait encore poser problème est TIDEDockingForm (c'est un composant interne de Delphi qui a pu changer au cours de l'évolution de Delphi, dont la fenêtre de la calculatrice hérite).

Ceci dit, si tu as réussi à installer les 2 premiers packages, tu peux utiliser les composants pour faire des maths, et compiler les 2 programmes d'exemple. Les packages OTAExpress et MathIDEIntegration contiennent seulement des plugins/améliorations pour Delphi.
JnBiz Messages postés 18 Date d'inscription mardi 18 avril 2006 Statut Membre Dernière intervention 30 mai 2006
30 mai 2006 à 20:13
J'ai réussi à installer les 2 premiers packages, mais lors de l'installation de OTAexpress, j'obtiens ceci:
[Pascal Hint] OTAKeyBoard.pas(45): H2365 Override method TOTACustomKeyBoard.DoUnRegister should match case of ancestor TNotifierComponent.DoUnregister
[Pascal Error] OTABufferOptions.pas(79): E2003 Undeclared identifier: 'GetHighlightCurrentLine'
[Pascal Error] OTABufferOptions.pas(79): E2003 Undeclared identifier: 'GetShowLineBreaks'
[Pascal Error] OTABufferOptions.pas(79): E2003 Undeclared identifier: 'SetHighlightCurrentLine'
[Pascal Error] OTABufferOptions.pas(79): E2003 Undeclared identifier: 'SetShowLineBreaks'
[Pascal Fatal Error] OTAExpress_D7.dpk(48): F2063 Could not compile used unit 'OTABufferOptions.pas'
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
29 mai 2006 à 22:23
JnBiz: Effectivement, j'y ai passé du temps (ça fait 6 mois que j'ai commencé, mais je n'y ai pas touché pendant un long moment entre temps). Ce qui m'a pris le plus de temps c'est COW (le plugin Delphi pour faire des grammaires formelles) et l'éditeur de code.

Tu pourrais me décrire les messages d'erreur que tu as eu? A priori les 2 premiers packages doivent être compatibles avec les autres versions de Delphi. Seule la calculatrice et OTAExpress ne le sont pas pour l'instant (du moins en théorie, je n'ai pas d'autre version de Delph installée)...
JnBiz Messages postés 18 Date d'inscription mardi 18 avril 2006 Statut Membre Dernière intervention 30 mai 2006
29 mai 2006 à 20:55
Je confirme c'est assez énorme comme boulot, tu as du y passer du temps.

Si tu as si peu de commentaires c'est peut-être parce que beaucoup n'ont pas réussi à l'installer (Moi j'y arrive toujours pas).

En tout cas ca m'interesse cette source.
Serait-il possible que tu la rende compatible avec d'autres versions ?
a+
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
28 mai 2006 à 21:28
Cool des commentaires!
Je me demandais si personne n'allait le voir!

J'attends de tes nouvelles fOxi ;-)
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 34
28 mai 2006 à 20:27
mmm enorme boulot ....
j'en ai pas l'utilitée mais ça me semble vraiment pas mal et surtout complet.

je jette un oeuil au code ... ç'est trés interressant.
cs_Forman Messages postés 600 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 6 avril 2010 1
24 mai 2006 à 17:56
Je ne sais pas du tout si c'est compatible pour les versions>7.

Pour la génération de code, jette un coup d'oeil aux fichiers:
>Math.Lexer
>Math.Parser
>MathParser.ppas

et finallement
>MathParser.pas

Les 3 premiers servent à générer le 4ème, en utilisant un autre outil que j'ai programmé et qui s'intègre à Delphi: COW. L'idée est de définir une grammaire formelle (c'est à dire un ensemble de lois), et de faire générer par COW le code Delphi qui implémente une classe pour parser des chaînes de caractères selon cette grammaire, et contstruire l'arbre syntaxique associé.

Il existe d'autres outils du même type pour d'autres langages, par exemple Yacc ou Bison.

Du coup, le code obtenu est très optimisé et très rapide (même s'il est parfois très long, par exemple, le code-source généré pour ma grammaire mathématique fait plus de 5000 lignes!). C'est d'ailleurs un exemple de code-source qui une fois compilé occupe beaucoup moins de place qu'avant...

COW génère à partir de la grammaire (Math.lexer et Math.parser) la table des transitions d'un automate à pile déterministe, et l'écrit comme spécifié par les directives de pré-compilation (MathParser.ppas) dans un "vrai" fichier Pascal (MathParser.pas).

Je posterai COW ainsi que ses sources prochainement sur le site...
JnBiz Messages postés 18 Date d'inscription mardi 18 avril 2006 Statut Membre Dernière intervention 30 mai 2006
24 mai 2006 à 17:05
Ca m'a l'air cool tout ca.
C'est dommage, je viens d'effacer D7 pour passer à BDS 2006, mais bon, j'imagine qu'on doit quand même pouvoir l'installer sur les versions >D7.

Quand tu parles de génération automatique de code, de quoi s'agit il ?
Rejoignez-nous