Realisierung einer Webanwendung zur Simulation eines Kellerautomaten

Autor: Andreas Rieger
Datum: 10.01.2022

Aufgabenstellung

Erzeugen Sie mit Hilfe der Grammatik aus Aufgabe P2 einen zufälligen arithmetische Ausdruck. Es sollt auch möglich sein einen [wahrscheinlich] fehlerhaften Ausdruck zu erzeugen. Dazu löschen Sie einfach ein beliebiges Zeichen aus dem Ausdruck. Prüfen Sie den erzeugten Ausdruck mittels eines Kellerautomaten.

Visualisierung

Die Generierung der Ausdrücke mittels der Grammatik wird nicht angezeigt. Der Kellerautomaten soll als Tabelle und als Graph dargestellt werden. Die Verarbeitung der Eingabe durch den Automaten kann gleichzeitig schrittweise in der Tabelle der Überführungsfunktion und im Graphen nachvollzogen werden. Schließlich wird das Endzustand und das Ergebnis (erkannt oder nicht erkannt) des Automaten dargestellt.

Technische Dokumentation

Die Anwendung basiert auf HTML, CSS und Javascript.

Zur Visualisierung der Oberfläche wurde das Framework Bootstrap v5.1 verwendet. Bootstrap liefert eine einheitliche, gut strukturierte und responsive Benutzeroberfläche, die sich verschiedenen Endgeräten anpassen lässt. Außerdem hält das Framework viele vordefinierte und ansprechend gestaltete Komponenten zur Interaktion bereit.

Fachliche Dokumentation

Zunächst erfolgt die Eingabe des zu prüfenden arithmetischen Ausdrucks per Formular. Alternativ dazu erstellt die Anwendung im Hintergrund einen zufälligen aber korrekten Ausdruck.

Übergabe der Formulardaten an das Backend bzw. Start des Zufallsgenerators.

const response = (input.value != "") ? main(input.value) : E(false);

Erzeugung eines zufälligen korrekten Ausdrucks.

const A = () => {
                    let expression = randomZ().toString();
                    for (let i = 1; i < eL; i++) {
                        expression = (i < 2 || i == eL) ? randomCD(expression) : randomCD(B(expression));
                    }
                    return expression
                };

Anschließend wird ein beliebiges Zeichen entfernt, so dass der Ausdruck wahrscheinlich fehlerhaft ist

Entfernung eines beliebigen Zeichens

const makeInvalid = (expression) => {
                    const min = 0;
                    const max = expression.length - 1;
                    const e2R = Math.floor(Math.random() * (max - min + 1)) + min;
                    return expression.slice(0, e2R) + expression.slice(e2R + 1);
                };

Der eingegebene bzw. erstellte Ausdruck und die Prüfschritte werden anschließend als Objekt zur Ausgabe an das Frontend zurückgegeben.

Rückgabe an das Frontend

const E = (bool) => {
                        const expression = (bool) ? A() : makeInvalid(A());
                        const states = isValidExpression(expression)
                        return {
                            expression: expression,
                            states: states
                        }
                    };

Ausgabe des Ausdrucks und der Zustände

Hierfür werden die Zustände in ein neues Objekt (Array) eingelesen und anschließend zeilenweise ausgegeben.

const stateOutput = response => {

                    let counter = 0;
                    const arr = [];
        
                    // Einlesen der Zustände in neues Objekt 
                    for (const state of response["states"]) {
                        arr.push(state)
                    }
        
                    ...
        
                    if (document.getElementById("nextButton")) {
                        document.getElementById("nextButton").addEventListener("click", () => {
                            if (counter == 0) tableHeader(arr[counter])
                            if (counter < arr.length) {
                                // console.log(arr[counter])
                                nextStep(arr[counter])
                                if (counter == arr.length - 1 && arr[counter]["valid"]) {
                                    alert("Der Automat akzeptiert den Ausdruck.")
                                } else if (counter == arr.length - 1 && !arr[counter]["valid"]) {
                                    alert("Der Automat hat den Ausdruck nicht erkannt.")
                                }
                                counter += 1;
                            }
                            if (counter == arr.length) {
                                nextButton.setAttribute("disabled", "")
                            }
                        })
                    }
                };

Zeilenweise Ausgabe der Automatenzustände

const nextStep = state => {
                    const outputTable = document.getElementById("transitions");
                    const tableRow = outputTable.insertRow();
                    for (const [key, value] of Object.entries(state)) {
                        if (key != "valid") {
                            const tableCell = tableRow.insertCell();
                            tableCell.appendChild(document.createTextNode(value))
                            tableRow.appendChild(tableCell)
                        }
                    }
                    outputTable.appendChild(tableRow)
                };