; Guide to Assembly Language
   ; Section 8.6 Complete Program
   ; Copyright 2019, James T. Streib
   .listall
   .686
   .model flat,c
     .stack 100h
scanf     PROTO arg2:Ptr Byte, inputlist:VARARG
printf    PROTO arg1:Ptr Byte, printlist:VARARG
   .data
in1fmt    byte "%s",0
in2fmt    byte "%d",0
msg1fmt   byte 0Ah,"%s",0
msg3fmt   byte 0Ah,"%s%d",0Ah,0
msg4fmt   byte 0Ah,0
errfmt    byte 0Ah,"%s",0Ah,0
msg1      byte "Enter a command, e, d, or s: ",0
msg2      byte "Enter a positive integer: ",0
msg3      byte "The integer is: ",0
errmsg1   byte "Error: Invalid entry, try again",0
errmsg2   byte "Error: Queue is full",0
errmsg3   byte "Error: Queue is empty",0
queue     sdword 3 dup(?)
command   sdword ?
number    sdword ?
count     sdword 0
   .code
enqueue   macro
   .if count < lengthof queue
   inc count                  ; increment count
   mov eax,number             ; load eax with number
   mov [edi],eax              ; store eax in rear
   mov eax,edi                ; copy edi (rear) to eax
   sub eax,offset queue       ; subtract address of queue
   add eax,4                  ; increment eax by 4
   cdq                        ; convert double to quad
   mov ecx,sizeof queue       ; get size of queue (bytes)
   idiv ecx                   ; divide
   mov edi,offset queue       ; load address in rear
   add edi,edx                ; add remainder to rear
   .else
   INVOKE printf, ADDR errfmt, ADDR errmsg2    
   .endif
   endm      
dequeue   macro
   .if count > 0
   dec count                  ; decrement count
   mov eax,[esi]              ; load eax from front     
   mov number,eax             ; store eax in number
   mov eax,esi                ; copy esi (front) to eax
   sub eax,offset queue       ; subtract address of queue
   add eax,4                  ; increment eax by 4
   cdq                        ; convert double to quad
   mov ecx, sizeof queue      ; get size of queue (bytes)
   idiv ecx                   ; divide
   mov esi,offset queue       ; load address in front
   add esi,edx                ; add remainder to front
   .else
   INVOKE printf, ADDR errfmt, ADDR errmsg3
   mov number,-1              ; store -1 (flag) in number
   .endif
   endm          
main      proc
   mov edi,offset queue+0     ; use edi as front of queue
   mov esi,offset queue+0     ; use esi as rear of queue
   INVOKE printf, ADDR msg1fmt, ADDR msg1     ; priming
   INVOKE scanf, ADDR in1fmt, ADDR command    ; read
   .while command != "s"      ; while not stop
   .if command=="e"           ; enqueue?
   INVOKE printf, ADDR msg1fmt, ADDR msg2
   INVOKE scanf, ADDR in2fmt, ADDR number   
   enqueue                    ; enqueue number
   .elseif command=="d"       ; dequeue?
   Dequeue                    ; deque number
   .if number >0              ; not -1 (flag)?
   INVOKE printf, ADDR msg3fmt, ADDR msg3, number
   .endif
   .else
   INVOKE printf, ADDR errfmt, ADDR errmsg1
   .endif
   INVOKE printf, ADDR msg1fmt, ADDR msg1
   INVOKE scanf, ADDR in1fmt, ADDR command
   .endw    
   INVOKE printf, ADDR msg4fmt
   ret
main      endp
   end