Priorités de calculs

Programmation d'applications complexes
Anonyme

Priorités de calculs

Message par Anonyme »

Salut à tous, je voudrais savoir comment m'y prendre pour
calculer une chaine de caractères du type :

S$ = " ((20-10)/2 * 5 * (50-5))+3 "

Bien entendu sans les parenthèse c'est faisable :
mais avec...

Code : Tout sélectionner

Structure Operands
  Value.f
  Prioriter.l
EndStructure


Procedure MathString(*Chaine_adresse)
  Static Buffer_Pass$
  Static CounterV.l
  Static CounterP.l
  Static Ar.f,Br.f,Fr.f
  Static OldChaine$
  
  Buffer_Pass$ = PeekS(*Chaine_adresse)
  
  StartAlgo:
  
  OldChaine$ = Buffer_Pass$
 
  Buffer_Pass$ = ReplaceString(Buffer_Pass$,Chr(47),"|")
  Buffer_Pass$ = ReplaceString(Buffer_Pass$,Chr(42),"|")
  Buffer_Pass$ = ReplaceString(Buffer_Pass$,Chr(45),"|")
  Buffer_Pass$ = ReplaceString(Buffer_Pass$,Chr(43),"|")
            
  ;Debug Buffer_Pass$
  
  For i = 1 To Len(Buffer_Pass$)
    If Mid(Buffer_Pass$,i,1)="|" : CounterV+1 : EndIf
    
      Next i 
  
      Dim Op.Operands(CounterV+1) 
      
      For i = 0 To CounterV+1
        Op(i)\Value = ValF(StringField(Buffer_Pass$,i,"|"))
        Next i
      
          
          
          Dim Pr.Operands(CounterV)  
         
          For i = 1 To Len(OldChaine$)
            If Mid(OldChaine$,i,1)="/"  : Pr(CounterP)\Prioriter = 10 : CounterP+1  :  EndIf
            If Mid(OldChaine$,i,1)="*"  : Pr(CounterP)\Prioriter = 9  : CounterP+1  :  EndIf
            If Mid(OldChaine$,i,1)="-"  : Pr(CounterP)\Prioriter = 8  : CounterP+1  :  EndIf
            If Mid(OldChaine$,i,1)="+"  : Pr(CounterP)\Prioriter = 7  : CounterP+1  :  EndIf
          Next i            
          
         
          ;;Debug
          ; For v = 1 To CounterV+1
              ; Debug Op(v)\Value
              ; If Pr(v-1)\Prioriter=10 :  Debug "/" : EndIf
              ; If Pr(v-1)\Prioriter=9  :  Debug "*" : EndIf
              ; If Pr(v-1)\Prioriter=8  :  Debug "-" : EndIf
              ; If Pr(v-1)\Prioriter=7  :  Debug "+" : EndIf
            ; Next
          
          
          
          For v = 1 To CounterV
            If Pr(v-1)\Prioriter=10
              Ar = Op(v)\Value
              Br = Op(v+1)\Value
              Fr = Ar/Br
              Buffer_Pass$ = OldChaine$
              Buffer_Pass$ = ReplaceString(Buffer_Pass$,Str(Ar)+"/"+(Str(Br)),Str(Fr))
              Dim Pr.Operands(0) : Dim Op.Operands(0) : CounterV=0 : CounterP=0 : Goto StartAlgo
             EndIf
          Next  
           
          For v = 1 To CounterV
            If Pr(v-1)\Prioriter=9
              Ar = Op(v)\Value
              Br = Op(v+1)\Value
              Fr = Ar*Br
              Buffer_Pass$ = OldChaine$
              Buffer_Pass$ = ReplaceString(Buffer_Pass$,Str(Ar)+"*"+(Str(Br)),Str(Fr))
              Dim Pr.Operands(0) : Dim Op.Operands(0) : CounterV=0 : CounterP=0 : Goto StartAlgo
            EndIf
          Next  
           
          For v = 1 To CounterV
            If Pr(v-1)\Prioriter=8
              Ar = Op(v)\Value
              Br = Op(v+1)\Value
              Fr = Ar-Br
              Buffer_Pass$ = OldChaine$
              Buffer_Pass$ = ReplaceString(Buffer_Pass$,Str(Ar)+"-"+(Str(Br)),Str(Fr))
              Dim Pr.Operands(0) : Dim Op.Operands(0) : CounterV=0 : CounterP=0 : Goto StartAlgo
            EndIf
          Next  
          
          For v = 1 To CounterV
            If Pr(v-1)\Prioriter=7
              Ar = Op(v)\Value
              Br = Op(v+1)\Value
              Fr = Ar+Br
              Buffer_Pass$ = OldChaine$
              Buffer_Pass$ = ReplaceString(Buffer_Pass$,Str(Ar)+"+"+(Str(Br)),Str(Fr))
              Dim Pr.Operands(0) : Dim Op.Operands(0) : CounterV=0 : CounterP=0 : Goto StartAlgo
            EndIf
          Next  
     
  ProcedureReturn Fr
EndProcedure

Debug MathString(@"50+100/2")


Pour ceux qui on la flème de lire le code, voici comment il procède :

- on récupère la chaine$ = 50 + 100 / 2
- on remplace tout les opérateurs par | = 50 | 100 | 2
- on compte le nombre d'opérandes
- on en deduit -1 pour les opérateurs
- on colle les opérandes & opérateurs dans des tableaux
- les opérateurs perdent leurs signes (+,-,/,*) au profit de 'priorités'
- on calcule suivant les priorités
- si il reste des opérateurs on recommence la fonction.

Etc :

1°Passe = 50 + 100 / 2
2°Passe = 50 + 50
3°Passe = 100

si quelqu'un à déjà bosser la dessus...

Ca m'enuyerais de ne pas trouver un truc fiable
car ca me sert pour mon petit interpreteur :

File:1->Splus.rar
Image

un exemple est fourni avec, ainsi que le plugin screen

@++
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message par Flype »

l'interprétation d'expression arithmétique çà s'improvise pas.
çà s'apprends meme en cours d'algo et c'est toujours basé sur des algos récursifs sur plusieurs niveaux ( la fonction s'appellant elle meme ) sinon on s'en sort pas.
je vais te poster un code pour çà...

[EDIT]
pour ce que tu veux il faut chercher 'eval' sur les forums.
un des meilleurs est ce lien (cf forum anglais) :
http://www.dracsoft.com/zips/dracscript.zip
Image
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

tiens ! lance ça en mode debug
ça evalue la chaine expression.s
qui est egale a : Expression.s = "(2*2)+2*(3+4*(4+1))*2"
le resultat est mis dans la variable res : Debug res

:D

Code : Tout sélectionner

Procedure.s GetContent(String.s, Pos.l, First.b, Last.b) ;String = "dd(hallo)xyz", 3, '(', ')'
  Protected Content.s, *p.Byte, AnzKl.l
  *p = @String + Pos
  While *p\b
    If *p\b = First
      AnzKl.l + 1
    ElseIf *p\b = Last
      AnzKl - 1
      If AnzKl <= -1
        Break
      EndIf
    EndIf
    Content + Chr(*p\b)
    *p + 1
  Wend
  
  ProcedureReturn Content
EndProcedure

Procedure.s CalcBiExpression(ContL.s, Op.s, ContR.s) ; A+b oder A*b ...
  Protected result.s
  
  Select Op
    Case "*"
      result = Str(Val(ContL) * Val(ContR))
    Case "/"
      result = Str(Val(ContL) / Val(ContR))
    Case "+"
      result = Str(Val(ContL) + Val(ContR))
    Case "-"
      result = Str(Val(ContL) - Val(ContR))
  EndSelect
  
  
  ProcedureReturn result.s
EndProcedure


Procedure.s ProcessExpression(Exp.s)
  Protected *p.Byte, v.s, zw.l, ContL.s, ContR.s, Op.s, Cont.s
  *p = @Exp
  
  
  ;/ Search for ()
  While *p\b
    If *p\b = '('
      Cont = GetContent(Exp, *p-@Exp+1, '(', ')')
      v.s = ProcessExpression(Cont)
      Exp = ReplaceString(Exp, "("+Cont+")", v)
      *p  = @Exp
    ElseIf *p\b = ')'
      Debug "Fehler: Klammer nicht geöffnet!"
    EndIf
    *p + 1
  Wend
  
  
  ;/ Search for * bzw. /
  *p = @Exp
  While *p\b
    If *p\b = '*' Or *p\b = '/'
      zw = *p ;Zwischenspeichern
      Op = Chr(*p\b)
      ; Gehe zurück bis ein Operator kommt
      *p - 1
      ContL = ""
      While *p\b <> '*' And *p\b <> '/' And *p\b <> '+' And *p\b <> '-' And *p\b
        ContL = Chr(*p\b) + ContL
        *p - 1
      Wend
      
      *p = zw
      
      ; Gehe vorwärts bis Operator kommt
      *p + 1
      ContR = ""
      While *p\b <> '*' And *p\b <> '/' And *p\b <> '+' And *p\b <> '-' And *p\b
        ContR = ContR + Chr(*p\b)
        *p + 1
      Wend
      
      v = CalcBiExpression(ContL, Op, ContR)
      Exp = ReplaceString(Exp, ContL+Op+ContR, v)
      *p = @Exp
    EndIf
    *p + 1
  Wend
  
  ;/ Search for + bzw. -
  *p = @Exp
  While *p\b
    If *p\b = '+' Or *p\b = '-'
      zw = *p ;Zwischenspeichern
      Op = Chr(*p\b)
      ; Gehe zurück bis ein Operator kommt
      *p - 1
      ContL = ""
      While *p\b <> '*' And *p\b <> '/' And *p\b <> '+' And *p\b <> '-' And *p\b
        ContL = Chr(*p\b) + ContL
        *p - 1
      Wend
      
      *p = zw
      
      ; Gehe vorwärts bis Operator kommt
      *p + 1
      ContR = ""
      While *p\b <> '*' And *p\b <> '/' And *p\b <> '+' And *p\b <> '-' And *p\b
        ContR = ContR + Chr(*p\b)
        *p + 1
      Wend
      
      v = CalcBiExpression(ContL, Op, ContR)
      Exp = ReplaceString(Exp, ContL+Op+ContR, v)
      *p = @Exp
    EndIf
    *p + 1
  Wend
  
  
  ProcedureReturn Exp
EndProcedure




Expression.s = "(2*2)+2*(3+4*(4+1))*2"
Expression = RemoveString(Expression, " ") ;im Parser
res.s = ProcessExpression(Expression)
Debug "#############  RESULTAT  #############"
Debug res
Anonyme

Message par Anonyme »

Merci à vous deux !

@Dobro, j'espèrais que tu passe ici :lol:


Sinon je pense avoir trouvé une solution de mon coté.

le principe est le suivant :

- On trouve la premiere " ( "
- On stocke sa position dans PosA.l
- On continu à parcourir la chaine

- Si on trouve " ) " on note sa position dans PosB
- On extrait PosB-PosA et on calcule, Puis on remplace (A operateur B)
par le resultat extrait

- Si on tombe sur un autre " ( " alors PosA est = à la position de "("
- etc...


@++
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

Cpl.Bator a écrit :Merci à vous deux !

@Dobro, j'espèrais que tu passe ici :lol:
ya plein de code comme celui-ci sur purearea !
et sur le forum anglais ...

:D
Anonyme

Message par Anonyme »

ya plein de code comme celui-ci sur purearea !
et sur le forum anglais ...
pourtant j'ai chercher :?
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message par Flype »

eval, calc, math, expr, ...

i'm sure you can find some interesting examples :wink:
Image
Good07
Messages : 308
Inscription : ven. 23/avr./2004 18:08
Localisation : Hérault 34190 Laroque

Message par Good07 »

Bonsoir Cpl.Bator.

Il y a même une fonction eval dans jaPBe. Elle existe dans l'aide externe, mais je ne me souviens pas comment on fait pour charger le programme. Depuis que je suis passé à la version 4.0 j'ai du oublier quelque chose en route. :?
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message par Flype »

jaPBe > menu > Projet > Options du projet > Onglet 'Fichier(s) inclus' -> Cocher 'Eval'
Image
Good07
Messages : 308
Inscription : ven. 23/avr./2004 18:08
Localisation : Hérault 34190 Laroque

Message par Good07 »

Merci flype. :D

Mais il semble y avoir des problèmes avec la version 4.0 de PB. Je vais voir ce que je peux faire. (J'ai des messages d'erreur sur le fichier include Math...PBI)... :(
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message par Flype »

faut sans doute convertir le code pb3.94 en pb4.0
çà doit pas etre difficile.

ou alors tu remplace carrément le source par un nouveau code plus récent.
Image
Good07
Messages : 308
Inscription : ven. 23/avr./2004 18:08
Localisation : Hérault 34190 Laroque

Message par Good07 »

Oui je pense que tu as raison, mais je n'ai pas le temps de me pencher sur le problème pour l'instant. J'ai juste essayé suite au message de Cpl.Bator car je me souvenais de m'en être servi et j'avais trouvé le code super lorsque j'essayais moi aussi de creer une fonction Eval qui existait d'ailleurs en natif dans le basic de mon Psion 5 Mx et qui manquait sur PureBasic. :(
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message par Flype »

oui elle manque vraiment je trouve.
Image
Répondre