;
;    Mecrisp - A native code Forth implementation for MSP430 microcontrollers
;    Copyright (C) 2011  Matthias Koch
;
;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
;

; Routinen, um mit Strings umzugehen, die aus einem Längenbyte und den folgenden Zeichen bestehen,

;------------------------------------------------------------------------------
;  Kapitelbirne_flash "--- Strings ---"  Das ist in query.asm ausgelagert !
;------------------------------------------------------------------------------ 
  
lowercase macro Zeichen ; Ein Zeichen in einem Register wird auf Lowercase umgestellt.
  ;    Hex Dec  Hex Dec
  ; A  41  65   61  97  a
  ; Z  5A  90   7A  122 z

  cmp.b #041h, Zeichen
  jlo +
  cmp.b #05Bh, Zeichen
  jhs +
  add.b #020h, Zeichen
+ ; Fertig
          endm

;------------------------------------------------------------------------------ 
  ifdef spezialstrings
    Wortbirne Flag_sichtbar, "compare" 
    flagdolmetscher
  endif
stringvergleich: ; ( Adresse Adresse -- ) Carry-Flag: Ergebnis.
;------------------------------------------------------------------------------ 
  push r10  ; Adresse des ersten  Strings
  push r11  ; Adresse des zweiten Strings
  push r12  ; Zeichen aus dem ersten  String
  push r13  ; Zeichen aus dem zweiten String
  push r14  ; Länge

  popda r10 ; Adresse des ersten  Strings holen
  popda r11 ; Adresse des zweiten Strings holen

  mov.b @r10+, r14 ; Längenbyte des ersten Strings holen
  cmp.b @r11+, r14 ; Mit dem Längenbyte des zweiten Strings vergleichen
  jne stringvergleich_ungleich ; Was macht das Carry-Flag bei cmp ?
  
  tst r14                      ; Für den Fall, dass leere Strings verglichen werden.
  jz stringvergleich_gleich

- ; Die Längen sind identisch. Prüfe nun nacheinander die Zeichen in den Strings.
  mov.b @r10+, r12
  mov.b @r11+, r13

  ifdef caseinsensitive
    ; Lowercase r12 und r13 für case-insensitive.
    lowercase r12
    lowercase r13
  endif

  cmp.b r12, r13
  jne stringvergleich_ungleich

  dec r14
  jnz -

stringvergleich_gleich:  
  setc
  jmp +

stringvergleich_ungleich:
  clrc 

+ pop r14
  pop r13
  pop r12
  pop r11
  pop r10
  ret

;------------------------------------------------------------------------------
  ifdef spezialstrings
    Wortbirne Flag_sichtbar, "skipstring"
  endif

stringueberlesen: ; ( Adresse -- Adresse ) 
                  ; Überspringt einen String.
;------------------------------------------------------------------------------
  push r10
  push r11

  mov @r4, r10 ; Stringanfangsadresse

    mov.b @r10, r11 ; Hole das Längenbyte nach r11
    inc r10         ; Längenbyte überlesen
    add r11, r10    ; Zahl der Textzeichen hinzuaddieren
  pop r11 

  ; Füll-Null überlesen, falls ungerade Adresse...
  bit #1, r10
  adc r10

  ; Zeiger ist jetzt beim Befehl nach dem String.
  mov r10, @r4

  pop r10
  ret

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "type"
schreibestringmitlaenge: ; ( Adresse -- ) 
                ; Schreibt einen String über emit hinaus
                ; Beispiel: Moinstring:  .byte 5, "Moin", 10
                  ; So geht es !
                  ; pushda #Moinstring
                  ; call #schreibestringmitlaenge
;------------------------------------------------------------------------------
        push r10
        push r11

        popda r10          ; Anfangsadresse des Strings
        mov.b @r10, r11    ; Länge des Strings holen
        inc r10            ; r10 ist Adresszeiger
        
-       cmp #0, r11        ; Wenn die Länge Null ist, sind wir fertig.
        je +
        
        decd r4
        clr @r4
        mov.b @r10+, @r4

        ; pushdabyte @r10+   ; Zeichen auf den Datenstack legen, Highbyte 
        ; Vorsicht ! Hierbei könnte ein Highbyte mitgeschmuggelt werden.
        ; and #0FFh, @r4 ; Das wird hier wegmaskiert.

        call #emit        
        
        dec r11           ; Länge verringern
        jnz -        
        
+       pop r11
        pop r10        
        ret

  ifdef spezialstrings
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar_immediate, "s\i" ; Dies ist s" und gibt einen Stringpointer zurück.
;------------------------------------------------------------------------------
  push #sgaensefuesschen
  jmp gaensefuesschendetektor

sgaensefuesschen:
  ; Returnstack: ( Stringanfangsadresse-im-Rücksprung )
  
  ; Adresse des Strings ist in der Rücksprungadresse enthalten.
  pushda @sp ; Lege die Stringadresse für spätere Verwendung bereit.
  ; call #schreibestringmitlaenge ; Das ist der einzige Unterschied zu dotgaensefuesschen.
  jmp dotgaensefuesschen_inneneinsprung

  endif


;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar_immediate, ".\i" ; Dies ist ." und das write von Forth.
;------------------------------------------------------------------------------

  push #dotgaensefuesschen

gaensefuesschendetektor:
  call #qcomp
  
  r_from
  call #callkomma
  
  pushda #34
  call #parse
  br #kommastring

  ; Benutzung:
  ; call #dotgaensefuesschen
  ; .byte Länge, Buchstaben [, 0 um Adresse gerade zu machen]

dotgaensefuesschen:
  ; Returnstack: ( Stringanfangsadresse-im-Rücksprung )
  
  ; Adresse des Strings ist in der Rücksprungadresse enthalten.
  pushda @sp
  call #schreibestringmitlaenge

dotgaensefuesschen_inneneinsprung:

  pushda @sp+ ; Adresse vom Returnstack auf den Datenstack legen
  call #stringueberlesen ; Rücksprungadresse auf den Befehl nach dem String setzen.
  mov @r4+, pc ; Ret über den Datenstack


;------------------------------------------------------------------------------
  Kapitelbirne "--- Strings ---"  
;------------------------------------------------------------------------------ 
  
