unit interpreteur;
{$INCLUDE ParserConfiguration.txt }
{ this defines if we are in a "PILOTAGE" or "TRAITEMENT" configuration }

{à jour le 30/10/00}
{ 17/11/00 (E.Leymarie) ajout de fonctions pour le comptage deux D et la RMN :  }
{- delay[t] : pause de t seconde dans l'exécution du batch                       }
{- acqsimple2D[TT, "wait"] : démarre une acquisition neutron 2D de TT secondes. Si le deuxième champs est ²wait², l'interpreteur attend la fin de l'acquisition avant de passer à la ligne suivante.
{- testacqsimple2D : test la fin de l'acquisition acqsimple2D. la variable acq2d de l'interpreteur est initialisée à 1 si l'acquisition est encore en cours et à 0 si elle est terminée.
{- RMNsaturation[  t] : démarre une saturation de t ms. L'interpreteur est bloqué pendant la saturation.
{- RMNlitpolar[npassages] : lit la polarisation nucléaire en npassages. Place le résultat dans les variables temps et polar de l'interpreteur.
{- RMNavecBase["true"] : permet de faire des spectres RMN avec ou sans signal de base.
{- Addpol[x,y] : ajoute un point dont les coordonnées sont les variables x et y de l'interpreteur dans la fenêtre visupol.
{- Clearvisupol : permet de réinitialiser visupol
{ Modification de interpreteurform.Timer1Timer pour arrêter l'interpreteur pendant une acquisition 2d ou RMN
{ Ajout de nouvelles variables dans l'interpreteur :                            }
{	Variables RMN (si RMNacqui existe) : polar et temps.                    }
{	Variable acquisition 2D (si comptage2D existe) : acq2d.                 }
{ 13.12.00 : FO : ajout d'une procédure lecture spectre, ligne 192              }
{              ReadSpectre1D et ReadSpectre2D                                   }
{              nouvelle procédure AcqSimplePSD                                  }
{              nouveau flag FlagWaitAcquisPSD                                   }
{ 10.01.01 : FO : procedure pour fixer le courant dans la BOSS508               }
{              il manque une initialisation qqe part                            }
{              la BOSS n'accepte pas une rafale de commandes                    }
{ 26.01.01 : FO : setFieldL, pilotage de la bobine supra                        }
{ 02.02.01 : FO : fonctionnement du bouton "continue" corrigé A TESTER !!!      }
{ 15.02.01 : FO : ajout d'une directive de compilation pour qu'on puisse utiliser traitement sans trainer toutes les unités du programme de pilotage }
{               $DEFINE PILOTAGE                                                }
{               $DEFINE TRAITEMENT                                              }
{ 14.03.01 : FO : ajout de quelques fonctions de base Scal2D, Add2D, Sub2D      }
{                 delSpectre2D, saveToASCII2D                                   }
{ 15.03.01 : CL :ajout des autres fonctions de base MultSpect, DivSpect, ScalAddSpect, }
{               ScalSubSpect, ScalMultSpect,ScalDivSpect                        }
{ 27.03.01 : EL :Modifications suite au couplage Traitement/pilotage:           }
{                L 297: ajout du 3eme parametre a addspectre,                   }
{                L 323: idem pour addpt,                                        }
{                L 61: ajout de graph2D dans les USES pilotage,                 }
{ 03.04.01 : FO : nouvelles procédures                                          }
{                   function SetX2D:integer;far;   function SetY2D:integer;far; }
{                   function Concat1D;                                          }
{                   function Remap2DtoQxQz:integer;far                          }
{ 06.06.01 : FO : ajout des procédures SetCurrentFXY pour le reglage automatique des flippers }
{ 12.06.06 : EL : ajout setExpCond et SetComment                                }
{ 15.06.01 : EL : nouvelle fonction SommeDNPA pour somme petits angles exacte   }
{ 9.07.01 : EL : nouvelle fonction masquesecteur                                }
{ 10.07.01 : EL : - Création de openspectre qui permet d'ouvrir un spectre au nouveau format}
{                 - Création de NormMoniSpectre2D qui normalise le moniteur d'un spectre 2D }
{ 16.07.01 : EL : Modification de la procedure traitstring pour utilisation du parametre string des variables }
{                 effet - les tableaux pars et par sont réinitialisés avant chaque instruction, }
{                        - en cas d'utilisation de variable, le parametre pars[i] est initialisé à la valeur de la variable et non a son nom comme precedement }
{                       - pour toute fonction, pars[i]=nom$ entraine l'initialisation pars[i]:=nom.p4     (le caractere # devient reserve) }
{                       - pour toute fonction, pars[i]=@nom entraine l'initialisation pars[i]:=nom    (le caractere @ devient reserve)  }
{                 création de setstring. permet d'initialiser la valeur de p4   }
{16.07.01 : EL : Création de variables type tableau                             }
{                - création du parametre tvaripar.p5 array of real              }
{                - création de la fonction settab[@nom,indice,value1,value2,...]  pour initialiser 7 elements du tableau nom}
{                - modification de la procedure traitstring :                   }
{                  l'utilisation de nom#expression entraine par[i]=nom.p5[expression]}
{18.07.01 : EL : Netoyage divers                                                }
{20.09.01 : EL : plus nouvelles procedures StartPolAlt,initTOF,startTOF,ReadDataTOF,RMNirrad }
{                 modification de acqsimple2D,testacqsimple2D,addcomment et de la procedure ScriptStopButtonClick pour inclure PAPOL }
{21.09.01 : EL: modification des procedures savetoASCII                         }
{30.10.01 : FO : mise a jour de la position de départ de la fenetre dans FormCreate }
{07.12.01 : EL : Mise a jour de la procedure Spectre3DTo2D                      }
{08.02.02 : EL : Ajout de la fonction OpenPaxy                                  }
{ 30.03.02 : FO : nouvelle fonction concat2D pour concatener 2 spectres 2D (ayant des coordonnées différentes) }
{ 31.02.02 : FO : ajout de deux fonctions appendRow et appendCol                }
{                 in : "Monspectre2D" et "MonSpectre1D", abscisses en pixels !! }
{ 02.04.02 : FO : nouvelle fonction : Extract2D["ACUP", xmin, ymin, xmax, ymax, "toto"] }
{ 05.04.02 : FO : nouvelle fonction racine carrée "sqrt1D" et "sqrt2D"          }
{                 pour calculer les barres d'erreurs                            }
{ 08.04.02 : FO : nouvelle fonction de moyenne glissante "smooth1D"             }
{                 <smooth1D> "spectrein" "nbr de points de moyenne" IMPAIR!, "spectre out" }
{ 02.10.02 : TDD: fonction Resize1D pour redimensionner la taille du spectre 1D }
{                 fonction Convert1Dto2DrowY, idem Convert1Dto2DRow avec le choix de y}
{                 fonction Convert1Dto2DcolX, idem Convert1Dto2DCol avec le choix de y}
{                 fonction AppendRowY, AppendColX ,idem AppendRow avec le choix de y  }
{ 08.12.02 : Fo : nouvelle fonction "SommeCirculaireSpectre2D"                  }
{ 16.04.03 : FO : nouveau traitement es paramètres des functions de l'ionterpréteur }
{                 les chaines peuvent maintenant contenir les caractères ',' et '=' }
{ 27.04.05 : FO : utilisation d'un fichier inclu pour defirni les directives de compilation }
{                 cela permet d'eviter les collisions entre SPectraProcessor et Spectrodriver}
{ ============================================================================= }
{ A FAIRE                                                                       }
{ * il faut réactiver les FlagWaitXXX                                           }
{   la procedure T1Timer a été firtement amputée pour le passage à la version 3.0  }
{ * régler le problème des <= et des <                                          }
{ * extract2D n'est pas au point -> les coupes 1D ne se font pas bien !         }
{   problème lié à la première colonne en X qui s'initialise à zéro?            }
{ * resize1D ne fonctionne pas tout à fait -> on ne peut pas se débarrasser des data }
{ documenter les functions : INPUT; OUTPUT, IMPLICIT CHANGES                    }
{ * les arguments de SaveSpectre sont dans un ordre douteux                     }
{ * pourquoi addpt peut-il marcher avec des spectres 2D ?                       }
{ * FAIRE UN SYNTAXE CHEKCKER SUR LE PARSER ET AMELIORER LA GESTION DES ERREURS }
{ * update des combo après les calculs                                          }
{ * mettre a jour la liste des fonctions disponibles                            }
{ * procédures pour les calculs sur les spectres 1D                             }
{   toujours definir les types des data dans les spectres 2D i.e. au moins "='raw' !!! }
{ * IL FAUT DES MESSAGES D'ERREURS pour les I/O sur le disque                   }
{   sinon on ne sait pas ce qui se passe                                        }
{ * quand on fait des copier-coller dans le parser ca marche mal en general     }
{ * il y a un petit bug ligne 606 pari[i] fait un Range Check error             }
{   ok si on désactive "verification des limites"                               }

interface
{$IFDEF PILOTAGE }
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, multimemo, Parser10, StdCtrls, Menus, Db, DBTables,editdata, graph2D,
  JvComponent, JvFormPlace;
{$ENDIF }

{$IFDEF TRAITEMENT }
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, multimemo, Parser10, StdCtrls, Menus, Db, DBTables, editdata,graph2D,
  JvComponent, JvFormPlace, math;
{$ENDIF }

const
repseq='c:\sequences\';
seqext='.seq';
wm_redessine=$403+wm_user;

type EvarError = class(Exception);

type
tvaripar = class(tobject)
       public
       value:extended;
       p1:integer;
       p2:double;
       p3:double;
       p4: string;
       p5: array of real;
end;
type
  Tinterpreteurform = class(TForm)
    Panel1: TPanel;
    Parser1: TParser;
    ScriptExecuteButton: TButton;
    Timer1: TTimer;
    ScriptExecuteSelectionButton: TButton;
    ScriptStopButton: TButton;
    Panel2: TPanel;
    Edit1: TEdit;
    Label1: TLabel;
    mem1: tmultimemo;
    MainMenu1: TMainMenu;
    suividevariable1: TMenuItem;
    variables1: TMenuItem;
    fonctions1: TMenuItem;
    ContinueButton: TButton;
    fonctionsmathmatiques1: TMenuItem;
    fonctionsduprogramme1: TMenuItem;
    ScriptStatus: TLabel;
    Parser2: TMenuItem;
    JvFormPlace1: TJvFormPlace;
    procedure FormCreate(Sender: TObject);
    procedure ScriptExecuteButtonClick(Sender: TObject);
    procedure ScriptExecuteSelectionButtonClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Timer1Timer(Sender: TObject);
    procedure suividevariable1Click(Sender: TObject);
    procedure ScriptStopButtonClick(Sender: TObject);
    procedure ContinueButtonClick(Sender: TObject);
    procedure variables1Click(Sender: TObject);
    procedure fonctions1Click(Sender: TObject);
    procedure Parser1ParserError(Sender: TObject; E: Exception);
    procedure Edit1KeyDown(Sender: TObject; var Key: Word;Shift: TShiftState);
  private
    { Déclarations privées}
    filename:string;
    actlig,actligf:tstringlist; {tableau des ordres à effectuer}
    procedure addmotorlist;
    procedure pretraitement;
    procedure execution;
    function traitstring(s:string;ind:integer):integer;
   public
    { Déclarations publiques}
    seqencours:integer;{sequence en cours}
    procedure addvariable(name:string;value:integer;p1:integer;p2:double;p3:double;p4:string;tpro:tobject);
    procedure setvaleur(name:string;value:double);
    procedure executeseq(name:string);
 end;

var
  interpreteurform: Tinterpreteurform;

implementation
{$IFDEF PILOTAGE }
uses variablesliste, functionsliste, interfaceMoteurs, SuiviAcquisitionPRISM,
  BoiteNoire, gpib_CEC, RMNbases, visu_polarisation,
  InterpreteurBase, InterpreteurComptage, InterpreteurDevices, InterpreteurFileIO, InterpreteurSpectra, InterpreteurMoteurs,
  ComptageMSGC_G56, ComptagePSDform, ComptageEROS;
{$ENDIF }
{$IFDEF TRAITEMENT }
uses variablesliste, functionsliste, BoiteNoire, FilesIO,
     InterpreteurBase, InterpreteurSpectra, InterpreteurFileIO;
{$ENDIF }

var
  ordre,variable,varpar,labels:tstringlist;
  par:parametresNum;
  pars:parametresStr;
  param:array[0..200] of tvaripar;
  labelstab:array[0..26] of integer;
  seqon,seqlig:integer;

{****************************************************************************}
{                      DEBUT de l'interpreteur}
{****************************************************************************}

{$R *.DFM}

{ ces fonctions sont appelable à partir du script mais elles font appel à des   }
{ affectations directes à "Variable" et donc sont renvoyées dans cette unitée   }
    {fonction permettant d'initialiser le parametre p4 de la variable pars[1] }
    {cette fonction concat l'ensemble des elements de pars (sauf le premier}
    { INPUT: pars[1] : nom de la variable (entrée en @nom)
             pars[2..10] : éléments concatenes
    {OUPUT : le parametre p4 de la variable nom}
    function Setstring(par:parametresNum;pars:parametresStr):integer;
    var temp:string;
        i:integer;
    begin
      temp:='';
      for i:=2 to 10 do  temp:=temp+pars[i];
      param[variable.indexof(pars[1])].p4:=temp;
    end;

    {fonction permettant d'initialiser le tableau p5 de la variable pars[1] }
    { INPUT: pars[1] : nom de la variable (entrée en @nom),
             par[2] : indice de départ,
             par[3],..., par[10]: valeur
    {OUPUT : les parametres p5[par[2]],...,p5[par[2]+7] de la variable pars[1]}
    function Settab(par:parametresNum;pars:parametresStr):integer;
    var vind:integer;
        i:integer;
    begin
    vind:=variable.indexof(pars[1]);
    for i:=0 to 7 do
        if pars[3+i]<>'' then
        begin
        {verification taille }
        if length(param[vind].p5)<(round(par[2])+i+1 ) then setlength(param[vind].p5,round(par[2])+i+1);
        {affectation}
        param[vind].p5[round(par[2])+i]:=par[i+3];
        end;
    end;

    { fonction spécifique aux moteurs }
    { elle uilse directement la table des variables et je ne peux donc pas la sortir }
    { de plus c'est une fonction bas niveau qui n'est pas appelé par l'interpreteur }
    function settable(s:string):integer;
    var i:integer;
    begin
    {$IFDEF PILOTAGE }
    i:=variable.indexof(s);
    if tabmot<>nil then tabmot.setval((param[i].p1),round(param[i].p2),round(param[i].value));
    result:=0;
    {$ENDIF }
    end;

    function fixtimer(s:string):integer;
    var
    i:extended;
    begin
    i:=param[variable.indexof(s)].value;
    if i=0 then
    interpreteurform.timer1.enabled:=false else
    interpreteurform.timer1.interval:=round(i);
    result:=0;
    end;

    function fixtemps(s:string):integer; far;
    begin
    {$IFDEF PILOTAGE }
    if suiviPRISMForm<>nil then suiviPRISMForm.fixtemps(round(param[variable.indexof(s)].value));
    result:=0;
    {$ENDIF}
    end;

    function comptcond(s:string):integer; far;
    begin
    {$IFDEF PILOTAGE }
    if suiviPRISMForm<>nil then suiviPRISMForm.comptcond(param[variable.indexof(s)].p1,round(param[variable.indexof(s)].value));
    result:=0;
    {$ENDIF}    
    end;

procedure Tinterpreteurform.FormCreate(Sender: TObject);
var i:integer;
begin
windowState:=wsMinimized;
left:=0;top:=401;width:=520;height:=270;
seqon:=0;
actlig:=tstringlist.create;
actligf:=tstringlist.create;
variable:=tstringlist.create;
varpar:=tstringlist.create;
ordre:=tstringlist.create;
labels:=tstringlist.create;
for i:=0 to 200 do param[i]:=tvaripar.create;
mem1.filter:='Séquences (*.seq)|*.seq|textes (*.txt)|*.txt';
mem1.defaultext:='.seq';
mem1.directory:=repseq;

{*********  Debut des déclaration propre à PILOTAGE}
{$IFDEF PILOTAGE }
{variables internes} {$INCLUDE VariablesBase.pas};
{variables de comptage} if suiviPRISMForm<>nil then {$INCLUDE VariablesPRISM.pas};
{variables RMN} { if RMNacqui<>nil then {$INCLUDE VariablesRMN.pas}; 
{variables acquisition 2D} { if comptage2Dform<>nil then {$INCLUDE VariablesComptage2D.pas};
{ajout des moteurs} 
if tabmot<>nil then addmotorlist;
{$INCLUDE FunctionsComptage.pas}
{$INCLUDE FunctionsDevices.pas}
{$INCLUDE FunctionsMoteurs.pas}
{$ENDIF }
{*********  Fin des déclaration propre à PILOTAGE}
ordre.addobject('setString',tobject(@setString));
ordre.addobject('setTab',tobject(@setTab));
{$INCLUDE FunctionsSpectra.pas}
{$INCLUDE FunctionsFileIO.pas}
{$INCLUDE FunctionsBase.pas}

{ création des labels de "la" à "lb" }
for i:=1 to 26 do begin labels.add('L'+chr(i+64));labelstab[i]:=0;end;
flagwaitchamp:=false;
flagwaittemp:=false;
flagwaitacquis:=false;
flagwaitacquisPSD:=false;
flagwaitmotor:=false;
end;

procedure Tinterpreteurform.addmotorlist;
var i:integer;
begin
{$IFDEF PILOTAGE }
{ on utilise la variable Mot plutot }
for i:=1 to NbrMoteurs do
   begin
   addvariable(Mot[i].nomcourt,0,i,3,0,'',tobject(@settable));
   addvariable(Mot[i].nomcourt+'dep',Mot[i].depart,i,4,0,'',tobject(@settable));
   addvariable(Mot[i].nomcourt+'fin',Mot[i].fin,i,5,0,'',tobject(@settable));
   addvariable(Mot[i].nomcourt+'inc',Mot[i].inc,i,6,0,'',tobject(@settable));
   addvariable(Mot[i].nomcourt+'zero',Mot[i].zero,i,7,0,'',tobject(@settable));
   addvariable(Mot[i].nomcourt+'val',0,i,8,0,'',tobject(@settable));
   end;

{tablemot.first;
while not tablemot.eof do begin
if (tablemotvalide.value=1)
then begin
   addvariable(tablemotnomcourt.value,0,tablemotindex.value,3,0,'',tobject(@settable));
   addvariable(tablemotnomcourt.value+'dep',tablemotdepart.value,tablemotindex.value,4,0,'',tobject(@settable));
   addvariable(tablemotnomcourt.value+'fin',tablemotfin.value,tablemotindex.value,5,0,'',tobject(@settable));
   addvariable(tablemotnomcourt.value+'inc',tablemotinc.value,tablemotindex.value,6,0,'',tobject(@settable));
   addvariable(tablemotnomcourt.value+'zero',tablemotzero.value,tablemotindex.value,7,0,'',tobject(@settable));
   addvariable(tablemotnomcourt.value+'val',0,tablemotindex.value,8,0,'',tobject(@settable));
   end;
tablemot.next; }

{$ENDIF }
end;

{ création d'une nouvelle variable }
procedure Tinterpreteurform.addvariable(name:string;value:integer;p1:integer;p2:double;p3:double;p4:string;tpro:tobject);
var i:integer;
begin
parser1.setvariable(name,value);
i:=variable.AddObject(name,tpro);
param[i].p1:=p1;param[i].p2:=p2;param[i].p3:=p3;param[i].p4:=p4;
varpar.AddObject(name,@param[i]);
end;

procedure Tinterpreteurform.setvaleur(name:string;value:double);
begin
parser1.setvariable(name,value);
end;

{ lancement d'une séquence de script
{ INPUT: utilise le text du memo en cours }
procedure Tinterpreteurform.ScriptExecuteButtonClick(Sender: TObject);
begin
actligf.text:=mem1.memo.text;
pretraitement;
execution;
end;

procedure Tinterpreteurform.ScriptExecuteSelectionButtonClick(Sender: TObject);
begin
actligf.text:=mem1.memo.seltext;
pretraitement;
execution;
end;

{prétraitement traite les inclusions}
procedure Tinterpreteurform.pretraitement;
var
i,tf:integer;
fich:tstringlist;
s:string;
begin
for i:=1 to 26 do labelstab[i]:=0;
actlig.clear;
fich:=tstringlist.create;
tf:=1;
{ajout des inclusions}
while tf<>0 do begin
tf:=0;
for i:=0 to actligf.count-1 do begin
{ajout du ; oublié}
if pos(';',actligf.strings[i])<=0 then actligf.strings[i]:=actligf.strings[i]+';';
actligf.strings[i]:=copy(actligf.strings[i],1,pos(';',actligf.strings[i]));
if copy(actligf.strings[i],1,4)<>'inc=' then begin
actlig.add(actligf.strings[i]);
end else begin
filename:=copy(actligf.strings[i],5,pos(';',actligf.strings[i])-5);
fich.loadfromfile(repseq+filename+seqext);
actlig.addstrings(fich);
tf:=1;
end;
end;
if tf<>0 then begin
actligf.text:=actlig.text;
actlig.clear;
end;
end;
{fin d'ajout des inclusions}
{assignation des labels}
for i:=0 to actlig.count-1 do begin
s:=actlig.Strings[i];
if (copy(s,3,1)=':') and (labels.indexof(copy(s,1,2))>=0) then
labelstab[labels.indexof(copy(s,1,2))]:=i;
end;
fich.free;
end;

procedure tinterpreteurform.execution {test d'une séquence pour écriture};
begin
{début de la realisation}
seqlig:=0;
seqon:=1;
flagwaitacquis:=false;
flagwaitacquisPSD:=false;
flagwaitEnergizing:=false;
timer1.enabled:=true;
ScriptStatus.caption:='Running...';
end;

function Tinterpreteurform.traitstring(s:string;ind:integer):integer;
label debut;
var
i,j:integer;
s2,sn,sval,nomvar:string;
retour:integer;
f:function(name:string):integer;
g:function(par:parametresNum;pars:parametresSTr):integer;
pari:string;
test,tu:boolean;
x,mon,tem:integer;
parCrt:string;
paraEnd,inString,inReal:boolean;
vind1D,vind2D,vind3D:integer;
begin
{$IFDEF PILOTAGE }
{lecture de paramètres externes avant l'exécution de l'instruction suivante}
{transfert des échelles de comptage dans le cas de PRISM}
if suiviPRISMForm<>nil then
   begin
   suiviPRISMForm.getcomptage(1,x,mon,tem);parser1.setvariable('Nupup',x);parser1.setvariable('Mupup',mon);
   parser1.setvariable('Tupup',tem);suiviPRISMForm.getcomptage(2,x,mon,tem);
   parser1.setvariable('Ndodo',x);parser1.setvariable('Mdodo',mon);
   parser1.setvariable('Tdodo',tem);
   suiviPRISMForm.getcomptage(3,x,mon,tem);
   parser1.setvariable('Nupdo',x);parser1.setvariable('Mupdo',mon);
   parser1.setvariable('Tupdo',tem);
   suiviPRISMForm.getcomptage(4,x,mon,tem);
   parser1.setvariable('Ndoup',x);parser1.setvariable('Mdoup',mon);
   parser1.setvariable('Tdoup',tem);
   end;

{$ENDIF }
retour:=ind+1;
debut:test:=false;
{chaine commentaire ou vide}
if (copy(s,1,1)=';') or (copy(s,2,1)=';') then test:=true;
{labels}
if (not test) and (copy(s,3,1)=':') and (labels.indexof(copy(s,1,2))>=0) then
s:=copy(s,4,length(s));
if (not test) and (copy(s,1,2)='if') then begin
{traitement du if}
 test:=true;
 if pos('then',s)<0 then
 begin
 timer1.enabled:=false;
 raise EvarError.Create('if sans then'+
 inttostr(ind)+':'+s);
 end;
 s2:=copy(s,4,pos('then',s)-5);
 tu:=false;
 if pos('>=',s2)>0 then begin
 sn:=copy(s2,1,pos('>=',s2)-1)+'-'+copy(s2,pos('>=',s2)+2,length(s2));
 parser1.expression:=sn;
 if parser1.value>=0 then tu:=true;
 end else
 if pos('<>',s2)>0 then begin
 sn:=copy(s2,1,pos('<>',s2)-1)+'-'+copy(s2,pos('<>',s2)+2,length(s2));
 parser1.expression:=sn;
 if parser1.value<>0 then tu:=true;
 end else
 if pos('<=',s2)>0 then begin
 sn:=copy(s2,1,pos('<=',s2)-1)+'-'+copy(s2,pos('<=',s2)+2,length(s2));
 parser1.expression:=sn;
 if parser1.value<=0 then tu:=true;
 end else
 if pos('=',s2)>0 then begin
 sn:=copy(s2,1,pos('=',s2)-1)+'-'+copy(s2,pos('=',s2)+1,length(s2));
 parser1.expression:=sn;
 if parser1.value=0 then tu:=true;
 end else
 if pos('<',s2)>0 then begin
 sn:=copy(s2,1,pos('<',s2)-1)+'-'+copy(s2,pos('<',s2)+1,length(s2));
 parser1.expression:=sn;
 if parser1.value<0 then tu:=true;
 end else
 if pos('>',s2)>0 then begin
 sn:=copy(s2,1,pos('>',s2)-1)+'-'+copy(s2,pos('>',s2)+1,length(s2));
 parser1.expression:=sn;
 if parser1.value>0 then tu:=true;
 end;
 if tu=true then begin
  s2:=copy(s,pos('then',s)+5,2);
  if labels.indexof(s2)>=0 then
  retour:=labelstab[labels.indexof(s2)] else
  begin
  s:=copy(s,pos('then',s)+5,length(s));goto debut;
  end;
 end;
end;
{fin du traitement if then}
if (not test) and (copy(s,1,4)='goto') then begin
s2:=copy(s,6,2);
  if labels.indexof(s2)>=0 then
  retour:=labelstab[labels.indexof(s2)];
test:=true;end;
{debut du traitement assignation de variables toto=10}
if (pos('=',s)>0) and not test then begin
test:=true;
sn:= copy(s,1,pos('=',s)-1);
if sn='' then raise  EvarError.Create('variable non valide à la ligne '+
inttostr(ind)+':'+s);
sval:=copy(s,pos('=',s)+1,pos(';',s)-pos('=',s)-1);
parser1.expression:=sval;
if not isvalidident(sn) then begin
timer1.enabled:=false;
raise  EvarError.Create('variable non valide à la ligne '+
inttostr(ind)+':'+s);
end else begin
try
if variable.indexof(sn)>=0 then begin
param[variable.indexof(sn)].value:=parser1.value;
@f:=variable.Objects[variable.indexof(sn)];
f(sn);
end;
parser1.setvariable(sn,parser1.value);
except begin
timer1.enabled:=false;
raise  EvarError.Create('variable non valide à la ligne '+
inttostr(ind)+':'+s);
end;
end;
end;
end;
{fin du traitement des variables}
{test des fonctions appelées}
if not test then begin
 if (pos('[',s)<=0) then
 begin
  pari:='';s2:=copy(s,1,pos(';',s)-1); { on recopie simplement le nom de la fonction appelée }
 end else begin
  s2:=copy(s,1,pos('[',s)-1); { s2 recoit le nom de la fonction appelée }
  pari:=copy(s,pos('[',s)+1,pos(']',s)-pos('[',s)-1);    {pari = argument d'une instruction}
 end;
if ordre.indexof(s2)=-1 then { test si la fontion appelée existe vraiment }
begin
timer1.enabled:=false;
raise EvarError.Create('fonction non valide à la ligne '+
inttostr(ind)+':'+s)
end else
begin

{traitement des parametres}
{clear du tableua de paramètres }         
   for j:=1 to maxPara do
     begin pars[j]:='';par[j]:=0; end;
   j:=1; { index du paramètre en traitement }
   parCrt:='';i:=1; { i index courant dans la chaine }
   inString:=false;InReal:=false; { flags indiqaunt si on traite un para string ou real }
   if pari<>'' then
   begin
      { extraction du premier paramètre }
      { le premier paramètre est-il une string? }
      paraEnd:=false; { on est arrivé au dernier paramètre }
      while (j<=maxPara) and (not(paraEnd)) do
      begin
      parCrt:='';inString:=false;InReal:=false;
      if pari[i]='"' then begin
                            inc(i);
                            while pari[i]<>'"' do
                            begin parCrt:=parCrt+pari[i];inc(i) end;
                            inc(i);
                            if pari[i]<>',' then paraEnd:=true;
                            inc(i);inString:=true;
                          end
                     else begin
                            while (pari[i]<>',') and (i<=length(pari)) do
                            begin parCrt:=parCrt+pari[i];inc(i) end;
                            if i>length(pari) then paraEnd:=true;
                            inc(i);inReal:=true;
                          end;
      { on passe systématiquement les paramètres en chaines (meme si real ou expr) }
      pars[j]:=parCrt;
      { traitement si on a pas explicitement une chaine de caractères }
      if InReal
      then begin
          {type variable ou expression}
          if  (pos('@',parCrt)=0) and (pos('$',parCrt)=0) and (pos('#',parCrt)=0) then
          begin {type expression numerique}
             { on verifie que les paramètres ne sont pas des noms de spectres }
             vind1D:=und.indexof(parCrt);vind2D:=deuxd.indexof(parCrt);vind3D:=troisd.indexof(parCrt);
             if (vind1D=-1) and (vind2D=-1) and (vind3D=-1)
             then begin
                  parser1.expression:=parCrt;
                  par[j]:=parser1.value;
                  pars[j]:=floattostr(par[j]);
                  end;
          end;
          if pos('$',pars[j])>1 then
          begin {type variable string: nom$}
             nomvar:=copy(pars[j],1,pos('$',pars[j])-1);
             if variable.indexof(nomvar) <>-1 then
             pars[j]:=param[variable.indexof(nomvar)].p4;
          end;
          if pos('@',pars[j])=1 then
          begin {type adresse variable: @nom}
             nomvar:=copy(pars[j],2,length(pars[j]));
             pars[j]:=nomvar;
             if variable.indexof(nomvar)=-1 then addvariable(pars[1],0,0,0,0,'',tobject(@rien));
          end;
          if pos('#',pars[j])>1 then
          begin {type variable tableau: nom#indice}
             nomvar:=copy(pars[j],1,pos('#',pars[j])-1);
             parser1.expression:=copy(pars[j],pos('#',pars[j])+1,length(pars[j]));
             if variable.indexof(nomvar) <>-1 then
             begin
               par[j]:=param[variable.indexof(nomvar)].p5[round(parser1.value)];
               pars[j]:=floattostr(par[j]);
             end;
          end;
          end;
      inc(j); { passage au paramètre suivant }
      end
   end;

 @g:=ordre.Objects[ordre.indexof(s2)];
 g(par,pars);
end;
end;
result:=retour;
end;


procedure Tinterpreteurform.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
actlig.free;
actligf.free;
variable.free;
varpar.free;
ordre.free;
for i:=1 to 200 do param[i].free;
end;

procedure Tinterpreteurform.Timer1Timer(Sender: TObject);
begin
{$IFDEF PILOTAGE }
if (flagwaitmotor) and (tabmot<>nil) then flagwaitmotor:=tabmot.onmov;
if (flagwaitacquis) and (suiviPRISMForm<>nil) then flagwaitacquis:=suiviPRISMForm.testacquis;
{if (flagwaitacquis) and (comptage2DForm<>nil) then flagwaitacquis:=comptage2DForm.testacquis;  }
{if (flagwaitacquis) and (comptage2DTOFForm<>nil) then flagwaitacquis:=comptage2DTOFForm.testacquis; }
if (flagwaitacquisPSD) and (ComptageMSGC<>nil) then flagwaitacquisPSD:=comptageMSGC.testacquis;
if (flagwaitacquisPSD) and (ComptagePSD<>nil) then flagwaitacquisPSD:=ComptagePSD.testacquis;
if (flagwaitacquisPSD) and (ComptageEROSform<>nil) then flagwaitacquisPSD:=ComptageEROSform.testacquis;
if (flagwaitEnergizing) then {testEnergizing};
{$ENDIF }

if (seqon>0)
and (not flagwaitchamp)
and (not flagwaitmotor)
and (not flagwaitacquis)
and (not flagwaitacquisPSD)
and (not flagwaitEnergizing)
then begin
 if (seqlig<actlig.count) and (seqlig>=0) then begin
 while ((copy(actlig.strings[seqlig],1,1)=';') or
 (copy(actlig.strings[seqlig],2,1)=';'))
  and (seqlig<actlig.count-1) do seqlig:=seqlig+1;
  interpreteurform.caption:='séq : '+actlig.strings[seqlig];
  seqlig:=traitstring(actlig.strings[seqlig],seqlig);
  VariablesListeForm.affiche;
  end else begin
  seqon:=0;timer1.enabled:=false;
  interpreteurform.caption:='pas de séquence en cours';
  scriptStatus.caption:='Paused';
 end;
end;
end;

procedure Tinterpreteurform.suividevariable1Click(Sender: TObject);
begin
if not VariablesListeForm.visible then VariablesListeForm.show
else VariablesListeForm.visible:=false;
end;

procedure Tinterpreteurform.ScriptStopButtonClick(Sender: TObject);
begin
{$IFDEF PILOTAGE }
if suiviPRISMForm<>nil then suiviPRISMForm.stop;  { arret du comptage dans PrismForm }
{ if comptage2DTOFform<>nil then comptage2DTOFform.stop; { arret du comptage dans comptage2DTOFform }
{ if comptage2Dform<>nil then comptage2Dform.stop;   { arret du comptage dans comptage2Dform }
{$ENDIF }
seqon:=0;timer1.enabled:=false;
interpreteurform.caption:='pas de séquence en cours';
scriptStatus.caption:='Paused';
end;

procedure Tinterpreteurform.ContinueButtonClick(Sender: TObject); { a tester }
begin
     seqon:=1;timer1.enabled:=true;
end;

procedure Tinterpreteurform.variables1Click(Sender: TObject);
begin
if not VariablesListeForm.visible then
begin
VariablesListeForm.affiche;VariablesListeForm.show;
end else VariablesListeForm.visible:=false;
end;

procedure Tinterpreteurform.fonctions1Click(Sender: TObject);
begin
if not functionslisteform.visible
then begin functionslisteform.affiche;functionslisteform.show; end
else functionslisteform.visible:=false;
end;

procedure Tinterpreteurform.Parser1ParserError(Sender: TObject; E: Exception);
var
mt:array[0..30] of char;
begin
timer1.enabled:=false;strpcopy(mt,E.message);
messagebox(interpreteurform.handle,'erreur',mt,mb_ok);
end;

procedure Tinterpreteurform.Edit1KeyDown(Sender: TObject; var Key: Word;Shift: TShiftState);
var toto:integer;
begin
if key=13 then begin
toto:=1;
if pos(';',edit1.text)<=0 then edit1.text:=edit1.text+';';
traitstring(edit1.text,toto);
VariablesListeForm.affiche;
end;
end;

procedure Tinterpreteurform.executeseq(name:string);
begin
mem1.activepage:=10;
mem1.Memo.Lines.LoadfromFile(name);
{$IFDEF PILOTAGE }
if suiviPRISMForm<>nil then suiviPRISMForm.stop;
{$ENDIF }
timer1.enabled:=false;
actligf.text:=mem1.memo.text;
pretraitement;
execution;
end;

end.
