zusammengehörige if-else-endif erkennen

So, ich hab jetzt mal mit der Class Stack ein bischen herumgespielt und versucht, damit irgendwie eine Lösung meines IF-ELSE-ENDIF Problems zu erreichen. Leider komme ich auch hier nicht unbedingt voran... den Rechner habe ich nun schon 2mal zum Absturz gebracht. :mad:

wenn Zeile == IF dann speichere Wert von Bedingung auf dem Stack.
bei ELSEIF Wert mit dem Top Stack vergleichen, falls FALSE, Wert vom Stack entfernen, neuen Wert von Bedingung drauf.
bei ELSE Wert des Stacks negieren.
bei ENDIF Wert vom Stack entfernen.
Dazu mal folgendes:
Java:
boolean ifcheck;      //Variable, ob IF-Bedingung true oder false ist
BufferedReader buff = new BufferedReader(new FileReader(path + "myTextfile.txt"));
Stack stack = new Stack();

//jede Zeile durchgehen
while ( (line = buff.readLine()) != null) {

   if( line.startsWith("IF") || line.startsWith("if") ){
      //prüfen, ob IF-Bedingung true oder false ist (funktioniert bereits!)
      ifcheck = checkIF(line);   //checkIF(line) gibt true oder false zurück
      //bei IF - true/false auf Stack
      if(ifcheck == true){
         stack.push( "true" );
      }else{
         stack.push( "false" );
      } 

   }else if( line.startsWith("ELSE") || line.startsWith("else") ){
      //bei ELSE Stack negieren
      if( stack.peek() == "true" ){
         stack.set(stack.size(), "false");
      }else{
         stack.set(stack.size(), "true");
      }

   }else if( line.startsWith("ENDIF") || line.startsWith("endif") ){
      //Wert vom Stack löschen
      try{
         stack.pop();
      }catch(EmptyStackException e){
         JOptionPane.showMessageDialog(null, "Stack ist leer!");
      }
   }

   //Auswahl der relevanten Zeilen
   if( stack.peek() == "true" ){
      JOptionPane.showMessageDialog(null, "oberstes Stackelement ist TRUE.      Stacksize="+stack.size() );
      strBuffer.append(line + "\n");
   }else if( stack.peek() == "false" ){
      JOptionPane.showMessageDialog(null, "oberstes Stackelement ist FALSE.      Stacksize="+stack.size() );
   }
}//while close 

//zur Überprüfung: neues Textfile nur mit relevanten Zeilen erstellen
//löscht evtl. exist. Textfile, bevor es neu erstellt wird
File f = new File(path + "myTextfile_NEU.txt");
if(f.exists()){
   f.delete();
}
BufferedWriter buff2 = new BufferedWriter(new FileWriter(path + "myTextfile_NEU.txt"));
buff2.write(strBuffer.toString());
buff2.close();
Ich bekomme hier eine Fehlermeldung "java.lang.ArrayIndexOutOfBoundsException: Array index out of range" für Zeile 21 angezeigt.
Außerdem bin ich mir gar nicht so sicher, ob das überhaupt so funktioniert mit dem ganzen true und false gesetze?!
Ach ja, mein (Ausgangs)Textfile sieht übrigens so aus:
Code:
IF 1==9
textzeile1
if 8==8
textzeile2
if 3<7
textzeile3
endif
else
textzeile4
endif
textzeile5
ELSE
textzeile6
if 4<6
textzeile7
else
textzeile8
endif
textzeile9
ENDIF
Je länger ich das alles anschaue, umso mehr bekomme ich´s im Kopf vor lauter true/false etc.!
Kann mir jemand zu meinem Code vielleicht paar Ansätze sagen, wie ich was eventuell verändern muß, damit ich nur die Zeilen (in Abhängikeit von IF=true/false) in myTextfile_NEU.txt geschrieben werden, die auch tatsächlich rein gehören!

Danke.
 
Hi.

Warum speicherst du denn String Objekte in dem Stack? Speichere doch einfach die booleschen Werte. Falls du Java >= 1.5 verwendest brauchst du durch das Auto-(Un)Boxing nicht mal die Boolean Klasse bemühen.

Java:
while ()  {
  line = line.toUpperCase();

  if( line.startsWith("IF")) {
    stack.push(checkIF(line));
  } else if (line.startsWith("ELSEIF")) { // Reihenfolge ist wichtig!
    if (!(bool)stack.peek()) {
      stack.pop();
      stack.push(checkIF(line));
    }
  } else if (line.startsWith("ELSE") {
    stack.push(!(bool)stack.pop());
  } else if (line.startsWith("ENDIF") {
    stack.pop();
  } else if (stack.empty() || (bool)stack.peek()) {
    // hier Zeile ausgeben
  }
}
Die Exception wird geworfen, weil du auf ein nicht-existentes Element zugreifst. Es sind n Element im Stack, numeriert von 0 bis (n-1). Es gibt also kein n-tes Element.

Gruß
 
Zuletzt bearbeitet:
Hi.

Ich hatte nicht bedacht, das die Entscheidung, ob man die Zeilen ausgeben kann, auch von der Bedingung des letzen if (und vorletzten if usw.) abhängen.

Hier mal ein Test in JavaScript (kannst du ja einfach übersetzen):
Javascript:
function checkIF(line) {
  var exp = line.substr(3);
  return eval(exp);
}

var text = ("IF 1==9;textzeile1;if 8==8;textzeile2;if 3<7;textzeile3;endif;else;" +
		   "textzeile4;endif;textzeile5;ELSE;textzeile6;if 4<6;textzeile7;else;textzeile8;" +
		   "endif;textzeile9;ENDIF").split(';');

var stack = new Array();
stack.push(true); // vor ersten if Ausgabe angeschaltet

stack.top = function () {
	return this[this.length-1];
}

for (var i = 0; i < text.length; ++i) {
  var line = text[i];

  if(/^IF/i.test(line)) {
    stack.push(stack.top() && checkIF(line));
  } else if (/^ELSEIF/i.test(line)) { // Reihenfolge ist wichtig!
    if (!stack.top()) {
      stack.pop();
      stack.push(stack.top() && checkIF(line));
    }
  } else if (/^ELSE/i.test(line)) {
    var b = stack.pop();
    stack.push(stack.top() && !b);
  } else if (/^ENDIF/i.test(line)) {
    stack.pop();
  } else if (stack.top()) {
    // Im if/else Zweig dessen Bedingung "TRUE" ist...
	document.writeln(line);
  }
}
Wenn du das im Browser ausführst, erhälst du als Ergebnis:
Code:
textzeile6
textzeile7
textzeile9
Gruß
 
Ich habe mal eine Frage dazu:

Bestehen die Abfragen bei den IFs immer nur aus a==b oder sollen da irgendwann noch andere Operatoren hinzukommen (> < !=) ?

Falls ja, gibt es bessere Wege dies zu lösen. (Compilerbau, Rekursiver Abstieg...)

KAi
 
Hi.

Ich hatte nicht bedacht, das die Entscheidung, ob man die Zeilen ausgeben kann, auch von der Bedingung des letzen if (und vorletzten if usw.) abhängen.

Hier mal ein Test in JavaScript (kannst du ja einfach übersetzen):
Javascript:
function checkIF(line) {
  var exp = line.substr(3);
  return eval(exp);
}

var text = ("IF 1==9;textzeile1;if 8==8;textzeile2;if 3<7;textzeile3;endif;else;" +
		   "textzeile4;endif;textzeile5;ELSE;textzeile6;if 4<6;textzeile7;else;textzeile8;" +
		   "endif;textzeile9;ENDIF").split(';');

var stack = new Array();
stack.push(true); // vor ersten if Ausgabe angeschaltet

stack.top = function () {
	return this[this.length-1];
}

for (var i = 0; i < text.length; ++i) {
  var line = text[i];

  if(/^IF/i.test(line)) {
    stack.push(stack.top() && checkIF(line));
  } else if (/^ELSEIF/i.test(line)) { // Reihenfolge ist wichtig!
    if (!stack.top()) {
      stack.pop();
      stack.push(stack.top() && checkIF(line));
    }
  } else if (/^ELSE/i.test(line)) {
    var b = stack.pop();
    stack.push(stack.top() && !b);
  } else if (/^ENDIF/i.test(line)) {
    stack.pop();
  } else if (stack.top()) {
    // Im if/else Zweig dessen Bedingung "TRUE" ist...
	document.writeln(line);
  }
}
Wenn du das im Browser ausführst, erhälst du als Ergebnis:
Code:
textzeile6
textzeile7
textzeile9
Gruß

Was macht 'stack.top()' - liefert mir das die Länge vom Stackspeicher?
 
Was macht 'stack.top()' - liefert mir das die Länge vom Stackspeicher?
Was diese Funktion macht, steht doch da... Die Funktion ist doch dort implementiert. Die Länge würde das Attribut length liefern.

Die Funktion top() liefert den obersten Wert vom Stack - also bei der Java Stack Klasse das gleiche wie die Methode peek().

Gruß
 
Zuletzt bearbeitet:
Die Funktion top() liefert den obersten Wert vom Stack - also bei der Java Stack Klasse das gleiche wie die Methode peek().
Ok, das habe ich mir dann auch so gedacht...
Das Stück Code:
Javascript:
if(/^IF/i.test(line)) {
   stack.push(stack.top() && checkIF(line));
}
... trägt im Falle von 'IF gefunden' in den Stack ein "true" bzw. "false" ein (was von der Funktion checkIF zurückgegeben wird) - richtig?!
Was ich aber dann nicht ganz verstehe:
Wenn stack.top() analog stack.peek() ist, wieso wird dann das oberste Element vom Stack gelesen (aber nicht wie durch pop() entfernt) und ein true/false angehängt?
Wieso nicht einfach 'stack.push(checkIF(line))' oder 'stack.push("true")' bzw. 'stack.push("false")'?

Gruß
 
Wieso nicht einfach 'stack.push(checkIF(line))' oder 'stack.push("true")' bzw. 'stack.push("false")'?
Weil's dann nicht funktioniert. ;)

Bsp:
Code:
IF 5 = 10
IF 5 = 5
PRINT 5
ENDIF
ELSE
PRINT 9
ENDIF
Wenn dieser Code verarbeitet wird, muss man beim zweiten IF prüfen, ob das vorherige IF überhaupt true war. Wenn man beim zweiten IF ankommt, befinden sich auf dem Stack die Werte (true, false). Die Bedingung beim zweiten IF ist also völlig unrelevant (und wird auch gar nicht getestet), da dieser Zweig des ersten IF gar nicht ausgeführt wird.

Genau das gleiche Problem gibt es bei der ELSEIF bzw. ELSE Verzweigung. Es ist wichtig ob das übergeordnete IF überhaupt wahr ist oder nicht.

Gruß
 

Neue Beiträge

Zurück