Je fais ici une brève description de quelques notions et techniques très utilisées en génétique des populations. Elles concernent mon stage car les données traitées par GeneClass 2 proviennent directement de ses manipulations, et ne peuvent être vraiment comprises qu'avec un minimum de connaissances sur leur origine et leur signification.
Un marqueur génétique est un caractère mesurable à hérédité Mendélienne.
On oppose traditionnellement les marqueurs morphologiques (couleur, forme,...)
aux marqueurs moléculaires (au niveau de l'ADN) et aux marqueurs biochimiques (protéines,...).
Swynghedauw, 2000.
Les marqueurs microsatellites sont des marqueurs moléculaires souvent utilisés pour créer
les données traitées par GeneClass 2. Ils sont transmis de génération en génération,
présentent un polymorphisme élevé (taux de mutation assez fort), ne sont pas source de sélection naturelle,
et ont d'autres avantages souhaitables pour être retenus comme marqueurs.
Ce sont de courtes séquences de motifs d'ADN répétées en tandem, constituées d'unités de
répétition de longueur variant entre 1 et 6 paires de bases (pb).
Les régions flanquantes, situées de part et d'autre d'un microsatellite, permettent de le repérer.
La longueur totale d'une séquence (microsatellite et régions flanquantes) est généralement
comprise entre 10 et 200pb.
Les microsatellites les plus courants (ex: ATATATAT) sont constitués de mono [ex: (A)n]
et de dinucléotides [ex:(AT)n].
Parmi les autres types marqueurs de marqueurs utilisés, on trouvera classiquement les
isoenzymes, qui sont exprimées par des différences de charges des protéines codées
à partir de l'ADN.
La PCR ou Polymerase Chain Reaction permet de cibler un segment d'ADN particulier dans le génome,
puis de recopier ce segment des millions de fois et de le rendre analysable.
Dans le cas d'un locus microsatellite, le segment intéressant est limité par ses régions
flanquantes, qui le caractérisent. Ces régions flanquantes sont propres à une population ;
mais si elles sont inconnues, elles doivent être préalablement cherchées par des techniques
de "criblage", longues et coûteuses, qui sortent du cadre de ce rapport.
Nous allons voir ici les principales étapes d'un cycle de PCR.
Plusieurs dizaines de cycles doivent être effectués (en général entre 25 et 35).
Présentation extraite de http://www.ens-lyon.fr/RELIE/PCR/ Avant la réaction, tous les acteurs de la PCR sont introduits dans le même tube. Il s'agit de l'ADN à amplifier, des amorces pour les régions flanquantes ciblées, de l'ADN polymérase (ici la Taq polymérase) et enfin du mélange des quatre désoxyribonucléotides constitutifs de l'ADN (A,C,T,G). Tous sont ajoutés en large excès par rapport à l'ADN. | |
Dénaturation Le thermomètre indique la température qui règne dans le thermocycleur, appareil qui permet d'automatiser la PCR. A cette température, les liaisons faibles qui assuraient la cohésion de la double hélice d'ADN sont rompues pour donner deux simples brins d'ADN. | |
Hybridation L'hybridation des amorces sur l'ADN repose sur le principe de l'appariement des bases complémentaires. On voit les amorces en bleu foncé et bleu clair qui se sont fixées. | |
Élongation (extension des amorces) Les amorces hybridées à l'ADN servent de point de départ, à la polymérisation du brin d'ADN complémentaire de l'ADN matrice. La polymérisation se fait par ajout successif des désoxyribonucléotides. Chaque base ajoutée est complémentaire de la base correspondante du brin matrice. Les ADN polymérases sont des enzymes qui synthétisent l'ADN de l'extrémité 5-prime vers l'extrémité 3-prime. Les polymérases (ici le petit personnage rouge) utilisées en PCR sont extraites de bactéries vivant naturellement à des températures élevées. |
Une fois la PCR validée sur un petit nombre d'individus, le typage des individus à l'échelle des populations peut être réalisé, avec une PCR radioactive (isotope radioactif du nucléotide A).
TPGDSStructure
Le composant TPGDSStructure
est une structure efficace, assez complète pour pouvoir traiter différents types de données de
génétique des populations, comme la ploïdie variable, fournissant assez d'informations pour pouvoir renseigner les différents algorithmes d'assignation,
comme les fréquences alléliques, la longueur des allèles.
Elle est donc un peu complexe, mais son utilisation est assez simple si l'on reste rigoureux.
Elle est basée sur l'héritage et le polymorphisme objet et nous allons voir ici rapidement comment utiliser ses fonctionnalités les plus usitées.
Voir la documentation automatique DelphiDoc.
Voici déjà l'arborescence des principaux objets (cliquez pour les méthodes et propriétés) :
TObject ______________|________________ / \ TBioAbstract TVectorBioAbstract _______|___ _______________|_________________ / \ / | \ TBioCalculable TLocus TVectorLoci TVectorIndividuals TVectorGroups __|___________ / \ TGroupAbstract TIndividual ___|___ / \ TGroup TSample |
TBioAbstract
: Objet abstrait ayant un attribut nom.TBioCalculable
: Objet abstrait sur lequel reposent tous les algorithmes généralisés : synthétise les données génétiques pour un ensemble de 1 à n individus.TLocus
: Représente un locus avec ses différents allèles.TIndividual
: C'est un individu avec ses caractéristiques.TGroupAbstract
: Objet abstrait regroupant des individus dans un TVectorIndividuals
.TGroup
: Contient un ensemble TVectorGroups
de groupes et/ou de populations. (noeud dans une arborescence de TGroupAbstract
).TSample
: C'est une population. (feuille dans une arborescence de TGroupAbstract
).TVectorBioAbstract
: Tableau abstrait stockant des TBioAbstract
, avec toutes les méthodes nécessaires pour les gérer (ajout, suppression, recherche, ...).TVectorLoci
: Spécification de TVectorBioAbstract
pour stocker des TLocus
.TVectorIndividuals
: Spécification de TVectorBioAbstract
pour stocker des TIndividual
.TVectorGroups
: Spécification de TVectorBioAbstract
pour stocker des TGroupAbstract
.Description physique de
TPGDSStructure
:
| TComponent(CLX) | ________TPGDSStructure___________ allIndividuals:TVectorIndividuals allLoci:TVectorLoci allSamples:TGroup _________________________________
- Les individus
- Une
TPGDSStructure
possède une tableallIndividuals
de typeTVectorIndividuals
contenant tous les individus.- Pour accéder à cette table des individus:
aPGDSStructure.allIndividuals
- Pour connaître le nombre d'individus :
aPGDSStructure.allIndividuals.size
- Les locus et les allèles
- Elle dispose d'une table
allLoci
de typeTVectorLoci
des locus contenant eux-mêmes tous les allèles trouvés pour l'ensemble des individusTIndividual
.- Pour accéder à cette table des locus et des allèles :
aPGDSStructure.allLoci
- Pour connaître le nombre de locus :
aPGDSStructure.allLoci.size
- Les populations
- La structure possède un super-groupe
allSamples
de typeTGroup
contenant toutes les populationsTSample
.- Pour accéder à une population :
aPGDSStructure.samples[i]
- Pour connaître le nombre de populations :
aPGDSStructure.nbSamples
- Pour accéder à toutes les fonctionnalités du super-groupe :
aPGDSStructure.allSamples
Description des sous-composants :
- Les populations ou les groupes sont gérés en partie par
TGroupAbstract
- Il contient un ensemble
TVectorIndividuals
d'individus appartenant à cette population ou groupe.- Pour accéder à ce tableau d'individus :
aGroupAbstract.allIndividuals
TBioCalculable
gère tout ce sur quoi on peut faire des calculs
- C'est un des objets les plus importants. Il permet de généraliser les algorithmes travaillant à l'assignation d'individus, de populations et même de groupes de populations.
- Plusieurs de ses méthodes sont abstraites pour profiter du polymorphisme et ne sont réellement implémentées que dans ses descendants.
- Il précalcule et stocke des informations génétiques comme la proportion d'hétérozygotes, la diversité génétique (Nei's Gene Diversity), les fréquences alléliques, le nombre de gènes et d'allèles différents sur un locus, ...
- Pour accéder à la fréquence d'un allèle dont on connaît la référence sur un locus donné :
aBioCalculable.freqAlleleRef[iLocus,refAllele]
Logiques de programmation :
Deux points sont essentiels :Aussi, pour comparer les fréquences d'un alléle sur un locus entre deux individus, il faudra connaître la référence de l'allèle (identifiant unique pour toute une
- Les locus sont toujours tous présents et dans le même ordre pour tous les individus, populations et groupes d'une même
TPGDSStructure
. La gestion des données manquantes est assurée.- Il n'en est pas de même pour les allèles, qui ne sont pas tous présents, et pas forcément dans le même ordre pour les différentes entités d'une
TPGDSStructure
.TPGDSStructure
). Pour cela, il faut demander la référence de l'allèle dont on connaît le nom au niveau de la table des locus de laTPGDSStructure
:
refAllele:=aPGDSStructure.allLoci.locus[numLocus].indexOfAllele('138');
Comme on le voit, la référence de l'allèle est en fait sa position au niveau du tableau des locus général de laTPGDSStructure
.
A présent on peut accéder à la fréquence de cet allèle précis (si l'allèle n'est pas présent, sa fréquence est de 0), pour un individu, une population ou un groupe.
frequence138:=aBioCalculable.freqAlleleRef[numLocus,refAllele];
De même pour le nombre d'occurrences d'un allèle (0 si l'allèle n'est pas présent), surtout pour une population ou un groupe :
occurences138:=aBioCalculable.nbGenesRef[numLocus,refAllele];
Pour connaître le nombre d'allèles recensés dans toute laTPGDSStructure
sur un locus :
aPGDSStructure.allLoci.locus[numLocus].nbAlleles;
Pour faire un parcours exhaustif des allèles d'un individu, d'une population ou d'un groupe, on peut se passer de leurs références. Comme on le voit, le parcours des locus ne nécessite pas l'accès à la table générale des locus, vu que tous les locus sont systématiquement présents pour toutes les entités.for numLocus:=0 to aBioCalculable.nbLocus-1 do begin //pour tous les locus d'une TPGDSStructure //nombres de gènes mesurés sur ce locus de ce TBioCalculable nbGenes:=aBioCalculable.nbGenestotal[numLocus]; for numAllele:=0 to aBioCalculable.nbAlleles[numLocus]-1 do begin //pour tous les allèles d'un locus de ce TBioCalculable //accés à la fréquence d'un allèle sur ce locus freq:=aBioCalculable.freqAllele[numLocus,numAllele]; //Variante, accés au nombre d'occurences d'un allèle sur ce locus nbAlleles:=aBioCalculable.nbGenes[numLocus,numAllele]; ... end; end;L'accès aux différentes populations est aussi très utilisé. Un raccourci pour accéder aux populations a été mis en place.for numPop:=0 to aPGDSStructureRef.nbSamples-1 do begin //parcours toutes les populations d'une TPGDSStructure aSample:=aPGDSStructure.samples[numPop]; ... end;
On a parlé de raccourci car l'appel complet pour accéder à la structure qui gère toutes les populations est plus long mais offre plus de fonctionnalités. Ce type d'accès est surtout utilisé par les parseurs de fichiers en interne et ne devrait pas être souvent utilisés par les utilisateurs du composantTPGDSStructure
. En fait, uneTPGDSStructure
contient unTGroup
nomméallSamples
qui contient des populationsTSample
.//Récupération d'une population dont on connait le nom aGroupAbstract:=aPGDSStructure.allGroups.groups.groupNamed['population1']; //Si un groupe de ce nom existe if Assigned(aGroupAbstract) then aSample:=TSample(aGroupAbstract); //Cast explicite éventuel ...
//Exemple d'ajout d'une population aPGDSStructure.allGroups.groups.addGroup(aSample);
La particularité des algorithmes d'assignation est qu'ils utilisent deux structures
TMatchPGDS
, une structure de croisementTPGDSStructure
, une servant de référence, l'autre contenant les échantillons à assigner. Pour faciliter et optimiser le croisement de deuxTPGDSStructure
, une structure intermédiaire permettant une interaction simple et efficace a été créée. Voici le modèle d'utilisation le plus courant ://Création de la structure de croisement à partir de deuxTPGDSStructure
//et d'une TList contenant les noms des locus communs qui vont être utilisés. aMatchPGDS:=TMatchPGDS.create(PGDSStructureRef,PGDSStructureSamp,listeLocusUtiles); for iLocusCurrent:=0 to matchPGDS.nbLoci-1 do //parcours de tous les locus sélectionnés with aMatchPGDS.matchLoci[iLocusCurrent]^ do begin //on charge le match des locus correspondants dans les 2 dataStructures //refLocSamp contient la référence du locus courant //dans la TPGDSStructure des échantillons //refLocRef contient la référence du locus courant //dans la TPGDSStructure de référence //nbAllelesSamp contient le nombre d'allèles pour le locus courant //dans la TPGDSStructure des échantillons //nbAllelesRef contient le nombre d'allèles pour le locus courant présents seulement //dans la TPGDSStructure des échantillons for hAllele:=0 to Pred(nbAllelesSamp+nbAllelesRef) do with matchAlleles[hAllele] do //parcours de tous les Allèles connus begin //on charge le match entre les 2 dataStructures des allèles du locus en cours //refAlleleRef contient la référence de l'allèle courant dans le locus courant //au niveau de la TPGDSStructure de référence, -1 s'il n'existe pas //refAlleleSamp contient la référence de l'allèle courant dans le locus courant //au niveau de la TPGDSStructure des échantillons, -1 s'il n'existe pas end; end; aMatchPGDS.Free(); //Libération de la structure de croisement
Assignation Baudouin, exemple d'algorithme d'assignation
Voici un exemple d'algorithme généralisé, qui permet de faire l'assignation Baudouin ou Rannala pour des individus ou des populations.
On remarquera surtout l'utilisation de deux structures de donnéesdataStructRef,dataStructSamp
ainsi que de la structure de croisementmatchPGDS
.
procedure _assignationBaudouinRannala(const dataStructRef,dataStructSamp:TPGDSStructure; const matchPGDS:TMatchPGDS; const sampleSamp:TBioCalculable; const filtre:Single; const assignMethod:TAssignMethod; aResultatsPopulation:TResultats); { FORMULE GENERALE AUX DEUX METHODES: (LnGamma, log de la fonction Gamma, pour mémoire Gamma(x)=(x-1)!) M : echantillon testé N : échantillon de référence k : nombre d'allèles alpha : paramètre de la loi de Dirichelet (1 selon Rannala ; k selon Baudouin) h : allèle courant mh : nombre de gènes de l'allèle h dans l'échantillon testé nh : nombre de gènes de l'allèle h dans la référence Ln(Pr(M/N)) = LnGamma(m+1) + LnGamma(n+alpha) + Somme(h=1 à k)[LnGamma(mh+nh+alpha/k)] - Somme(h=1 à k)[LnGamma(mh+1)] - Somme(h=1 à k)[LnGamma(nh+alpha/k)] - LnGamma(m+n+alpha) on a alors la probabilité d'assignation Pr(M/N) = exp(Ln(Pr(M/N))) Dans l'implémentation, les trois sommes sont appelées respectivement S1, S2 et S3. } var iPopRef : Integer; //index de la référence courante iLocusCurrent : Integer; //index du locus courant sampleRef : TSample; //échantillon de référence courant hAllele : Integer; //allèle courant du locus courant mh,nh : Integer; //nombre de gènes pour l'allèle courant dans la référence (nh) et l'échantillon (mh) m,n : Integer; //nombre de gènes pour le locus courant dans la référence (n) et l'échantillon (m) k : Integer; //nombre total d'allèles connus pour ce Locus alpha : Extended; //paramètre de la loi de Dirichelet S1, S2, S3 : Extended; //sommes (cf + haut) LnP : Extended; //Ln de la probabilité d'assignation sommeScore : Extended; produitScore : Extended; begin aResultatsPopulation.size:=dataStructRef.allSamples.groups.size; aResultatsPopulation.nomEchantillon:=sampleSamp.treeName; sommeScore:=0; for iPopRef:=0 to aResultatsPopulation.size-1 do //parcours de toutes les Populations de référence begin sampleRef:=dataStructRef.samples[iPopRef]; LnP := 0.0; // initialisation du Ln de la proba d'assignation for iLocusCurrent := 0 to matchPGDS.nbLoci-1 do //parcours de tous les Locus sélectionnés with matchPGDS.matchLoci[iLocusCurrent]^ do begin //on charge le match des locus correspondants dans les 2 dataStructures //refLocSamp contient la référence du locus courant dans la TPGDSStructure des échantillons //refLocRef contient la référence du locus courant dans la TPGDSStructure de référence //nbAllelesSamp contient le nombre d'allèles pour le locus courant //dans la TPGDSStructure des échantillons //nbAllelesRef contient le nombre d'allèles pour le locus courant présents seulement //dans la TPGDSStructure des échantillons k := nbAllelesSamp+nbAllelesRef; //récupération du nombre total d'allèles connus case assignMethod of //calcul de alpha selon la méthode asmBaudouin: alpha := k; asmRannala: alpha := 1; else alpha := k; //initialisation par défaut end; //récupération du nombre de gènes total dans la référence (n) et l'échantillon (m) n := sampleRef.nbGenestotal[refLocRef]; m := sampleSamp.nbGenestotal[refLocSamp]; S1 := 0.0; S2 := 0.0; S3 := 0.0; //initialisation des sommes for hAllele:=0 to Pred(k) do //parcours de tous les Allèles connus begin with matchAlleles[hAllele] do begin //on charge le match entre les 2 dataStructures des allèles du locus en cours //refAlleleRef contient la référence de l'allèle courant //dans le locus courant au niveau de la TPGDSStructure de référence //refAlleleSamp contient la référence de l'allèle courant //dans le locus courant au niveau de la TPGDSStructure des échantillons //récupération du nombre de gènes de l'allèle courant //dans la référence (nh) et l'échantillon (mh) if refAlleleRef<0 then nh:=0 else nh := sampleRef.nbGenesRef[refLocRef,refAlleleRef]; if refAlleleSamp<0 then mh:=0 else mh := sampleSamp.nbGenesRef[refLocSamp,refAlleleSamp]; end; S1 := S1 + LnGamma(mh + nh + alpha/k); S2 := S2 + LnGamma(mh + 1); S3 := S3 + LnGamma(nh + alpha/k); end; //hAllele //on cumule les Ln de la probabilité d'assignation LnP := LnP + LnGamma(m + 1) + LnGamma(n + alpha) + S1 - S2 - S3 - LnGamma(m + n + alpha); end; //with dans iLocusCurrent with aResultatsPopulation.resultat[iPopRef]^ do begin //on associe la valeur de probabilité à la population courante valeur := Exp(LnP); //score obtenu pour l'assignation de l'échantillon à la Population courante intitule := sampleRef.name; //nom de la population de référence if isNan(valeur) then valeurTri := MinExtended //en cas de non-calculabilité else begin valeurTri := valeur; sommeScore:=sommeScore+valeurTri; end; end; end; //iPopRef // classement et filtrage des références assignées à l'échantillon aResultatsPopulation.prepareTrieTronque(); if sommeScore>0 then produitScore:=100.0 / sommeScore else produitScore:=100.0; for iPopRef:=0 to aResultatsPopulation.size-1 do with aResultatsPopulation.resultatTrieTronque[iPopRef]^ do valeurTri:=valeurTri*produitScore; aResultatsPopulation.TrierTronquer(filtre); end;
Utilisation du clustering avec Models@Home |
||
Les transferts de données et d'ordres dans un cluster Models@Home se font essentiellement par fichiers.
|
ciradprnlex.inc
, un morceau de fichier source Delphi.%{ %} %START INITIAL xPOPULATIONS xPOPULATION xINDIVIDUAL xINITIALCOMMENT xPOPULATIONSCOMMENT xPOPULATIONCOMMENT xINDIVIDUALCOMMENT eol (\r\n)|(\n\r)|\r|\n spaces [ \t]+ comment \* pop ^\{[^\r\n\*\{\}]{1,6} endpop ^\} nom [^\*\r\n\t\{\} ]{1,4} allele [0-9]{3} allelenul [nN][iuIU][lL] %% <INITIAL,xPOPULATIONS,xPOPULATION,xINDIVIDUAL>{spaces} begin (* ignored *) end; <INITIAL,xPOPULATIONS,xPOPULATION>{eol} begin progress(); end; <INITIAL>{comment} begin start(xINITIALCOMMENT); end; <xINITIALCOMMENT>[^\r\n]* begin (* ignored *) end; <xINITIALCOMMENT>{eol} begin progress(); start(INITIAL); end; <INITIAL>{nom} begin yylval:=yytext; if yylval='DATA' then begin start(xPOPULATIONS); return(tokDATA); end else return(tokLOCUS); end; <xPOPULATIONS>{comment} begin start(xPOPULATIONSCOMMENT); end; <xPOPULATIONSCOMMENT>[^\r\n]* begin (* ignored *) end; <xPOPULATIONSCOMMENT>{eol} begin progress(); start(xPOPULATIONS); end; <xPOPULATIONS>{pop} begin yylval:=yytext; start(xPOPULATION); return(tokSTARTPOPULATION); end; <xPOPULATION>{comment} begin start(xPOPULATIONCOMMENT); end; <xPOPULATIONCOMMENT>[^\r\n]* begin (* ignored *) end; <xPOPULATIONCOMMENT>{eol} begin progress(); start(xPOPULATION); end; <xPOPULATION>{nom} begin yylval:=yytext; start(xINDIVIDUAL); return(tokSTARTINDIVIDUAL); end; <xPOPULATION>{endpop} begin start(xPOPULATIONS); return(tokENDPOPULATION); end; <xINDIVIDUAL>{allele} begin yylval:=yytext; return(tokALLELE); end; <xINDIVIDUAL>{allelenul} begin yylval:=yytext; return(tokALLELENUL); end; <xINDIVIDUAL>{eol} begin progress(); start(xPOPULATION); return(tokENDINDIVIDUAL); end; <xINDIVIDUAL>{comment} begin start(xINDIVIDUALCOMMENT); end; <xINDIVIDUALCOMMENT>[^\r\n]* begin (* ignored *) end; <xINDIVIDUALCOMMENT>{eol} begin progress(); start(xINDIVIDUAL); end; %%
{$INCLUDE ciradprnlex.inc}
qui inclue le fichier généré par Lex dans celui généré par Yacc,
pour faire une seule unité ciradprn.pas
Delphi valide, capable d'interpréter un fichier CIRAD PRN (sur lequel on a branché un flux TStream
),
par l'appel de la méthode parseCiradPRN(...)
.%{ unit ciradprn; interface {$INCLUDE conditional.inc} uses U_TPGDSStructure, Classes; type TYaccEvent = procedure(const progression:Integer; out stop:Boolean) of Object; function parseCiradPRN(var dataStructure:TPGDSStructure; aStream:TStream; yaccEvent:TYaccEvent):Boolean; function yystart():Integer; procedure yyerror(const msg:String; state:Integer; lineno, colno:Integer); resourcestring GENOTYPE_MANQUANT = 'Génotype manquant'; TROP_DE_GENOTYPES = 'Trop de génotypes'; ALLELE_MANQUE = 'Génotype manquant'; ERREUR_LECTURE = 'Erreur "%s" à la ligne %d colonne %d en lecture de fichier CIRAD PRN'; implementation uses lexlib, yacclib, U_TLocus, U_TSample, U_TIndividual, U_lib, SysUtils; type YYSType = String; var DS : TPGDSStructure; onYaccEvent : TYaccEvent; iLoc : Integer; iAllele : Integer; popName : String; a1 , a2: String; iA : Integer; Samp : TSample; Ind : TIndividual; procedure yydebugoutput(msg : String); begin {$IFDEF yydebug} msg:=msg+EOL; yyoutput.Write(msg[1],Length(msg)); {$ENDIF} end; function yywrap():Boolean; begin Result := True; end; procedure progress(); //Déclanche un événement de progression var stop:Boolean; begin if Assigned(onYaccEvent) then begin onYaccEvent(100 * yyinput.Position div yyinput.Size,stop); if stop then begin yyabort(); yyerror(FILE_STOP,yystate,yylineno,yycolno); end; end; end; %} %token tokLOCUS tokDATA tokSTARTPOPULATION tokENDPOPULATION tokSTARTINDIVIDUAL tokENDINDIVIDUAL tokALLELE tokALLELENUL %% Input: Header tokDATA Populations { DS.fileType := fbtPRN; yyaccept(); }; Header: tokLOCUS { DS.allLoci.addLocus(TLocus.create($1)); } | Header tokLOCUS { DS.allLoci.addLocus(TLocus.create($2)); }; Populations: Population | Populations Population; Population: StartPopulation Individus tokENDPOPULATION; StartPopulation: tokSTARTPOPULATION { PopName := Trim( Copy($1, 2, Length($1)-1) ); // vire accolade Samp := TSample.create(PopName, DS.allLoci.size); DS.allSamples.groups.addGroup(Samp); }; Individus: LigneIndividu | Individus LigneIndividu; LigneIndividu: NomIndividu Typage | LigneIndividu Typage | LigneIndividu tokENDINDIVIDUAL { if iAllele=1 then yyerror(ALLELE_MANQUE, yystate, yylineno, yycolno); if iLoc < DS.allLoci.size then yyerror(GENOTYPE_MANQUANT, yystate, yylineno, yycolno) else if iLoc > DS.allLoci.size then yyerror(TROP_DE_GENOTYPES, yystate, yylineno, yycolno); }; NomIndividu: tokSTARTINDIVIDUAL { Ind := TIndividual.create($1, DS.allLoci.size, 2); DS.allIndividuals.addIndividual(Ind); Samp.allIndividuals.addIndividual(Ind); iLoc := 0; iAllele :=0; }; Typage: tokALLELE { if (iAllele=0) then begin a1 := $1; iA:=DS.allLoci.locus[iLoc].declareAlleleGlobal(a1, strToInt(a1)); Ind.addGene(iLoc, iA); Inc(iAllele); end else begin a2 := $1; iA:=DS.allLoci.locus[iLoc].declareAlleleGlobal(a2, strToInt(a2)); Ind.addGene(iLoc, iA); Inc(iLoc); // on passe au locus suivant iAllele:=0; end; } | tokALLELENUL { if (iAllele=0) then begin //a1 := $1; Inc(iAllele); end else begin //a2 := $1; Inc(iLoc); // on passe au locus suivant iAllele:=0; end; }; %% {$INCLUDE ciradprnlex.inc} //Inclusion du fichier généré par Lex function yystart():Integer; //réinitialise le parseur begin yylineno:=0; yyinput.Seek(0, soFromBeginning); start(INITIAL); Result := 0; end; procedure yyerror(const msg:String; state:Integer; lineno,colno:Integer); var vException:EFileFormatWarning; begin vException := EFileFormatWarning.CreateResFmt(Integer(@ERREUR_LECTURE),[msg,lineno,colno]); DS.parseErrors.Add(vException.Message); raise vException; end; function parseCiradPRN(var dataStructure:TPGDSStructure; aStream:TStream; yaccEvent:TYaccEvent):Boolean; {$IFNDEF yydebug} var trash : String; {$ENDIF} begin DS := dataStructure; onYaccEvent:=yaccEvent; yyclear(); yyinput := aStream; {$IFDEF yydebug} yyoutput := TFileStream.create('ciradprn.txt', fmCreate or fmShareDenyWrite); {$ELSE} yyoutput := TStringStream.create(trash); {$ENDIF} yystart(); Result := (yyparse() = 0); yyoutput.Free(); end; end.
TPGDSStructure
dans un autre logiciel de génétique développé par Jean-Marie Cornuet (Introgène).