    .model small
    .stack
    .data
        cr = 13     ;carrige return (kocsi vissza)
        lf = 10     ;line feed (uj sor)
        tab = 9     ;tabulator
        bckspc = 8  ;backspace a torleshez
		
        startszimb = 'S'  ;szabalyok start szimboluma

        start0 db 0    ;szabaly blokk kezdete
        b1 db 'S',1    ;szabaly bal oldala. 1-es az elvalaszto karakter
        j1 db 'aS',0   ;jobb oldal. A szabaly vege a 0
        b2 db 'S',1
        j2 db 'bAc',0
        b3 db 'A',1
        j3 db 'bAc',0
        b4 db 'A',1
        j4 db 'd',0
        maxindex = $   ;A szabaly blokk vege. dollar az aktualis cim
		
        prompt db 'Adj meg egy mondatot: ',0   ;kiirando uzenetek
        msgSzab db 'Szabalylista: ',0
        msgVeremTart db 'Verem: ',0
        msgAktKar db 'Aktualis karakter: ',0
        msgJo db 'Felismertem ezt a szot!',0
        msgNemJo db 'Ez bizony nem felel meg a szabalyoknak',0
		
        dcrlf db cr,lf,0   ;uj sor
        sep db ': ',0      ;az 1-es karaktert erre csereli
        bool db 0          ;boolean valtozo
        tmpchr db 0        ;ideiglenes valtozok
        tmpNT db 0
		
        verem db 255 dup(' '),0   ;a verem. max 255 karakteres
        vmut db 0                 ;verem mutato
        input db 255 dup(0)       ;az inputnak elõre lefoglalt 255 karakter
    .code

dsinit proc          ;adatszegmens inicializalasa
    push ax

    mov ax, @data    ;adatszegmens kezdocime ax-be
    mov ds, ax       ;ezt betoltjuk az adatszegmens regiszterbe

    pop ax
    ret
dsinit endp
	
clrscr proc	   ;DOS kepernyo torlese
    push ax    ;ax mentese
    mov ax, 3  ;3-as bekerul ah-ba. Utasitas kepernyo torlesere
    int 10h    ;hexa 10-es megszakitas. Kepernyo driver hivasara
    pop ax
    ret
clrscr endp
	
gotoNextStr proc          ;ugrik az adatszegmensben a kov stringre
    .while 1
       mov dl, [di]
       or dl, dl
	   .break .if zero?	   
       inc di
    .endw
    inc di
    ret
gotoNextStr endp
		
writem macro string       ;atadott karakter kiirasa kepernyore
    push bx
   
    lea bx, string
    call write_string
   
    pop bx
endm
	
write_string proc         ;dl-ben levo kezdocimtol string kiirasa
    push dx
    push bx

    .while 1
      mov dl, [bx]
      or dl, dl
      .break .if zero?   ;flag regiszter zero bitje ha 1, akkor kilep
      .if dl == 1
          writem sep
	  .else
          call write_char
      .endif
      inc bx
    .endw
    
    pop bx
    pop dx
    ret
write_string endp

write_char proc ;dl-ben varja mit kell kiirni
    push ax	; ax stack -be mentese

    mov ah, 2h	; Kiiras kodja
    int 21h
	
    pop ax	; ax-be a stackbol adat kivetele
    ret
write_char endp
	
writem_char macro chr    ;atadott karakter kiirasa kepernyore
    push dx
	
    mov dl, chr
    call write_char
	
    pop dx
endm
				
write_tab macro num     ;num darab tabulator kiirasa
    local _end          ;lokalis cimke. Kell, mert a makro tobbszor fut
    push dx             ;es minden alkalommal behelyettesiti a forrast
    push cx
	
    mov dl, tab
	mov cx, num
    .if cx == 0         ;ha 0 volt a tabok szaba, akkor kilep
       jmp _end
    .endif
    .repeat             ;ciklus amig cx nem nulla
       call write_char
    .untilcxz
	
  _end:
    pop cx
    pop dx	
endm
		
szablista proc              ;szabalyok listajaak kiirasa
    push di

    lea di, b1              ;az elso szabaly kezdocime di-be
    .while (di < maxindex)  ;ciklus amig di kisebb az utolso szabaly vegenek cimenel
       write_tab 1
       writem [di]
       call linebreak
       call gotoNextStr
    .endw

    pop di
    ret
szablista endp

linebreak proc        ;sortores
    writem dcrlf
    ret
linebreak endp

kovszab macro NT, chr  ;kovszab
    local vege         ;lokalis cimke
    push dx
    push ax

    mov tmpNT, NT      ;NT jelet el kell menteni, 
                       ;mert dl regiszter felul lesz irva
	
    lea di, b1         ;elso szabaly kezdocime
    .repeat
       mov dl, [di]    ;aktualis karakter a szabalyokbol
       .if dl == tmpNT    ;ha a szabaly karaktere nem terminalis
	       
           inc di
           inc di
           mov dl, [di]   ;ugras a szabaly job oldalara
		   
           .if dl == chr  ;ha a jobb oldal elso karaktere az amit keresunk
                _pop dl   ;kivesszuk a verembol
                call gotoNextStr  ;ugras a kovetkezo stringre
                dec di            ;vissza ugras az elozo string utolso karakterere
                dec di
                .while 1               ;ciklus
                    mov dh, [di]
                    .break .if dh == 1  ;amig nem elvalaszto karakter jon
				   
                   _push dh            ;verembe betesszuk az uj szabaly karaktereit
                   dec di              ;index  dekrementalasa
                .endw
				
                jmp vege               ;ha ide eljut, akkor megvan a szabaly
           .endif
       .endif  
        call gotoNextStr      ;ugras a kovetkezo szabalyra
    .until di > maxindex     ;amig nem erte el az utolso szabaly veget
   
    jmp eznemjo        ;ha nem talalta meg a szabalyt, akkor hiba

  vege:
    mov NT, tmpNT      ;ertekek visszaallitasa
	
    pop ax
    pop dx
endm

_pop macro chr      ;verembol ertek chr beirasa. mutato novelese
    push bx

    dec vmut
    xor bx, bx
    mov bl, vmut
    mov chr, verem[bx]
	
    pop bx	
endm

_push macro chr   ;vereme chr beirasa
    push bx

    xor bx, bx
    mov bl, vmut
    mov verem[bx], chr
    inc vmut
	
    pop bx	
endm

_top macro chr    ;mutato allitasa nelkul utolso karakter a verembol chr-be
    push bx

    xor bx, bx
    mov bl, vmut
    dec bl
    mov chr, verem[bx]

    pop bx
endm

write_verem proc       ;verem tartalmanak kiirasa
    push dx

    _push 0
    writem [verem+1] ;az elso karakter nula. Ezert a 2. tol kell kezdeni
    _pop dl

    pop dx
    ret
write_verem endp

isTerm macro chr           ;ha chr terminalis, akkor bool = 1, egyebkent bool = 0
    push di
    push dx

    mov bool, 1
    mov tmpchr, chr
    lea di, b1 
    .repeat
       mov dl, [di]       ;egyenloseg vizsgalat
       sub dl, tmpchr
       .if zero?          ;ha egyenlo volt a chr egy terminalis jellel,
          mov bool, 0     ;azaz zero flag 1-es, akkor nem terminalis
           .break
       .endif 
       call gotoNextStr   ;ugras a kovetkezo szabalyra
    .until di > maxindex  ;amig index kisebb az utolso szabaly vegenek cimenel

    pop dx
    pop di
endm

read_char proc			;egy karakter beolvasasa
    push ax				;ax regiszter mentese
	
    mov ah, 1			;karakter bekeres kodja
    int 21h				;hexa 21 -es megszakitas DOS-funkciok hivasahoz
						;A karakter ekkor AL regiszterbe kerül
	
    mov dl, al			;A karakter-t a DL regiszterbe tesszuk

    pop ax				;ax visszatoltese
    ret					;visszateres subrutinbol
read_char endp

readw proc
    push dx				;regiszterek tartalmanak elmentese
    push ax
    push cx
    push bx
	
    xor bx, bx
  readw_r_start:		;karakterek olvasasanak kezdete
    call read_char		;egy karakter beolvasasa. Eredmeny a dl regiszterbe kerul

    .if dl != cr
       mov input[bx], dl
       inc bx
       .if dl != bckspc
          jmp readw_r_start
       .endif
       writem_char ' '		;egyebkent az elozo karakter torlese a kepernyon
       writem_char bckspc	;majd visszapozicionalas a torolt karakter helyere

       dec bx
       mov input[bx], ' '
       dec bx
       mov input[bx], ' '
	
       jmp readw_r_start	;ciklus vege. Ha eddig eljut, kezdi elolrol
    .endif
    mov input[bx], 0
    call linebreak

    pop bx
    pop cx				;regiszterek visszaallitasa a verembol
    pop ax
    pop dx
	
    ret					;kilepes a subrutinbol
readw endp

debug proc                  ;aktualisertekek kiirasa
    writem msgVeremTart
    call write_verem
    writem_char ' ' 
    write_tab 1
	
    writem msgAktKar
    writem_char input[bx]

	
    call linebreak
    ret
debug endp

main proc                ;LL(1) szo felismerese
    call dsinit
    call clrscr          ;keperyno torlese
	 	
    writem prompt        ;szo bekerese
    call readw    
	
    call linebreak
    writem msgSzab      ;szabalyok listaja
    call linebreak
    call szablista
    call linebreak
		
    _push 0
    _push startszimb  ;start szimbolummal kezdunk a veremben

    xor bx, bx
    .repeat       ;ciklus, amig nem ertunk a verem vegere
        _top dl   ;verem teteje dl-be

        .if dl == 0   ;ha a verem ures
           call debug    
              .if input[bx] == 0   ;es ha az input vegere ertunk
                 jmp ezjo ;akkor felismertuk a nyelvet
              .else					   
                 jmp eznemjo ;egyebkent hiba
              .endif
        .endif
        		
        isTerm dl  ;ha terminalis jel volt dl, boolba 1 kerul. ha nem, boolba 0 kerul

        .if bool == 1           ;ha terminalis volt
            .if dl == input[bx] ;ha egyezik a beolvasando karakterel
                 call debug      
                _pop dl         ;kivesszuk a verembol
                inc bx          ;ugras a kov karakterre inputban
            .else               ;egyebkent hiba. Nem ismerheto fel a szo
                call debug
                jmp eznemjo     
            .endif
        .else                    ;ha nem terminalis jel volt
            call debug
            kovszab dl, input[bx]  ;akkor keressuk a kovetkezo szabalyt
			
        .endif
    .until dl == 0 ;verem vege, ha dl-ben nulla volt
	
    jmp ezjo
  eznemjo:
    call linebreak
    writem msgNemJo
    jmp vege
  ezjo:
    call linebreak
	writem msgJo
  vege:	 
    .EXIT
main endp	
	
		
end main
