Aus Das deutschsprachige Scratch-Wiki

Dieses Tutorial lehrt wie man einen Ausdruck auswertet.

Den benutzerdefinierten Block erstellen

Diese Implementierung enthält nur instabile Unterstützung für Funktionen und gar keine unäre Negation. Deswegen muss man -5 * 10 zu (0-5) * 10 ändern.

Variablen

Man braucht folgende Variablen:

  • (i)
  • (letzter token)
  • (token)
  • (zeichen)
  • (ergebnis)

Man braucht auf folgende Listen:

  • (warteschlange::list)
  • (stapel::list)
  • (tokens::list)

Und mache eine Liste "Operatoren" mit genau diesen Zeichen in genau dieser Reinfolge:

  1. -
  2. +
  3. /
  4. *

Dies ist wichtig, wegen Punkt vor Strich.

Kompletter Benutzerdefinierter Block

Definiere Werte (Ausdruck :: custom-arg) aus
setze [i v] auf (1) //  Tokenisierung des Ausdrucks
lösche alles aus [tokens v]
wiederhole (Länge von (Ausdruck :: custom-arg)) mal 
  setze [zeichen v] auf (Zeichen (i) von (Ausdruck :: custom-arg))
  setze [letzter token v] auf (Element (Länge von [tokens v]) von [tokens v])
  falls <(123456.7890) enthält (zeichen) ?> , dann 
    falls <<((letzter token) / (1)) = (last token)> oder <(last token) = [.]>> , dann 
      ersetze Element (Länge von [tokens v]) von [tokens v] durch (verbinde (letzter token) und (zeichen))
    sonst 
      füge (zeichen) zu [tokens v] hinzu
    end
  sonst 
    falls <[()+-/*√] enthält (zeichen) ?> , dann 
      füge (zeichen) zu [tokens v] hinzu
    end
  end
  ändere [i v] um [1]
end
lösche alles aus [stapel v] //  Sortierung der Operationen (Punkt vor Strich, Klammer usw.) und wechselung von Infix zu Postfix
lösche alles aus [warteschlange v]
setze [i v] auf (1)
wiederhole (Länge von [tokens v]) mal 
  setze [token v] auf (Element (i) von [tokens v])
  falls <((token) / (1)) = (token)> , dann 
    füge (token) zu [warteschlange v] hinzu
  end
  falls <[operatoren v] enthält (token) ?> , dann 
    wiederhole bis <<<(Element (1) von [stapel v]) = [(]> oder <(Länge von [stapel v]) = [0]>> oder <(Nummer von (Element (1) von [stapel v]) in [operatoren v]) < (Nummer von (token) in [operatoren v])>> 
      füge (Element (1) von [stapel v]) zu [warteschlange v] hinzu
      lösche (1) aus [stapel v]
    end
    füge (token) bei (1) in [stapel v] ein
  end
  falls <(token) = [(]> , dann 
    füge (token) bei (1) in [stapel v] ein
  end
  falls <(token) = [)]> , dann 
    wiederhole bis <<(Element (1) von [stapel v]) = [(]> oder <(Länge von [stapel v]) = [0]>> 
      füge (Element (1) von [stapel v]) zu [warteschlange v] hinzu
      lösche (1) aus [stapel v]
    end
    falls <(Element (1) von [stapel v]) = [(]> , dann 
      lösche (1) aus [stapel v]
    end
  end
  ändere [i v] um (1)
end
wiederhole bis <(Länge von [stapel v]) = (0)> 
  füge (Element (1) von [stapel v]) zu [warteschlange v] hinzu
  lösche (1) aus [stapel v]
end
wiederhole bis <(Länge von [warte schlange v]) = [0]> 
  setze [token v] auf (Element (1) von [warteschlange v])
  lösche [1] aus [warteschlange v]
  falls <[operatoren v] enthält (token) ?> , dann 
    falls <(token) = [+]> , dann 
      füge ((Element [2] von [stapel v]) + (Element [1] von [stapel v])) bei [1] in [stapel v] ein
    end
    falls <(token) = [-]> , dann 
      füge ((Element [2] von [stapel v]) - (Element [1] von [stapel v])) bei [1] in [stapel v] ein
    end
    falls <(token) = [/]> , dann 
      füge ((Element [2] von [stapel v]) / (Element [1] von [stapel v])) bei [1] in [stapel v] ein
    end
    falls <(token) = [*]> , dann 
      füge ((Element [2] von [stapel v]) * (Element [1] von [stapel v])) bei [1] in [stapel v] ein
    end
    falls <(token) = [√]> , dann // Unärer Operator
      füge ([Wurzel v] von (Element [1] von [stapel v])) bei [1] in [stapel v] ein
      füge () bei [2] in [stapel v] ein //Füge ein Dummy ein, damit die andere Nummer nicht gelöscht wird, der Token darf nur ein Charakter lang sein. Dieser Weg Funktionen und Unäre Negation einzubauen ist instabil, es wird vorgeschlagen, einen besseren parser zu benutzen.
    end
    lösche [2] aus [stapel v]
    lösche [2] aus [stapel v]
  sonst 
    füge (token) bei (1) in [stapel v] ein
  end
end //  Löse die Schlange auf
setze [ergebnis v] auf (Element [1] von [stapel v]) //  Das Ergebnis ist in der Variable "ergebnis"

Erklärung

Das Problem der Auswertung eines Ausdrucks kann in 3 Schritte unterteilt werden:

  1. Tokenisierung des Ausdrucks (Umwandlung der Eingabe in eine Liste von Symbolen und Zahlen)
  2. Umwandlung der Token in das Postfix-Format (wobei der Operator hinter den 2 Operanden steht)
  3. Auswertung des Postfix-Ausdrucks mit einer Stapelmaschine (Berechnung der Antwort)


Tokenisierung des Ausdrucks

Der Ausdruck muss zunächst in eine Liste umgewandelt werden. Jede Zahl muss alle ihre Ziffern in demselben Listenelement haben.

Dieses Skript tokenisiert einen Ausdruck.

setze [i v] auf (1)
lösche alles aus [tokens v]
wiederhole (Länge von (Ausdruck :: custom-arg)) mal 
  setze [zeichen v] auf (Zeichen (i) von (Ausdruck :: custom-arg))
  setze [letzter token v] auf (Element (Länge von [tokens v]) von [tokens v])
  falls <(123456.7890) enthält (zeichen) ?> , dann 
    falls <<((letzter token) / (1)) = (last token)> oder <(last token) = [.]>> , dann 
      ersetze Element (Länge von [tokens v]) von [tokens v] durch (verbinde (letzter token) und (letter))
    sonst 
      füge (zeichen) zu [tokens v] hinzu
    end
  sonst 
    falls <[()+-/*] enthält (zeichen) ?> , dann 
      füge (zeichen) zu [tokens v] hinzu
    end
  end
  ändere [i v] um [1]
end


Umwandlung der Token in das Postfix-Format

Zunächst wird der Shunting yard Algorithmus verwendet, um die Token von Infix (A op B) in Postfix (A B op) umzuwandeln. Dies geschieht, weil die Berechnung eines Postfix-Ausdrucks viel weniger Code erfordert als die eines Infix-Ausdrucks.

Dieses Skript lässt den Shunting yard Algorithmus auf der Tokenliste laufen:


Information icon.png Information:


lösche alles aus [stapel v]
lösche alles aus [warteschlange v]
setze [i v] auf (1)
wiederhole (Länge von [tokens v]) mal 
  setze [token v] auf (Element (i) von [tokens v])
  falls <((token) / (1)) = (token)> , dann 
    füge (token) zu [warteschlange v] hinzu
  end
  falls <[operatoren v] enthält (token) ?> , dann 
    wiederhole bis <<<(Element (1) von [stapel v]) = [(]> oder <(Länge von [stapel v]) = [0]>> oder <(Nummer von (Element (1) von [stapel v]) in [operatoren v]) < (Nummer von (token) in [operatoren v])>> 
      füge (Element (1) von [stapel v]) zu [warteschlange v] hinzu
      lösche (1) aus [stapel v]
    end
    füge (token) bei (1) in [stapel v] ein
  end
  falls <(token) = [(]> , dann 
    füge (token) bei (1) in [stapel v] ein
  end
  falls <(token) = [)]> , dann 
    wiederhole bis <<(Element (1) von [stapel v]) = [(]> oder <(Länge von [stapel v]) = [0]>> 
      füge (Element (1) von [stapel v]) zu [warteschlange v] hinzu
      lösche (1) aus [stapel v]
    end
    falls <(Element (1) von [stapel v]) = [(]> , dann 
      lösche (1) aus [stapel v]
    end
  end
  ändere [i v] um (1)
end
wiederhole bis <(Länge von [stapel v]) = (0)> 
  füge (Element (1) von [stapel v]) zu [warteschlange v] hinzu
  lösche (1) aus [stapel v]
end


Berechnen des Ergebnisses mit einer Stapelmaschine

Dieses Skript berechnet das Ergebnis des Postfix-Ausdrucks:

wiederhole bis <(Länge von [warte schlange v]) = [0]> 
  setze [token v] auf (Element (1) von [warteschlange v])
  lösche [1] aus [warteschlange v]
  falls <[operatoren v] enthält (token) ?> , dann 
    falls <(token) = [+]> , dann 
      füge ((Element [2] von [stapel v]) + (Element [1] von [stapel v])) bei [1] in [stapel v] ein
    end
    falls <(token) = [-]> , dann 
      füge ((Element [2] von [stapel v]) - (Element [1] von [stapel v])) bei [1] in [stapel v] ein
    end
    falls <(token) = [/]> , dann 
      füge ((Element [2] von [stapel v]) / (Element [1] von [stapel v])) bei [1] in [stapel v] ein
    end
    falls <(token) = [*]> , dann 
      füge ((Element [2] von [stapel v]) * (Element [1] von [stapel v])) bei [1] in [stapel v] ein
    end
    falls <(token) = [*]> , dann 
      füge (([Wurzel v] von (Element [1] von [stapel v])) ) bei [1] in [stapel v] ein
    end

    lösche [2] aus [stapel v]
    lösche [2] aus [stapel v]
  sonst 
    füge (token) bei (1) in [stapel v] ein
  end
end //  Löse die Schlange auf
setze [ergebnis v] auf (Element [1] von [stapel v])

Wie man den Block benutzt

Wenn die grüne Flagge angeklickt
werte [5 + 5] aus :: custom
sage (ergebnis)

Wenn es funktioniert hat, sollte die Figur die Nummer 10 anzeigen.

Demo


Das Projekt auf Scratch



Code zum Einbinden ins Forum:
[wiki=de:Mathematische Ausdrücke auswerten]Mathematische Ausdrücke auswerten[/wiki]
Cookies helfen uns bei der Bereitstellung von Das deutschsprachige Scratch-Wiki. Durch die Nutzung von Das deutschsprachige Scratch-Wiki erklärst du dich damit einverstanden, dass wir Cookies speichern.