Assemblercodes für das neue X4

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • Die "Spielereien" mit Arrays wären nicht komplett, wenn wir nicht sortieren könnten.


      Aufruf jeweils wieder mit 2 Parametern, der Erste die Anfangsadresse und der Zweite die Anzahl der Elemente. Kurze Beschreibung:
      Zeiger 1 zeigt auf das erste Element, Zeiger 2 zeigt auf das vorletzte Element. Verglichen werden immer das Element, auf das gezeigt wird und sein Nachfolger. Dann wird Zeiger 1 erhöht und Zeiger 2 erniedrigt bis alle Elemente durch sind. Nächster Durchlauf beginnt mit dem zweiten und dem vorvorletzten Element. Abgebrochen wird, wenn am Schleifenbeginn der Zeiger 2 kleiner als Zeiger 1 wird oder innerhalb eines Schleifendurchlaufs kein Element vertauscht werden mußte. Hat sowas auch einen Namen? ;-)

      Gruß Volkmar

      Edit: Auch die Korrektur zeigte noch Fehler, ich habe das Ganze erst mal raus genommen. Irgendwo ist da noch der Wurm drin

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Volkmar () aus folgendem Grund: Code fehlerhaft

    • Sowas nennt sich Bubblesort, denke ich. Das sind sicher keine "Spielereien", das sind sehr wichtige Beiträge von dir, Volkmar!

      Ich dagegen wollte x87-FPU-Code in den XASM einschleusen (- bin sicher, daß RGH das in einer kommenden XProfan-Version eingeplant hat, aber bis dahin dachte ich an eine Behelfslösung). Allein, ich bin bisher kläglich gescheitert, nicht am Code selbst, aber "von aussen" eingebracht sind Adressangaben zum laden und speichern der Register scheinbar nicht korrekt ermittelbar, schon gar nicht aus Labels.

      Ein Experimental-Sourcecode mit allen FPU-OpCodesequenzen (ohne Bytes zu Speicheradressierung) ist hier von meiner homepage zu laden, da wieder einmal die 10k-Grenze des Boards stark überschritten ist.

      Hat jemand eine Idee?
      Gruss

      P.S.: Natürlich müssen die Befehle noch (ev. nach Häufigkeit der Verwendung aufsteigend, und anschließend dominant ...) nach Länge absteigend sortiert werden, um korrektes parsing zu ermöglichen.

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von p. specht ()

    • Danke :-)
      Nichtdestotrotz, das Sortieren war bisher nur Spielerei, der Code war nicht stabil. Habe nun die Abbruchbedingung in den obigen Codes verändert, jetzt sollte es wirklich immer klappen.

      Gruß Volkmar

      Edit: Da ist noch immer der Wurm drin, ich habe die Codes erst mal raus genommen.
      Die überarbeitete Fassung gibts in #66

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Volkmar ()

    • Ja, die Fließkomma-Geschichte kommt. Bei mir ist es schon seit letztem Wochenende eingebaut und es funktionier derartiges schon:


      Quellcode

      1. ASM "DivTest", 2
      2. JMP Start
      3. Ergebnis:
      4. DD 0
      5. Start:
      6. FINIT
      7. FLD Par1 // oben auf den Stack
      8. FLD Par2 // oben auf den Stack
      9. FDIV // Stack1 / Stack0 - beide Werte vom Stack nehmen und Ergebnis auf den Stack
      10. FSTP [Ergebnis] // Ergebnis speichen und vom Stack nehmen
      11. MOV EAX,[Ergebnis]
      12. ENDASM
      13. Set("Decimals",6)
      14. Var single A = 2.25
      15. Var single B = 3
      16. Var single C = DivTest(A, B)
      17. Print C
      18. WaitInput
      19. End
      Alles anzeigen
      Wer einen HP-Rechner mit UPN nutze oder FORTH kennt, wird sich in der Stackgeschichte der FPU-Einheit des Prozesors zu Hause fühlen. ;-) Die 8 Register der FPU (ST0 bis ST7) fungieren nämlich als Stack.

      Aber dazu am Wochenende mehr. Und damit ist der Funktionsumfang von X4 weitgehend abgeschlossen.

      Gruß
      Roland
      Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD / ATI Radeon HD4770 512 MB / Windows 7(32) - XProfan X3
      AMD Athlon II X2 2,9 GHz / 3 GB RAM / 500 GB HDD / ATI Radeon 3000 (onboard) / Windows 10(64) - XProfan X3


      http://www.xprofan.de

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von RGH ()

    • Jetzt nach einer Umorganisation der Abbruchbedingungen klappt es mit dem Sortieren ohne Fehler. Hinzugekommen ist noch der Rückgabewert -1, wenn versucht wird, ein Array mit weniger als 2 Elementen zu sortieren.

      Steigende Sortierung:

      Quellcode

      1. ASM "ArraySSort", 2
      2. // Array in steigender Richtung sortieren
      3. PUSH EBX
      4. PUSH ECX
      5. PUSH EDX
      6. PUSH EDI
      7. PUSH ESI
      8. MOV EDX, Par1 // Arrayadresse
      9. MOV EBX, Par2 // Arraygröße
      10. MOV EAX, -1
      11. CMP EBX, 2
      12. JNL @@OK
      13. JMP @@Fehler
      14. @@OK:
      15. MOV ECX, EDX // Anfang nach ECX
      16. SUB EBX, 2
      17. SHL EBX, 2 // Größe *4
      18. // Berechnet wird die Distanz vom ersten
      19. // zum vorletzten Element und diese dann
      20. // zur Anfangsadresse addiert
      21. ADD EDX, EBX // Endadresse berechnet
      22. MOV [@@Start], ECX
      23. MOV [@@Ende], EDX
      24. MOV EDI, ECX
      25. SUB EDI, 4
      26. JMP @@ASchleife
      27. @@Start:
      28. DD 0
      29. @@Ende:
      30. DD 0
      31. @@ASchleife:
      32. XOR ESI, ESI // Flag löschen
      33. CMP EDX, EDI // Zeiger 2 kleiner als Hilfszeiger
      34. JL @@fertig // JA -> raus
      35. @@ISchleife:
      36. MOV EAX, [ECX]
      37. MOV EBX, [ECX + 4]
      38. CMP EAX, EBX
      39. JL @@NoCh1
      40. // Vertauschen Wertpaar von Zeiger 1
      41. MOV [ECX], EBX
      42. MOV [ECX + 4], EAX
      43. INC ESI // Flag setzen
      44. @@NoCh1:
      45. ADD ECX, 4
      46. MOV EAX, [EDX]
      47. MOV EBX, [EDX + 4]
      48. CMP EAX, EBX
      49. JL @@NoCh2
      50. // Vertauschen Wertpaar von Zeiger 2
      51. MOV [EDX], EBX
      52. MOV [EDX + 4], EAX
      53. INC ESI // Flag setzen
      54. @@NoCh2:
      55. SUB EDX, 4
      56. CMP EDX, EDI
      57. JG @@ISchleife // noch nicht alle Werte durch
      58. // komplette Schleife durch
      59. OR ESI, ESI
      60. JZ @@Fertig // Flag nicht gesetzt -> Fertig
      61. // Nächste Schleifenwerte berechnen
      62. MOV ECX, [@@Start]
      63. MOV EDI, ECX
      64. ADD ECX, 4
      65. MOV [@@Start], ECX
      66. MOV EDX, [@@Ende]
      67. SUB EDX, 4
      68. MOV [@@Ende], EDX
      69. JMP @@ASchleife
      70. @@Fertig:
      71. XOR EAX, EAX // Rückgabewert 0, wenn sortiert wurde
      72. @@Fehler:
      73. POP ESI
      74. POP EDI
      75. POP EDX
      76. POP ECX
      77. POP EBX
      78. EndASM
      Alles anzeigen

      Fallende Sortierung:

      Quellcode

      1. ASM "ArrayFSort", 2
      2. // Array in steigender Richtung sortieren
      3. PUSH EBX
      4. PUSH ECX
      5. PUSH EDX
      6. PUSH EDI
      7. PUSH ESI
      8. MOV EDX, Par1 // Arrayadresse
      9. MOV EBX, Par2 // Arraygröße
      10. MOV EAX, -1
      11. CMP EBX, 2
      12. JNL @@OK
      13. JMP @@Fehler
      14. @@OK:
      15. MOV ECX, EDX // Anfang nach ECX
      16. SUB EBX, 2
      17. SHL EBX, 2 // Größe *4
      18. // Berechnet wird die Distanz vom ersten
      19. // zum vorletzten Element und diese dann
      20. // zur Anfangsadresse addiert
      21. ADD EDX, EBX // Endadresse berechnet
      22. MOV [@@Start], ECX
      23. MOV [@@Ende], EDX
      24. MOV EDI, ECX
      25. SUB EDI, 4
      26. JMP @@ASchleife
      27. @@Start:
      28. DD 0
      29. @@Ende:
      30. DD 0
      31. @@ASchleife:
      32. XOR ESI, ESI // Flag löschen
      33. CMP EDX, EDI // Zeiger 2 kleiner als Hilfszeiger
      34. JL @@fertig // JA -> raus
      35. @@ISchleife:
      36. MOV EAX, [ECX]
      37. MOV EBX, [ECX + 4]
      38. CMP EAX, EBX
      39. JG @@NoCh1
      40. // Vertauschen Wertpaar von Zeiger 1
      41. MOV [ECX], EBX
      42. MOV [ECX + 4], EAX
      43. INC ESI // Flag setzen
      44. @@NoCh1:
      45. ADD ECX, 4
      46. MOV EAX, [EDX]
      47. MOV EBX, [EDX + 4]
      48. CMP EAX, EBX
      49. JG @@NoCh2
      50. // Vertauschen Wertpaar von Zeiger 2
      51. MOV [EDX], EBX
      52. MOV [EDX + 4], EAX
      53. INC ESI // Flag setzen
      54. @@NoCh2:
      55. SUB EDX, 4
      56. CMP EDX, EDI
      57. JG @@ISchleife // noch nicht alle Werte durch
      58. // komplette Schleife durch
      59. OR ESI, ESI
      60. JZ @@Fertig // Flag nicht gesetzt -> Fertig
      61. // Nächste Schleifenwerte berechnen
      62. MOV ECX, [@@Start]
      63. MOV EDI, ECX
      64. ADD ECX, 4
      65. MOV [@@Start], ECX
      66. MOV EDX, [@@Ende]
      67. SUB EDX, 4
      68. MOV [@@Ende], EDX
      69. JMP @@ASchleife
      70. @@Fertig:
      71. XOR EAX, EAX // Rückgabewert 0 wenn sortiert wurde
      72. @@Fehler:
      73. POP ESI
      74. POP EDI
      75. POP EDX
      76. POP ECX
      77. POP EBX
      78. EndASM
      Alles anzeigen


      Gruß Volkmar
    • Da hat Roland ja noch unbewußt ein Feature eingebaut.
      Ich verwalte ja gerne meine Werke, oder die
      aus dem Forum hier, in .inc Dateien.

      Besonders die ASM-Codes hier habe ich in einer eigenen
      Include gesammelt.

      In der .inc habe ich noch
      Set("ASMMODE", 1)
      stehen gehabt. Da hatte ich mal den
      RUN-Knopf bzw. Ausführen Interpreter gedrückt.
      Da hat er auch sämtliche .lst Dateien geschrieben.

      Für mich ist das ein Feature, wenn ich zur Include
      auch gleich sämtliche .lst Dateien habe. :top:
    • Ich weiss ja nicht, warum meine eigenen Versuche alle fehlschlugen, aber seit RGH die 64-bit FPU-Lade- und Speicherbefehle implementiert hat, klappt das direkte Beladen von XProfans normalen Double Precision-Float-Zielvariablen ohne Probleme:

      Quellcode

      1. cls
      2. set("ASMMODE",0)
      3. ASM "TST4",2
      4. mov eax,par1 // In EAX ist die Adresse, an der der Double-Parameter steht
      5. mov ebx,par2 // In EBX ist die Adresse, an die das Ergebnis befördert werden soll
      6. FLD64 [eax] // Die 64Bit, die dort stehen, landen auf dem FPU-Stack ...
      7. FLD1 // Lade Wert 1 in neues ST0
      8. FADD // Addiere ST1 zu ST0, Wert nun in ST0
      9. FSTP64 [ebx] // *** und lade die Zielvariable direkt! ***
      10. mov eax,0 // Fehlercode könnte hier übergeben werden!
      11. ENDASM
      12. Set("DECIMALS",17) // (15 davon sind i.d.R. genau)
      13. declare P!,Q! // Q! MUSS declared sein, sonst kracht es!!!
      14. var P!=Pi()
      15. print "\n Übergabevariable P! ist derzeit ";P!
      16. print " Zielvariable Q! ist noch ";Q!
      17. print " Fehlermeldung (0=OK): ";Tst4(addr(P!),addr(Q!))
      18. print "\n ASM ausgeführt: Q! ist nun: ";q!
      19. print " Q! sollte nun Pi+1 sein. Differenz: ";Q! - (P!+1)
      20. print "\n Bei Differenz 0 hat das geklappt!"
      21. waitinput
      22. end
      Alles anzeigen


      P.S.: Ein Riesen-Danke!

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von p. specht ()

    • Hängt wahrscheinlich auch mit XProfans automatischer
      Typumwandlung zusammen :
      In der XProfan - Hilfe :

      Spoiler anzeigen

      Ab XProfan X2 können Fließkommawerte auch direkt an externe Funkltioonen übergeben werden, so lange diese nicht mit DEF definiert wurden, da sie dann automatisch vor der Übergabe in 32-Bit umgewandelt werden. Für mit DEF definierte externe Funktionen ist die Umwandlung mittels Single weiterhin notwendig.
    • GetQuota(Text#, TextLänge%, Addr(Trenn$), ZitatNummer%, AusgabePuffer#, AusgabePufferLänge%)


      Text# wird nach Teilstrings untersucht, die in Zeichen entsprechend Trenn$ eingeschlossen sind. Trenn$ besteht immer aus 2 Zeichen, einem Zitatbeginn und einem Zitatende. Beide Zeichen können gleich sein, wenn zum Beispiel nach Textteilen in Anführungszeichen gesucht wird oder verschieden bei typografischen Anführungszeichen (Code 132, 147). Ist Textlänge% = 0, dann muß Text# einen nullterminierten String enthalten.
      Das Ganze erinnert zwar an SubStr$, ist aber doch etwas anders.
      Dieser "Text" wird nun "untersucht".
      Text ist das erste Zitat und untersucht das zweite Zitat.
      Das Zitat mit der gewünschten Nummer wird in AusgabePuffer# zurück gegeben. Der Rückgabewert ist dann die Anzahl Zeichen.
      Die ZitatNummer -1 beim Aufruf bewirkt, daß nur die Anzahl der im Text erkannten Zitate zurück gegeben wird.
      Wird AusgabePuffer# als 0 angegeben, wird die AusgabePufferLänge% ignoriert und es wird nur die Anzahl Zeichen des gewünschten Zitates oder ein Fehler zurückgegeben. Wird diese Zitatlänge benutzt, um den notwendigen AusgabePuffer# zu DIMmen, dann muß für das abschließende Nullbyte ein Byte mehr berücksichtigt werden, als DIM AusgabePuffer#, Rückgabe% + 1
      Mögliche Fehlerwerte:
      0 Gewünschtes Zitat nicht gefunden
      -1 Zweites Trennzeichen nicht gefunden (Zitat hat kein Ende, wurde deshalb nicht ermittelt)
      -2 AusgabePuffer zu klein
      -3 ZitatNummer% 0 oder kleiner -1 nicht erlaubt, (ZitatNummer% -1 ist erlaubt und hat eine besondere Bedeutung)


      Da die Trennzeichen variabel sind, könnte auch nach Klammern gesucht werden. Sind allerdings Klammern verschachtelt, funktioniert das nicht: 'Dieser (Text (wird)) untersucht' findet dann 'Text (wird' Für die Auflösung von Klammern sollte deshalb immer die Funktion Brackets() im nächsten Beitrag verwendet werden.

      Quellcode

      1. ASM "GetQuota", 6
      2. PUSH EBX
      3. PUSH ECX
      4. PUSH EDX
      5. PUSH ESI
      6. PUSH EDI
      7. MOV ESI, Par1 // Adresse Quellstring
      8. MOV ECX, Par2 // Länge Quellstring
      9. MOV EBX, Par3 // Adresse Trennzeichenstring (immer 2 Zeichen lang)
      10. MOV EDX, Par4 // Nummer des gesuchten Teilstrings
      11. MOV EDI, Par5 // Ergebnispuffer
      12. PUSH EDI
      13. MOV EDI, Par6 // Länge Ergebnispuffer
      14. PUSH EDI
      15. OR ECX, ECX // Quelllänge 0?
      16. JNZ IsLen // Nein, Länge ist angegeben in ECX
      17. DEC ECX // sonst auf -1 setzen damit maximale Länge bis 0-Byte
      18. OR EDX, EDX
      19. JZ CFehler
      20. IsLen:
      21. CMP EDX, -1
      22. JL CFehler
      23. MOV AL, [EBX] // Erstes Trennzeichen in AL
      24. MOV BH, [EBX + 1]// Zeites Trennzeichen in BH
      25. MOV BL, AL // Erstes Trennzeichen in BL
      26. OR BH, BH // Zweites Trennzeichen ist 0?
      27. JNZ StartSuche // Nein: Beginnen
      28. MOV BH, BL // sonst gleiches Zeichen wie erstes Zeichen
      29. StartSuche:
      30. MOV AH, BL // Suche erstes Trennzeichen
      31. S1:
      32. LODSB
      33. CMP AL, AH
      34. JZ F1 // Trennzeichen gefunden
      35. DEC ECX
      36. CMP ECX, -1
      37. JZ StrtFehler // Speicherende vor gefunden
      38. OR AL, AL
      39. JZ StrtFehler // Nullbyte = Textende
      40. JMP S1
      41. F1:
      42. MOV EDI, ESI // Stringanfang nach EDI
      43. EndeSuche:
      44. MOV AH, BH // Zweites Trennzeichen suchen
      45. S2:
      46. LODSB
      47. CMP AL, AH
      48. JZ F2 // Trennzeichen gefunden
      49. DEC ECX
      50. CMP ECX, -1
      51. JZ EndeFehler // Speicherende vor gefunden
      52. OR AL, AL
      53. JZ EndeFehler // Nullbyte = Textende vor gefunden
      54. JMP S2
      55. F2:
      56. DEC EDX // Gefunden, Teilstringnummer runter zählen
      57. JNZ StartSuche // Nicht der gesuchte Teilstring, nächsten Start suchen
      58. MOV EAX, ESI
      59. DEC EAX // EAX zeigt auf letztes Teilstringzeichen
      60. JMP Ausgabe
      61. CFehler:
      62. POP EAX // Stackkorrektur
      63. POP EAX // Stackkorrektur
      64. MOV EAX, -3 // Fehler setzen (ungültige Teilstringnummer) = -3
      65. JMP Ende
      66. StrtFehler:
      67. CMP EDX, 0
      68. JL Counter
      69. XOR EAX, EAX // Startfehler (Nicht gefunden) = 0
      70. JMP Fehler
      71. EndeFehler:
      72. CMP EDX, 0
      73. JL Counter // Teilstringzählen ausfiltern
      74. MOV EAX, -1 // Endefehler (Zweites Trennzeichen nicht gefunden) = -1
      75. Fehler:
      76. POP ECX // Länge Ergebnispuffer
      77. POP EDI // Adresse Ergebnispuffer
      78. OR EDI, EDI // kein Ausgabepuffer angegeben?
      79. JZ NoMemF // ist kein Fehler
      80. OR ECX, ECX // Ist 0?
      81. JZ MemFehler // Ja: Speicherfehler
      82. PUSH EAX
      83. XOR EAX, EAX // 0 als Ergebnisstring
      84. STOSB // 0 in Ausgabepuffer schreiben
      85. POP EAX
      86. NoMemF:
      87. JMP Ende
      88. MemFehler:
      89. MOV EAX, -2 // Fehler setzen (Speicher zu klein) = -2
      90. JMP Ende
      91. Counter:
      92. NOT EDX // Teilstringzahl umrechnen
      93. // setzt voraus, daß Anzahl als 1 angegeben war
      94. POP EAX // Stackkorrektur
      95. POP EAX // Stackkorrektur
      96. MOV EAX, EDX // Teilstringzahl nach Ergebnis
      97. JMP Ende
      98. Ausgabe: // kopiert gefundenen Teilstring in Ausgabepuffer
      99. SUB EAX, EDI // Teilstringlänge nach EAX
      100. MOV ESI, EDI // Anfang Teilstring nach ESI
      101. POP ECX // Länge Ergebnispuffer holen
      102. POP EDI // Anfang Ergebnispuffer holen
      103. OR EDI, EDI // Ergebnispuffer 0: Nur Teilstringlänge ermitteln?
      104. JZ Ende // JA, gleich beenden
      105. CMP EAX, ECX
      106. JNB MemFehler // Ergebnispuffer kleinergleich Teilstringlänge
      107. // muß ein Byte länger sein!
      108. PUSH EAX // Teilstringlänge notieren
      109. MOV ECX, EAX // und für REP nach ECX
      110. REPNZ
      111. MOVSB
      112. POP EAX // Teilstringlänge nach Rückgabe
      113. Ende:
      114. POP EDI
      115. POP ESI
      116. POP EDX
      117. POP ECX
      118. POP EBX
      119. EndASM
      Alles anzeigen
      Gruß Volkmar
    • Brackets(Text#, TextLänge%, Funktion%, AusgabePuffer#, AusgabePufferLänge%, Addr(KlammerPaar$))


      In Text# wird der zu untersuchende Text gestellt. Die Textlänge% kann -1 sein, wenn es sich um einen nullterminierten String handelt.
      Funktion% kann folgende Werte annehmen
      -2 ermittelt die Anzahl Klammerpaare, Ausgabepuffer# und AusgabePufferLänge% sollten 0 sein
      -1 ermittelt tiefste Klammerverschachtelung, Ausgabepuffer# und AusgabePufferLänge% sollten 0 sein
      1 .. n ermittelt Text in der angegebenen Klammernummer*, Rückgabewert ist die Verschachtelungsebene dieser Klammer
      KlammerPaar$ ist immer die Adresse eines Strings, der das gesuchte Klammerpaar enthält, also "()" oder "[]" oder "{}"

      Mögliche Fehlerwerte:
      -1 AusgabePuffer zu klein
      -2 Klammern in Text# nicht ausgewogen
      -3 KlammerPaar$ zu kurz (nur 1 Zeichen oder Leerstring)
      -4 KlammerPaar$ enthält zwei identische Zeichen
      -5 mehr als 255 Klammern sind nicht möglich
      -6 Funktion% ungültig (0 oder <-2)
      -7 Gesuchte Klammernummer nicht gefunden
      *Klammern werden immer von links nach rechts nach dem Auftreten der öffnenden Klammer gezählt

      Quellcode

      1. ASM "Brackets", 6
      2. PUSH EBX
      3. PUSH ECX
      4. PUSH EDX
      5. PUSH ESI
      6. PUSH EDI
      7. MOV ESI, Par1 // Eingabezeile
      8. MOV ECX, Par2 // Länge Eingabezeile oder -1
      9. MOV EDX, Par3 // Funktionsauswahl
      10. MOV EDI, Par4 // Ausgabepuffer
      11. MOV EBX, Par5 // Länge Ausgabepuffer
      12. MOV [OutLen], EBX
      13. MOV EBX, Par6 // Klammerstring
      14. JMP Start
      15. FM:
      16. DD 0 // Funktionsnummer oder Klammerzahl bei Kopieren
      17. KE:
      18. DD 0 // Klammerebene bei Kopieren
      19. OutLen:
      20. DD 0 // Merker Ausgabelänge
      21. Count: // Zählt nur die Klammerpaare
      22. NEG EDX
      23. MOV [FM], DL // Funktionsnummer zwischenspeichern
      24. XOR EDX, EDX // Zählregister löschen
      25. XOR EAX, EAX
      26. CS:
      27. LODSB
      28. DEC ECX
      29. JZ CEnde // Stringende erreicht
      30. OR AL, AL // Null-Byte?
      31. JZ CEnde // Ja: Stringende erreicht
      32. CMP AL, BH // Schließende Klammer
      33. JNE NSC
      34. DEC DL // Klammerzahl runterzählen
      35. JS COV // Klammerfehler (Vorzeichen negativ)
      36. NSC:
      37. CMP AL, BL // Öffnende Klammer
      38. JNE CS // Nein: Weitersuchen
      39. INC DL // Klammerzahl hochzählen
      40. INC AH
      41. CMP DL, DH
      42. JL NoBM
      43. MOV DH, DL // und merken, wenn nicht kleiner als bisherige Merkzahl
      44. NoBM:
      45. JMP CS
      46. CEnde:
      47. OR DL, DL
      48. JNZ COV // Klammerzähler <> 0 ist Klammerfehler
      49. MOV DL, [FM] // Funktionsnummer holen
      50. CMP DL, 1 // ist 1?
      51. JZ NBP // Ja, höchste Klammerzahl (Verschachtelungstiefe)
      52. MOV DH, AH // sonst Klammerpaare insgesamt
      53. NBP:
      54. XOR EAX, EAX
      55. MOV AL, DH // Ergebnis nach EAX
      56. JMP Ende // Abgeschlossen mit Klammerzahl in EAX
      57. COV:
      58. MOV EAX, -2 // Fehlercode -2: Klammern nicht ausgewogen
      59. JMP Ende
      60. // ############
      61. All: // Alle Klammerinhalte kopieren
      62. MOV EAX, -6 // Funktion 0 noch nicht implementiert
      63. JMP Ende
      64. // ############
      65. ZahlCopy: // einzelnen Klammerinhalt kopieren, EDX enthält Nummer der Klammer
      66. CMP EDX, 255
      67. JNA ZCCanSeek // gesuchte Klammernummer nicht größer als 255 ist erlaubt
      68. MOV EAX, -5 // ab Klammernummer 256 Fehler -5
      69. JMP Ende
      70. ZCCanSeek:
      71. OR EDI, EDI
      72. JNZ ZCNoMErr
      73. MOV EAX, -1
      74. JMP Ende
      75. ZCNoMErr:
      76. XOR EAX, EAX
      77. MOV AL, [OutLen]
      78. OR AL, AL
      79. JNZ ZCOSeekStart
      80. MOV EAX, -1 // Speicherfehler
      81. JMP Ende
      82. ZCOSeekStart:
      83. MOV AH, DL // zu suchende Klammernummer nach AH
      84. XOR EDX, EDX // Zählregister löschen
      85. MOV [KE], EDX
      86. ZCOSeek:
      87. LODSB
      88. OR AL, AL
      89. JZ ZCFertig1 // Wenn Nullbyte erkannt
      90. DEC ECX
      91. OR ECX, ECX
      92. JZ ZCFertig1 // Wenn Stringlänge durch
      93. CMP AL, BH
      94. JNZ ZCNoSK // keine schließende Klammer
      95. INC DH // schließende Klammer zählen
      96. PUSH EAX
      97. MOV EAX, [KE]
      98. DEC EAX
      99. MOV [KE], EAX
      100. POP EAX
      101. JMP ZCOSeek
      102. ZCNoSK:
      103. CMP AL, BL
      104. JNZ ZCNoOK // keine öffnende Klammer
      105. INC DL // öffnende Klammer zählen
      106. PUSH EAX
      107. MOV EAX, [KE]
      108. INC EAX
      109. MOV [KE], EAX
      110. POP EAX
      111. CMP AH, DL
      112. JE ZCCopy
      113. ZCNoOK:
      114. JMP ZCOSeek
      115. // hier dann Copyroutine, wenn DL = AH
      116. ZCFertig1: // Auffangpunkt Sprungdistanz
      117. JMP ZCFertig // weiterleiten
      118. ZCCopy:
      119. MOV [FM], 0 // Klammerzähler zurücksetzen
      120. ZCCopy1:
      121. LODSB
      122. OR AL, AL
      123. JZ ZCFertig1 // Wenn Nullbyte erkannt
      124. DEC ECX
      125. OR ECX, ECX
      126. JZ ZCFertig1 // Wenn Stringlänge durch
      127. CMP AL, BH
      128. JNZ ZCCNoSK // keine schließende Klammer
      129. INC DH // schließende Klammer zählen
      130. SUB [FM], 1 // gemerkte Klammerzahl runterzählen
      131. JLE CopyEnd // Kopierende
      132. ZCCNoSK:
      133. CMP AL, BL
      134. JNZ ZCSSeek
      135. INC DL // öffnende Klammer zählen
      136. ADD [FM], 1
      137. ZCSSeek:
      138. STOSB
      139. DEC [OutLen]
      140. JNZ ZCCopy1 // Ausgabepuffer nicht voll
      141. MOV EAX, -1 // sonst Speicherfehler
      142. JMP Ende
      143. ZCFertig:
      144. CMP DL, DH
      145. JE ZCNoBErr // öffnende und schließende Klammerzahl gleich
      146. MOV EAX, -2 // sonst Fehler Klammern nicht ausgewogen
      147. JMP Ende
      148. ZCNoBErr:
      149. MOV EAX, -7 // kein Fehler aufgetreten, nichts kopiert
      150. JMP Ende
      151. CopyEnd:
      152. XOR EAX, EAX // Nullbyte an Ausgabe anfügen
      153. STOSB
      154. MOV EAX,[KE] // Verschachtelungstiefe holen
      155. JMP Ende
      156. // ############
      157. Start: // Parameter prüfen und in Funktionsteile verzweigen
      158. OR EBX, EBX // ist Klammerstring 0?
      159. JZ BParErr // Klammerangabe zu kurz oder fehlt
      160. MOV AL, [EBX] // öffnende Klammer nach AL
      161. MOV BH, [EBX + 1] // schließende Klammer nach HB
      162. OR BH, BH // ist schließende Klammer NullByte?
      163. JNZ NoBParErr1 // Nein, kein Fehler
      164. BParErr:
      165. MOV EAX, -3 // Klammerangabe im Parameter zu kurz oder fehlt
      166. JMP Ende
      167. NoBParErr1:
      168. MOV BL, AL // öffnende Klammer nach BL
      169. CMP BL, BH // öffnende und schließende Klammer gleich?
      170. JNZ NoBParErr2 // Nein, kein Fehler
      171. MOV EAX, -4 // beide Klammern gleiches Zeichen
      172. JMP Ende
      173. NoBParErr2:
      174. // hier EDX auswerten und zur jeweiligen Funktion verzweigen
      175. CMP EDX, -1 // Funktion -1 durch Count bearbeitet
      176. JZ CountCall
      177. CMP EDX, -2 // Funktion -2 durch Count bearbeitet
      178. JZ CountCall
      179. // ab hier erst mal Fehler für ungültige Funktionen
      180. OR EDX, EDX
      181. JNZ ZCopy // Funktion 1 .. n
      182. JMP All // Funktion 0
      183. MOV EAX, -6 // sonstige Funktionen noch nicht implementiert
      184. JMP Ende
      185. ZCopy:
      186. JMP ZahlCopy
      187. CountCall:
      188. JMP Count // hier nun Count aufrufen
      189. Ende:
      190. POP EDI
      191. POP ESI
      192. POP EDX
      193. POP ECX
      194. POP EBX
      195. EndASM
      Alles anzeigen

      Gruß Volkmar