;======================================================================
;  MAKEBAR: read a bar-definition-file (.BDF) and produce a tokenized
;  .BAR file to be read by the TSR interpreter.
;----------------------------------------------------------------------
CSEG	SEGMENT	PUBLIC	PARA	'CODE'
	ASSUME	CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
		ORG	100H
ENTPT:		JMP	MAIN

COPYRIGHT  DB  "MAKEBAR 1.0 (c) 1987, Ziff-Davis Publishing Corp",CR,LF,'$'
AUTHOR	   DB  1AH,"Robert L. Hummel"

;======================================================================
;  EQUATES
;----------------------------------------------------------------------
SPACE		EQU	20H			;Some keys
CR		EQU	0DH
LF		EQU	0AH
QUOTE		EQU	22H
TAB		EQU	09H

INPUT_BUF_LEN	EQU	4000			;Size constants
OUTPUT_BUF_LEN	EQU	46000
MENU_BUF_LEN	EQU	4000
MENU_TBL_LEN	EQU	4000
BUF_TOTAL = INPUT_BUF_LEN + OUTPUT_BUF_LEN + MENU_BUF_LEN + MENU_TBL_LEN

_SHIFT		EQU	1			;Internal shift flags
_CTRL		EQU	2
_ALT		EQU	4


;----------------------------------------------------------------------
;  BUFFERS AND POINTERS
;----------------------------------------------------------------------
INPUT_HNDL	DW	0			;Handle of source file
INPUT_HNDL_PTR	DW	0			;Pointer to source file
INPUT_BUF_END	DW	0FFFFH			;Used by GET_CHAR
OUTPUT_HNDL	DW	0			;Handle of output file
MENU_HEAD	DW	0			;Pointer to current menu
SHIFT_FLAGS	DB	0			;Hold current shift state

;----------------------------------------------------------------------
;  COUNTERS
;----------------------------------------------------------------------
SOURCE_LINE	DW	0			;For error messages
NEW_REF		DB	-1			;Two counters track menu
OLD_REF		DB	0			; references

;----------------------------------------------------------------------
;  TABLES
;----------------------------------------------------------------------
CMD_TABLE	LABEL	BYTE			;All commands names
_ASK		EQU	0			; and their token values
A_CMD		DB	'ASK',0
_CR		EQU	1
C_CMD		DB	'CR',0
_EXECUTE	EQU	2
E_CMD		DB	'EXECUTE',0
_INPUT		EQU	3
I_CMD		DB	'INPUT',0
_MENU		EQU	4
M_CMD		DB	'MENU',0
_OPTION		EQU	5
O_CMD		DB	'OPTION',0
_PROGRAM	EQU	6
P_CMD		DB	'PROGRAM',0
_TYPE		EQU	7
_CMD		DB	'TYPE',0
_MEND		EQU	8
		DB	'MEND',0
_END		EQU	9
		DB	'END',0
_SEND		EQU	10
		DB	0			;End-of-table byte
;----------------------------------------------------------------------
KEY_NAME_TBL	LABEL	BYTE			;Special key names
		DB	"S",0,"C",0,"A",0

		DB	"F1",0,"F2",0,"F3",0,"F4",0,"F5",0
		DB	"F6",0,"F7",0,"F8",0,"F9",0,"F10",0

		DB	"ESC",0,"TAB",0,"ENTER",0,"BS",0

		DB	"HOME",0,"PGUP",0,"END",0,"PGDN",0,"INS",0
		DB	"DEL",0,"U",0,"D",0,"L",0,"R",0,0
;----------------------------------------------------------------------
;  These keys may be combined with the CRTL and ALT keys
;----------------------------------------------------------------------
KEY_TBL_1	DB	"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-=\[]",0

;----------------------------------------------------------------------
;  CTRL combinations for 1234567890-= (use {c}1 for ; {c}3 for ")
;----------------------------------------------------------------------
KEY_TBL_2	DW	003BH,0FE03H,0022H,0,0,001EH,0,0,0,0,001FH,0
		DW	001CH, 001BH, 001DH
;----------------------------------------------------------------------
;  Scan codes for alpha keys a-z (used for ALT-alpha)
;----------------------------------------------------------------------
KEY_TBL_3	DB	01EH,30H,2EH,20H,12H,21H,22H,23H,17H,24H,25H,26H
		DB	32H,31H,18H,19H,10H,13H,1FH,14H,16H,2FH,11H,2DH
		DB	15H,2CH

;----------------------------------------------------------------------
;  SHIFT,CTRL for enter,bs,home,pgup,end,pgdn,ins,del,up,down,left,right
;----------------------------------------------------------------------
KEY_TBL_4	DB	0DH,0FEH, 8,7FH, 47H,77H, 49H,84H, 4FH,75H
		DB	51H,76H, 52H,0, 53H,0, 48H,0, 50H,0, 4BH,73H,4DH,74H

;----------------------------------------------------------------------
;  FLAGS
;----------------------------------------------------------------------
MENU_FLAG	DB	0		;Non-zero when open menu blk
OPTION_FLAG	DB	0		;Non-zero when open option blk
PROGRAM_NAME_FLAG DB	0		;Non-zero when PROGRAM cmd read

;----------------------------------------------------------------------
;  MESSAGES
;----------------------------------------------------------------------
USAGE_MSG	DB	"Usage: MAKEBAR [path]input_file [path]output_file$"
BAD_FILE_MSG	DB	"Can't Open File$"
READ_MSG	DB	"Error Reading File$"

DUP_CMD_MSG	DB	"Duplicate Cmd$"
CMD_ORDER_MSG	DB	"Cmd Out Of Order$"
UNK_CMD_MSG	DB	"Unknown Cmd$"

NEST_MSG	DB	"MENU Without MEND$"
SYNTAX_MSG	DB	"Syntax Error$"
NO_NAME_MSG	DB	"Missing Name$"
REF_MSG		DB	"Bad MENU Reference$"
EOF_MSG		DB	"Missing END$"
DEAD_KEY_MSG	DB	"Dead-Key or Bad Key$"
LINE_MSG	DB	CR,LF,"Error At Line #       $"
LINE_NUM_BUF	EQU	$-2

;======================================================================
;  MENU FILE TOKENIZER - MAIN PROCEDURE
;----------------------------------------------------------------------
MAIN		PROC	NEAR

		MOV	AH,9			;Display string fn
		MOV	DX,OFFSET COPYRIGHT	;Say who we are
		INT	21H			; Thru DOS

		CLD				;Strings moves forward
;----------------------------------------------------------------------
;  Check the file specs given on the command line.  Open the files and
;  save the file handles.
;----------------------------------------------------------------------
		CALL	OPEN_FILES

;----------------------------------------------------------------------
;  Read in the Menu-Definition-File and tokenize.  Write the output to
;  the new .BAR file for use with the resident interpreter.
;----------------------------------------------------------------------
		CALL	TOKENIZE

;----------------------------------------------------------------------
;  Close and update any open files.  Terminate gracefully.
;----------------------------------------------------------------------
		CALL	CLOSE_FILES
		MOV	AX,4C00H		;Terminate process
		INT	21H			; Thru DOS

MAIN		ENDP

;======================================================================
;  OPEN_FILES - Open the file given on the command line and the working
;  files needed during operation of the tokenizer.
;----------------------------------------------------------------------
OPEN_FILES	PROC	NEAR

		MOV	SI,81H			;Command line parameters
		CALL	OPEN_A_FILE		;Open source
		MOV	INPUT_HNDL,AX		;Save handle

		CALL	OPEN_A_FILE		;Open destination file
		MOV	OUTPUT_HNDL,AX		;Save handle

		MOV	INPUT_BUF_END,0		;Make refresh occur
		RET

OPEN_FILES	ENDP

;======================================================================
; OPEN_A_FILE - Read a string from the command line and attempt to open
;  it as a file.
;----------------------------------------------------------------------
OPEN_CNT	DB	0			;Switch for open function

OPEN_A_FILE	PROC	NEAR

		CALL	NON_WHITE		;Point SI to 1st nonwhite
		CMP	AL,CR			;If not carriage return
		JNE	HAVE_ARGS		; go parse arguments
NO_SPECS:
		MOV	DX,OFFSET USAGE_MSG	;Say how we are used
OPEN_ERR:
		JMP	ERROR_EXIT		;Exit thru error procedure
HAVE_ARGS:
		PUSH	SI			;Save start of string
		CALL	WHITE			;Point past end
		MOV	CX,SI			;End of string
		POP	SI			;Restore start
		SUB	CX,SI			;Get length of string
		OR	CX,CX			;If zero
		JZ	NO_SPECS		; no file names
		MOV	DI,OFFSET PATH_BUF	;Copy string here
		REP	MOVSB			; do it
		XOR	AL,AL			;Make ASCIIZ
		STOSB				; put in buffer

;----------------------------------------------------------------------
;  Attempt to open the file.
;----------------------------------------------------------------------
		MOV	AX,3D00H		;Open file for reading
		CMP	OPEN_CNT,0		; if first file
		JE	FILE_OPEN
		DEC	AH			;Create file if second
FILE_OPEN:
		MOV	DX,OFFSET PATH_BUF	;Pathname of file
		INT	21H			;Handle in AX
		JNC	SOURCE_OPEN		;No carry if open OK
		MOV	DX,OFFSET BAD_FILE_MSG
		JMP	OPEN_ERR
SOURCE_OPEN:
		INC	OPEN_CNT		;Change switch
		RET

OPEN_A_FILE	ENDP

;======================================================================
;  Close the files to update the length.
;----------------------------------------------------------------------
CLOSE_FILES	PROC	NEAR

		MOV	AH,3EH			;Close file function
		MOV	BX,INPUT_HNDL		; first file
		INT	21H			; Thru DOS

		MOV	AH,3EH			;Close file function
		MOV	BX,OUTPUT_HNDL		; second file
		INT	21H			; Thru DOS
		RET

CLOSE_FILES	ENDP

;======================================================================
; TOKENIZE - Read and process the Bar Definition File (BDF).
;----------------------------------------------------------------------
TOKENIZE	PROC	NEAR

;----------------------------------------------------------------------
;  Clear flags and reset source line counter.
;----------------------------------------------------------------------
		XOR	AX,AX			;Zero
		MOV	PROGRAM_NAME_FLAG,AL	;No program name
		MOV	MENU_FLAG,AL		;Not inside MENU block
		MOV	SOURCE_LINE,AX		;Source line counter

		MOV	DI,OFFSET MENU_NAME_TBL	;Fill the table with zeros
		MOV	CX,MENU_TBL_LEN		;Entire length
		REP	STOSB			; do it

		CALL	REFRESH_BUFFER		;Load some chars into buf
		MOV	DI,OFFSET OUTPUT_BUF	;Init output buffer pointer

;----------------------------------------------------------------------
;  Parse the input file to find commands and arguments.
;----------------------------------------------------------------------
FIND_WORD:
		CALL	NON_WHITE		;Find non-white char
		CMP	AL,CR			;Ignore blank lines
		JNE	TKN_1
		CALL	NEXT_LINE		;Skip to next line
		JMP	FIND_WORD		;Continue search
TKN_1:
;----------------------------------------------------------------------
;  SI points to word.  Compare with known commands.  Return token in AL
;  or 0FFh if not recognized.
;----------------------------------------------------------------------
		CALL	MAKEZ			;Copy word at SI to buffer
						; and make ASCIIZ
		PUSH	SI			;Preserve SI
		MOV	SI,OFFSET CMD_TABLE	;Look up word in this table
		CALL	TABLE_LOOKUP		;Compare cmd in buffer
		POP	SI			;AL = CMD # or FFh
		CMP	AL,0FFH			;Is error?
		JNE	TKN_1A			;No, valid CMD found
		MOV	DX,OFFSET UNK_CMD_MSG
		JMP	SHORT TKN_ERR
TKN_1A:
;----------------------------------------------------------------------
;  If this is a PROGRAM statement, load the name of the program into the
;  buffer.  Must be the first command in the file.
;----------------------------------------------------------------------
		CMP	PROGRAM_NAME_FLAG,0	;Test if already had PROGRAM
		PUSHF				;Save result

		CMP	AL,_PROGRAM		;Is this PROGRAM?
		JE	TKN_2			; yes, jump

		POPF				;Did we have one?
		JNZ	TKN_4			; yes, try next cmd
		JMP	TKN_7A			; no, error
TKN_2:
		POPF				; yes, Did we have one?
		JZ	TKN_3			;  No, this is first
		MOV	DX,OFFSET DUP_CMD_MSG	;  Yes, indicate error
		JMP	SHORT TKN_ERR
TKN_3:
;----------------------------------------------------------------------
;  Copy the name of the program to the output buffer.
;----------------------------------------------------------------------
		MOV	BX,DI			;Point BX to start of buf
		MOV	AL,SPACE		;Fill name with spaces
		MOV	CX,10			;10 chars
		REP	STOSB			;do it

		CALL	NEXT_WORD
		CALL	TKN_STRING		;Copy quoted string

		INC	PROGRAM_NAME_FLAG	;Make flag non-zero
		JMP	FIND_WORD		;Get next command
TKN_4:
;----------------------------------------------------------------------
;  END command terminates processing.
;----------------------------------------------------------------------
		CMP	AL,_END			;If not END, jump
		JNE	TKN_4A

		MOV	AL,MENU_FLAG		;If no open menus
		OR	AL,OPTION_FLAG		; or options
		JZ	NO_OPENS		; then clean up
TKN_4AA:
		MOV	DX,OFFSET NEST_MSG	;Else, nesting error
		JMP	SHORT TKN_ERR
NO_OPENS:
		MOV	AL,NEW_REF		;If no unbalanced menu
		OR	AL,OLD_REF		; references
		JZ	REFS_OK			; write the results
		MOV	DX,OFFSET REF_MSG	;Else, error
TKN_ERR:
		JMP	ERROR_EXIT
REFS_OK:
;----------------------------------------------------------------------
;  Flush the output buffer.
;----------------------------------------------------------------------
		MOV	DX,OFFSET OUTPUT_BUF	;Source buffer
		MOV	CX,DI			;End of buf
		SUB	CX,DX			; minus start = length
		MOV	AH,40H			;Write to file
		MOV	BX,OUTPUT_HNDL		; this handle
		INT	21H			;Thru DOS
		RET				;Return to top level

;----------------------------------------------------------------------
;  Is this a command to start a MENU block?
;----------------------------------------------------------------------
TKN_4A:
		CMP	AL,_MENU
		JNE	TKN_6			;Jump if not MENU

;----------------------------------------------------------------------
;  If we are already inside an active menu block, either an MEND is
;  missing or the menus are nested (both are errors).
;----------------------------------------------------------------------
		CMP	MENU_FLAG,0
		JNE	TKN_4AA			;Jump if in block

;----------------------------------------------------------------------
;  Execute MENU block startup code.  Point BX to a buffer where the
;  tokenized output will be temporarily stored.  When then menu block is
;  closed, the addresses in the menu header will be adjusted by the length
;  of the header.
;----------------------------------------------------------------------
TKN_5:
		MOV	BX,OFFSET MENU_BUF	;Buffer for menu tokens
		MOV	MENU_HEAD,DI		;Location of menu header
		XOR	AX,AX			;Number of OPTIONS = 0
		STOSW				; placed in header (at DI)
		INC	MENU_FLAG		;Say we're inside menu

;----------------------------------------------------------------------
;  Make sure the MENU command is followed by a name
;----------------------------------------------------------------------
		CALL	NEXT_WORD		;Point SI to next word
		CMP	AL,CR			;If CR, no name = error
		JE	TKN_8A
;----------------------------------------------------------------------
;  If Menu name is in table, it was referenced by an earlier menu and
;  the address must be put back into that command line.  If it's not in
;  the table, add it and point to it's address.
;----------------------------------------------------------------------
		CALL	MAKEZ			;Change menu name to ASCIIZ
		MOV	AX,MENU_HEAD		;Signal says posting
		SUB	AX,OFFSET OUTPUT_BUF	;Make into offset
		CALL	SEARCH_MENU_TABLE	;Enter in table or resolve
						; reference or error
		CALL	NEXT_LINE		;Skip to next line
		JMP	FIND_WORD		;Continue parsing

;----------------------------------------------------------------------
;  If not a MENU command, must be inside a block to be valid.
;----------------------------------------------------------------------
TKN_6:
		CMP	MENU_FLAG,0
		JE	TKN_7A			;Jump if outside block
TKN_7:
;----------------------------------------------------------------------
;  Inside a MENU block must reside a series of OPTION blocks.
;----------------------------------------------------------------------
		CMP	OPTION_FLAG,0		;Test if in option block
		PUSHF				; save result

		CMP	AL,_OPTION
		JE	TKN_8			;Jump if OPTION
		POPF				;Inside option block?
		JNE	TKN_12			;Jump if yes
TKN_7A:
		MOV	DX,OFFSET CMD_ORDER_MSG
		JMP	TKN_ERR
TKN_8:
		POPF				;Inside option block?
		JE	NEW_OPTION_BLOCK	;Jump if not

;----------------------------------------------------------------------
;  Close this option block by adding the SEND command.
;----------------------------------------------------------------------
		MOV	AL,_SEND		;Send token
		CALL	PUT_MENUBUF		; to buffer

;----------------------------------------------------------------------
;  To start new option block, increase the option counter.
;  Parse name and help line and point the pointers at them.
;----------------------------------------------------------------------
NEW_OPTION_BLOCK:
		INC	OPTION_FLAG		;Inside option block
		MOV	BP,MENU_HEAD		;Number options this MENU
		INC	WORD PTR [BP]		; increase by 1

;----------------------------------------------------------------------
;  Save the option name
;----------------------------------------------------------------------
		CALL	NEXT_WORD		;Point to OPTION NAME
		CMP	AL,CR			;Option must have name
		JNE	TKN_9			;Jump if name
TKN_8A:
		MOV	DX,OFFSET NO_NAME_MSG
		JMP	TKN_ERR
TKN_9:
		CALL	MAKEZ			;Make name at SI into ASCIIZ
		MOV	AX,BX			;Address where name is stored
		SUB	AX,OFFSET MENU_BUF	; from start of buffer
		STOSW				; is saved in menu header

;----------------------------------------------------------------------
;  Copy the option name from the asciiz buffer to the menu buffer
;----------------------------------------------------------------------
		PUSH	SI			;Save register
		MOV	SI,OFFSET PATH_BUF	;Source for copy
COPY_NAME:
		LODSB				;Get char
		CALL	PUT_MENUBUF
		OR	AL,AL			;If not last byte
		JNZ	COPY_NAME		;continue copy
		POP	SI			;Restore register
		CALL	NEXT_WORD		;Look for help line

;----------------------------------------------------------------------
;  HELP line is quoted string
;----------------------------------------------------------------------
TKN_11:
		MOV	AX,BX			;Offset from start of buf
		SUB	AX,OFFSET MENU_BUF	; is location to put
		STOSW				; in header
		CALL	TKN_STRING

;----------------------------------------------------------------------
;  Put the offset where the tokenized commands will start into the header.
;----------------------------------------------------------------------
		MOV	AX,BX			;Current location
		SUB	AX,OFFSET MENU_BUF	; minus start is offset
		STOSW				;Put word
		JMP	FIND_WORD

;----------------------------------------------------------------------
;  The MEND command requires some cleanup to be performed.
;  The length of the header is calculated and added to the offsets in
;  the header.  Then the menu_buf is appended to the output_buf.
;----------------------------------------------------------------------
TKN_12:
		CMP	AL,_MEND
		JNE	TKN_12AA		;If not MEND, move on
;----------------------------------------------------------------------
;  Close out the option block (if there was one).
;----------------------------------------------------------------------
		MOV	AL,_SEND		;Write send token
		CALL	PUT_MENUBUF
;----------------------------------------------------------------------
;  Flush the buffers.
;----------------------------------------------------------------------
		PUSH	SI			;Save register
		MOV	SI,MENU_HEAD		;Address of start of menu
						; in the output file
		LODSW				;Number of entries in menu

		MOV	CX,AX			;#Words = # entries * 3
		SHL	CX,1			; *2
		ADD	CX,AX			; +1 is same as *3

		JCXZ	APPEND_TOKENS		;NULL menu bailout
		PUSH	CX			;Save number words to update
		MOV	AX,CX			;Length of offset
		INC	AX			; plus one
		SHL	AX,1			; times two

		MOV	CX,MENU_HEAD		;Offset of start of menu
		SUB	CX,OFFSET OUTPUT_BUF	; from start of buf
		ADD	AX,CX			; plus length of header
		POP	CX
UPDATE_POINTERS:
		ADD	WORD PTR [SI],AX	; makes pointers correct
		INC	SI			;Skip to next pointer
		INC	SI
		LOOP	UPDATE_POINTERS

;----------------------------------------------------------------------
;  Append the tokenized menu.
;----------------------------------------------------------------------
APPEND_TOKENS:
		MOV	CX,BX			;End of menu buf
		MOV	SI,OFFSET MENU_BUF	;start of menu buf
		SUB	CX,SI			;# bytes to transfer
		REP	MOVSB			;do it
		POP	SI			;restore register

;----------------------------------------------------------------------
;  Reset the flags.
;----------------------------------------------------------------------
		MOV	MENU_FLAG,0
		MOV	OPTION_FLAG,0
		JMP	FIND_WORD		;get next command

;----------------------------------------------------------------------
;  Deal with commands other than PROGRAM, MENU, and OPTION
;----------------------------------------------------------------------
TKN_12AA:
		CALL	PUT_MENUBUF		;Put the token in the file
		CMP	AL,_EXECUTE		;If not execute
		JNE	TKN_13			; move on

;----------------------------------------------------------------------
;  EXECUTE command references another menu.  Let the SEARCH_MENU_TABLE
;  routine satisfy the reference, or leave a "wanted" message.
;----------------------------------------------------------------------
		CALL	NEXT_WORD		;Point to named menu
		CMP	AL,CR			;End of line?
		JNE	TKN_12A
		JMP	TKN_8A			;(out of range jump)
TKN_12A:
		CALL	MAKEZ			;Put name in buffer
		MOV	AX,0FFFFH		;= want address
		CALL	SEARCH_MENU_TABLE	;Try and resolve
		JMP	FIND_WORD

;----------------------------------------------------------------------
;  Separate out commands that take arguments.
;----------------------------------------------------------------------
TKN_13:
		CMP	AL,_ASK			;Ask takes string
		JE	TKN_17
		CMP	AL,_TYPE		;So does type
		JE	TKN_17
		JMP	FIND_WORD		;Token already in, so go

;----------------------------------------------------------------------
;  These commads require the quoted string following them to be included
;  as an ASCIIZ string following the command byte.
;----------------------------------------------------------------------
TKN_17:
		CALL	NEXT_WORD		;Point to string
		CALL	TKN_STRING		;Copy it
		JMP	FIND_WORD

TOKENIZE	ENDP

;======================================================================
;  AX points to an ASCIIZ string.  Look up that string in table pointed
;  to by SI to see if we can find a match.
;----------------------------------------------------------------------
TABLE_LOOKUP	PROC	NEAR

		PUSH	DI			;Save registers
		PUSH	CX
		PUSH	DX

		XOR	CL,CL			;Command counter
CL_0:
		CMP	BYTE PTR [SI],0		;End of table?
		JNZ	CL_2			; jump if not
		MOV	CL,0FFH			;Signal error
CL_1:
		MOV	AL,CL			;Return cmd number
		POP	DX			;Restore registers
		POP	CX
		POP	DI
		RET
CL_2:
		MOV	DI,AX			;Pointer to unknown command
		CALL	STR_CMP			;NC if matched
		JNC	CL_1
		INC	CL			;Point to next
		JMP	CL_0			;Test for table end

TABLE_LOOKUP	ENDP

;======================================================================
;  Compare strings at DI,SI where SI is a table.
;----------------------------------------------------------------------
STR_CMP		PROC	NEAR
STR_1:
		MOV	DL,[DI]			;Get char from string
		INC	DI			;Point to next
		MOV	DH,[SI]			;Get char from table
		INC	SI			;Point to next
		CMP	DH,DL			;If equal
		JE	STR_3			; jump
		DEC	SI			;Backup in table
STR_2:
		MOV	DH,[SI]			;Examine char in table
		INC	SI			;Goto next char
		OR	DH,DH			;Is it end of entry?
		JNZ	STR_2			; no, continue scanning
		STC				; return with failure
		RET
STR_3:
		OR	DX,DX			;If both not 0
		JNZ	STR_1			; continue compare
		CLC				; else, they match
		RET

STR_CMP		ENDP

;======================================================================
;  This procedure prints an error message and indicates the source line
;  number on which it occured.
;----------------------------------------------------------------------
ERROR_EXIT	PROC	NEAR

		MOV	AH,9			;Print the error message
		INT	21H			; Thru DOS

		MOV	DI,OFFSET LINE_NUM_BUF	;Put line number here
		MOV	AX,SOURCE_LINE		;Contains line number
		MOV	BX,10			;Base 10 numbers
LINE_LOOP:
		XOR	DX,DX			;Divide DX:AX by BX
		DIV	BX
		ADD	DL,30H			;Make number into ASCII
		MOV	[DI],DL			;Save it
		DEC	DI			;Move toward more significant
		OR	AX,AX			;If remainder not 0
		JNZ	LINE_LOOP		; continue

		MOV	DX,OFFSET LINE_MSG	;Write message
		MOV	AH,9			;Display string fn
		INT	21H			; Thru DOS

		CALL	CLOSE_FILES		;Close files and terminate
		MOV	AX,4CFFH		; with error=255
		INT	21H			; Thru DOS

ERROR_EXIT	ENDP

;======================================================================
;  Position SI to the begining of the next word.
;----------------------------------------------------------------------
NEXT_WORD	PROC	NEAR

		CALL	IS_WHITE		;Is current char white?
		JNC	NW_1			; yes, jump
		CALL	WHITE			; no, find first white
NW_1:
		CALL	NON_WHITE		;Scan for first non-white
		RET

NEXT_WORD	ENDP

;======================================================================
;  Enter with SI pointing to string.  Position so SI points at first
;  delimiter character AFTER the present char.  Return char in AL.
;  AL changed, SI moved by file routines.
;----------------------------------------------------------------------
WHITE		PROC	NEAR

		MOV	AL,[SI]			;Check current char
		CMP	AL,CR			; for EOL
		JE	W_RET			; and leave
W_LOOP:
		CALL	GET_CHAR		;Get the next char
		CMP	AL,CR			;If EOL
		JE	W_RET			; return
		CALL	IS_WHITE		;Returns NC if white
		JC	W_LOOP
W_RET:
		RET
WHITE		ENDP

;======================================================================
;  Enter with SI pointing to string.  Position so SI points at first
;  non-delimiter character AFTER the present char.  Return char in AL.
;  AL changed, SI moved by file routines.
;----------------------------------------------------------------------
NON_WHITE	PROC	NEAR

		MOV	AL,[SI]			;Check current char
		CMP	AL,CR			; for EOL
		JE	NW_RET			; and leave
NW_LOOP:
		CALL	GET_CHAR		;Get the next char
		CMP	AL,CR			;If EOL
		JE	NW_RET			; return
		CALL	IS_WHITE		;Returns NC if white
		JNC	NW_LOOP
NW_RET:
		RET
NON_WHITE	ENDP

;======================================================================
;  Examine Char at SI and return CY if non-white, NC if delimiter
;  Only flags changed.
;----------------------------------------------------------------------
DELIMS		DB	" ,:",LF,TAB		;White chars

IS_WHITE	PROC	NEAR

		PUSH	AX			;Save registers
		PUSH	CX
		PUSH	DI

		MOV	AL,[SI]			;Examine current char
		MOV	CX,5			;Number delims to compare
		MOV	DI,OFFSET DELIMS	;Here they are
		REPNE	SCASB			;Compare them
		CLC				;NC if delimiter
		JZ	IW_1			;ZR indicates match found
		STC				; else CY
IW_1:
		POP	DI			;Restore registers
		POP	CX
		POP	AX
		RET

IS_WHITE	ENDP

;======================================================================
;  Make the character in AL UPPER case.
;----------------------------------------------------------------------
MAKE_UC		PROC	NEAR

		CMP	AL,'a'			;If between a and z
		JB	UC_1
		CMP	AL,'z'
		JA	UC_1
		SUB	AL,20H			;Make upper case
UC_1:
		RET
MAKE_UC		ENDP

;======================================================================
;  Position SI to the next char after a CR.  Start search with current
;  char.
;----------------------------------------------------------------------
NEXT_LINE	PROC	NEAR

		MOV	AL,[SI]			;Examine current char
NL_1:
		CMP	AL,CR			;Is it CR?
		JE	NL_2			; yes, jump
		CALL	GET_CHAR		; no, get next char
		JMP	NL_1			;  and try again
NL_2:
		CALL	GET_CHAR		;Go to first char after CR
		RET

NEXT_LINE	ENDP

;======================================================================
;	This proc helps resolve references to other menus made with
;  EXECUTE commands.  If entered with AX=FFFF, the calling procedure has
;  a reference it needs to satisfy.  If an address has been entered in
;  the table for that name, the address is returned and the reference is
;  satisfied.  If not, a "IOU" is inserted in the table.
;	If entered with AX != FFFFh, the calling procedure is supplying the
;  starting address of the MENU named at PATH_BUF, and asking that these
;  be entered into the table to satisfy a reference.  If the name is found
;  in the table, left in a previous bookmark, the reference is satisfied
;  and the entry is marked "USED". Any further use of that name generates
;  an error.
;	For a forward reference, the structure is:
;		ASCIIZ string
;		WORD - Address of the start of the menu that
;			contains the reference (menu_head)
;		WORD - Offset from the end of menu header that
;			is the destination for the fix-up
;	For a POST:
;		ASCIIZ string
;		WORD - Address in output file of menu
;		WORD - 0FFFFh
;  Possibilities:
;	1) Post a MENU not previously requested
;	2) Post a MENU previously requested
;	3) Request a MENU previously posted
;	4) Ask for a MENU not previously posted
;----------------------------------------------------------------------
SEARCH_MENU_TABLE	PROC	NEAR

		PUSH	SI			;Save used registers
		PUSH	DI
		PUSH	DX
		PUSH	CX

;----------------------------------------------------------------------
;  AX=FFFF if request.  AX != FFFF, then post the MENU address.
;----------------------------------------------------------------------
		CMP	AX,0FFFFH		;Switch = FFFF if request
		JE	WANT_ADR		; to satisfy reference

;----------------------------------------------------------------------
;  AX contains the output file offset of a menu to post in this table.
;  If the name is in the table, it was referenced earlier and we can go
;  back and fix it up.  If the name is NOT in the table, post it.
;----------------------------------------------------------------------
		CALL	MENU_LOOK		;Changes SI
		JNC	SMT_7			;Match was found if NC

;----------------------------------------------------------------------
;  1) Post a menu not previously requested. No match found.  Create a
;  new entry for this menu.  SI points to end of table.
;  Copy the name from the buffer to the menu table.
;----------------------------------------------------------------------
		INC	NEW_REF			;Add a new reference
		MOV	CX,0FFFFH		;POST code
SMT_1:
		MOV	DI,OFFSET PATH_BUF	;Name of MENU is here
;----------------------------------------------------------------------
;  Copy menu name to menu_name_table
;----------------------------------------------------------------------
SMT_5:
		MOV	DL,[DI]			;Get char in DL
		INC	DI			;Point to next
		MOV	[SI],DL			;Save this char in table
		INC	SI			;next destination
		OR	DL,DL			;Was that last byte?
		JNZ	SMT_5			; no, get more

;----------------------------------------------------------------------
;  Make AX into offset from buffer start.  Save in menu table.
;  CX contains either offset from menu_buf of reference or FFFF (POST).
;----------------------------------------------------------------------
		MOV	WORD PTR [SI],AX	;Menu at this address
		MOV	WORD PTR [SI][2],CX
		JMP	SHORT SMT_EXIT		;clean up

;----------------------------------------------------------------------
;  2) Post a MENU previously requested.  SI points past the ASCIIZ name
;  in the table to the location of the forward reference.
;----------------------------------------------------------------------
SMT_7:
		INC	OLD_REF			;Add an old reference
		MOV	DX,WORD PTR [SI][2]	;2nd word
		CMP	DX,0FFFFH		; if POST, two menus have
		JE	SMT_7B			; the same name (error)
		CMP	DX,0FFFEH		;Already referenced
		JNE	SMT_8			; is also an error
SMT_7B:
		MOV	DX,OFFSET REF_MSG	;error
		JMP	ERROR_EXIT
SMT_8:
;----------------------------------------------------------------------
;  SI points to address of menu as offset from start of buffer.
;  SI+2 points to additional offset from end of header.
;  Address of reference is [si] + 2 + 3 * 2 * [[si]] + [si+2] !
;----------------------------------------------------------------------
		MOV	DI,WORD PTR [SI]	;Offset into output_buf
		ADD	DI,OFFSET OUTPUT_BUF	;Absolute memory location
		MOV	CX,WORD PTR [DI]	;Number of entries in header
		SHL	CX,1			; 2 bytes per word
		ADD	DI,CX
		INC	CX			; 2 for first word
		SHL	CX,1
		ADD	DI,CX

		ADD	DI,WORD PTR [SI][2]
		MOV	[DI],AX			; reference satisfied
		MOV	WORD PTR [SI][2],0FFFEH	;Mark this entry USED
		JMP	SHORT SMT_EXIT		;Clean up

;----------------------------------------------------------------------
;  Try and satisfy a reference.
;----------------------------------------------------------------------
WANT_ADR:
		CALL	MENU_LOOK		;CY if no match
		JC	SMT_9

;----------------------------------------------------------------------
;  3) Request a MENU previously posted.  Entry name was in table.
;----------------------------------------------------------------------
		DEC	NEW_REF
		MOV	DX,WORD PTR [SI][2]	;Second word
		CMP	DX,0FFFFH		; should contain POST code
		JNE	SMT_7B			;if not, ERROR!

		MOV	AX,[SI]			;Get address of menu
		CALL	PUT_MENUBUF		;Put lower byte
		MOV	AL,AH
		CALL	PUT_MENUBUF		;Put upper byte

		MOV	WORD PTR [SI][2],0FFFEH	;Mark entry used
		JMP	SHORT SMT_EXIT

;----------------------------------------------------------------------
;  4) Ask for a MENU not previously posted.  Put an IOU in the table.
;----------------------------------------------------------------------
SMT_9:
		DEC	OLD_REF
		MOV	AX,MENU_HEAD		;First entry is offset of
		SUB	AX,OFFSET OUTPUT_BUF	; requesting menu

		MOV	CX,BX			;Second entry is offset past
		SUB	CX,OFFSET MENU_BUF	; the menu header

		ADD	BX,2			;Leave room for address
		JMP	SMT_1			;Go create table entry
SMT_EXIT:
		POP	CX			;Restore registers
		POP	DX
		POP	DI
		POP	SI
		RET

SEARCH_MENU_TABLE	ENDP

;======================================================================
;  Look for a name in the menu.  If carry is set, no match was found
;  and SI points to the end of the table.  If carry is clear, match was
;  found and SI points to address word after entry.
;  SI is changed.
;----------------------------------------------------------------------
MENU_LOOK	PROC	NEAR

		PUSH	DI			;Save registers
		PUSH	DX

		MOV	SI,OFFSET MENU_NAME_TBL	;Known names
ML_1:
		CMP	BYTE PTR [SI],0		;If 0, end of table
		JNE	ML_3			; else compare entry
		STC				;signal error
ML_2:
		POP	DX			;Restore registers
		POP	DI
		RET
ML_3:
		MOV	DI,OFFSET PATH_BUF	;Name to find
		CALL	STR_CMP			;CY if no match
		JNC	ML_2			;Return result
		ADD	SI,4			;Skip past addresses
		JMP	ML_1			;Check next table entry

MENU_LOOK	ENDP

;======================================================================
;  Interpret the contents of the quoted string and write to output buffer.
;  Entered with SI pointing to the beginning quote.  An illegal character
;  or combination produces an error and terminates processing.
;----------------------------------------------------------------------
TKN_STRING	PROC	NEAR

		CMP	BYTE PTR [SI],QUOTE	;Must point to quoted string
		JNE	TS_ERR			; or syntax error.

		PUSH	DI			;Save used register
TS_1:
		MOV	SHIFT_FLAGS,0		;Clear shift flags
TS_1AA:
		CALL	GET_CHAR		;Get next char
		CMP	AL,CR			;If not CR
		JNE	TS_QUOTE		; go to next test
TS_ERR:
		JMP	SC_ERR			;Report a syntax error
TS_QUOTE:
		CMP	AL,QUOTE		;If quote
		JNE	TS_1A
TS_EXIT:
		XOR	AL,AL			; make string asciiz
		CALL	PUT_MENUBUF		; and write to buffer

		CALL	NEXT_LINE		;Position to next line
		POP	DI			;Restore register
		RET				; and leave
TS_1A:
		CMP	AL,"{"			;Key name follows
		JE	SPEC_CHAR		;Go snif it out

		CMP	SHIFT_FLAGS,0		;If any shift keys on
		JNE	DO_XLAT			; do translation
		XOR	AH,AH			;Else, ASCII output of AL

;----------------------------------------------------------------------
;  If AH=0, output the code in AL; If AH != 0, output AH, then AL.
;----------------------------------------------------------------------
OUTPUT_CODE:
		OR	AH,AH			;If AH=0
		JZ	OC_1			; output AL only
		XCHG	AH,AL			;Switch
		CALL	PUT_MENUBUF		;Write the high byte
		XCHG	AH,AL			;restore AL
OC_1:
		CALL	PUT_MENUBUF		;Put AL in buffer
		JMP	TS_1			;Get another character

;----------------------------------------------------------------------
;  These keys may be valid with CTRL and ALT, but not SHIFT
;----------------------------------------------------------------------
DO_XLAT:
		CMP	SHIFT_FLAGS,_SHIFT	;Is SHIFT on?
		JNE	TS_1B
DEAD_KEY_ERROR:
		MOV	DX,OFFSET DEAD_KEY_MSG	;Invalid key combo
		JMP	ERROR_EXIT
TS_1B:
;----------------------------------------------------------------------
;  See if the key is in the table.
;----------------------------------------------------------------------
		CALL	MAKE_UC			;Make upper case

		MOV	AH,AL			;Save original char
		MOV	DI,OFFSET KEY_TBL_1	;Source for compare
		MOV	CX,DI			;Save start of table
TS_2:
		MOV	AL,[DI]			;Get char from table
		INC	DI			;Point to next
		OR	AL,AL			;If 0, AL was illegal char
		JE	DEAD_KEY_ERROR
		CMP	AL,AH			;Do we have a match?
		JNE	TS_2			;No, try again
		DEC	DI			;Backup pointer
		MOV	AX,DI			;Have a match if here
		SUB	AX,CX			;Offset into table

;----------------------------------------------------------------------
; Found a match.  Tediously calculate output byte.
;----------------------------------------------------------------------
		CMP	AL,25			;If A-Z
		JBE	IS_ALPHA		; process as alpha keys
		SUB	AL,26			;Remove alpha bias

		CMP	SHIFT_FLAGS,_CTRL	;Go perform CTRL combos
		JE	TS_4
						;These are ALT combos
		CMP	AL,11
		JA	DEAD_KEY_ERROR		;Too high
		ADD	AX,0FE78H		;Output 2 bytes
		JMP	OUTPUT_CODE
TS_4:						;CTRL combos
		SHL	AL,1			;multiply by 2
		MOV	DI,OFFSET KEY_TBL_2
		ADD	DI,AX			;Find word in table
		MOV	AX,[DI]			;Load into AX
		OR	AX,AX			;If zero
		JZ	DEAD_KEY_ERROR		; this combo not allowed
		JMP	OUTPUT_CODE		; else write it

;----------------------------------------------------------------------
;  CTRL/ALT alphabet combinations.
;----------------------------------------------------------------------
IS_ALPHA:
		CMP	SHIFT_FLAGS,_ALT
		JE	TS_5
		INC	AL			;ALT is simple, add 1
		JMP	OUTPUT_CODE
TS_5:
		MOV	DI,OFFSET KEY_TBL_3	;CTRL keys combos
		ADD	DI,AX			;Add offset to
		MOV	AL,[DI]			; get char code
		MOV	AH,0FEH			;Signal extended ASCII
		JMP	OUTPUT_CODE		;Send it to buffer

;----------------------------------------------------------------------
;  Here the {strings} are translated to their equivalent keystrokes.
;  Move the key name into the ASCIIZ buffer.
;----------------------------------------------------------------------
SPEC_CHAR:
		MOV	DI,OFFSET PATH_BUF
SC_1:
		CALL	GET_CHAR		;Get char inside brace

		CMP	AL,'{'			;If doubled, use {
		JNE	SC_2			;Jump for other chars
		CMP	DI,OFFSET PATH_BUF	;If = no chars have been
		JE	OC_1			; processed yet. {{
SC_ERR:
		MOV	DX,OFFSET SYNTAX_MSG
		JMP	ERROR_EXIT
SC_2:
		CMP	AL,QUOTE		;If char is quote
		JE	SC_ERR

		CMP	AL,'}'			;Close brace?
		JE	SC_3			; go search table
		CALL	MAKE_UC			;Make Upper case
		STOSB				;Put char in buffer
		JMP	SC_1			;Continue to copy key name
SC_3:
		XOR	AL,AL			;Make asciiz
		STOSB
		PUSH	SI			;Save register
		MOV	SI,OFFSET KEY_NAME_TBL	;Search this table
		MOV	AX,OFFSET PATH_BUF	; for this entry
		CALL	TABLE_LOOKUP
		POP	SI			;Restore register

;----------------------------------------------------------------------
;  Return # of entry in table or FFh if not found.
;----------------------------------------------------------------------
		CMP	AL,0FFH
		JE	SC_ERR

		OR	AL,AL			;0 = Turn SHIFT on
		JNZ	SC_4
		MOV	SHIFT_FLAGS,_SHIFT
		JMP	TS_1AA
SC_4:
		DEC	AL			;0 = Turn CTRL on
		JNZ	SC_5
		MOV	SHIFT_FLAGS,_CTRL
		JMP	TS_1AA
SC_5:
		DEC	AL			;0 = Turn ALT on
		JNZ	SC_6
		MOV	SHIFT_FLAGS,_ALT
		JMP	TS_1AA

;----------------------------------------------------------------------
;  Test for the Function keys (40 combinations).
;----------------------------------------------------------------------
SC_6:
		DEC	AL			;Adjust key number
		CMP	AL,9			;Keys 0-9
		JA	SC_10			;Can't be function key
		ADD	AL,3BH			;Key code
		MOV	AH,SHIFT_FLAGS		;Test for shift states
		CMP	AH,_SHIFT		;For shift
		JNE	SC_7
		ADD	AL,19H			;Add 19h
SC_7:
		CMP	AH,_CTRL		;For CTRL
		JNE	SC_8
		ADD	AL,23H			;Add 23h
SC_8:
		CMP	AH,_ALT			;For ALT
		JNE	SC_9
		ADD	AL,2DH			;Add 2dh
SC_9:
		MOV	AH,0FEH			;Say this is extended ascii
		JMP	OUTPUT_CODE		;Dump the bytes

;----------------------------------------------------------------------
;  ALT is not allowed for these keys.
;----------------------------------------------------------------------
SC_10:
		CMP	SHIFT_FLAGS,_ALT	;If Alt's not on
		JNE	SC_10B			; jump
SC_10A:
		JMP	DEAD_KEY_ERROR		; else, error
SC_10B:
		SUB	AL,10			;Eliminate BIAS
		JNZ	SC_11
		MOV	AL,01BH			;ESC key
		JMP	OC_1
SC_11:
		DEC	AL			;TAB key
		JNZ	SC_13
		CMP	SHIFT_FLAGS,0		;Any shift keys on?
		JE	SC_12			; no, jump
		CMP	SHIFT_FLAGS,_SHIFT	;SHIFT only is allowed
		JNE	SC_10A			; else error
		MOV	AX,0FE0FH		;SHIFT-TAB
		JMP	OUTPUT_CODE		;to output
SC_12:
		MOV	AL,9			;Normal TAB
SC_12A:
		JMP	OC_1

;----------------------------------------------------------------------
;  These keys are the same alone or with SHIFT, but CTRL is different.
;----------------------------------------------------------------------
SC_13:
		DEC	AL			;Remove bias
		XOR	AH,AH			;Zero AH
		MOV	DI,OFFSET KEY_TBL_4	;Table of SHIFT/CTRL values
		SHL	AX,1			;Make into offset
		ADD	DI,AX			; from start of table
		MOV	DH,SHIFT_FLAGS		;If CTRL
		CMP	DH,_CTRL
		JNE	SC_14
		INC	DI			; move one byte further
SC_14:
		MOV	DL,[DI]			;Get char from table
		OR	DL,DL			; =0 if illegal
		JZ	SC_10A
		XCHG	AL,DL			;Put offset in DL
		CMP	DL,2			;What key?
		JE	SC_12A			;If BS, all ascii
		JA	SC_15			;above, all extended
		CMP	DH,_CTRL		;CTRL-ENTER is special
		JNE	SC_12A
SC_15:
		MOV	AH,0FEH			;Add extended code
		JMP	OUTPUT_CODE

TKN_STRING	ENDP

;======================================================================
;  Read from the BDF file into a buffer.  If an EOF is found, perform
;  the final cleanup and return to the main procedure.
; (must also keep track of file pointer and signal when EOF)
;----------------------------------------------------------------------
REFRESH_BUFFER	PROC	NEAR

		PUSH	BX
		PUSH	CX
		PUSH	DX

		MOV	AH,42H			;Move file pointer
		XOR	AL,AL			; offset from begining
		MOV	BX,INPUT_HNDL		;File handle
		XOR	CX,CX			;Offset CX:DX
		MOV	DX,INPUT_HNDL_PTR
		INT	21H			;Thru DOS
		JC	READ_ERR

;----------------------------------------------------------------------
;  Fill buffer.
;----------------------------------------------------------------------
		MOV	AH,3FH			;Read from handle fn
		MOV	BX,INPUT_HNDL
		MOV	CX,INPUT_BUF_LEN	;Number bytes to read
		MOV	SI,OFFSET INPUT_BUF
		MOV	DX,SI			;DS:DX destination

		CMP	[INPUT_HNDL_PTR],0	;If start of file
		JNE	NOT_FIRST_READ
		MOV	BYTE PTR [SI],20H	;Make a current char
		DEC	CX			;Read one less byte
		INC	DX			;New destination
NOT_FIRST_READ:
		INT	21H			;Thru DOS
		JNC	READ_OK
READ_ERR:
		MOV	DX,OFFSET READ_MSG
		JMP	ERROR_EXIT
READ_OK:
		ADD	INPUT_HNDL_PTR,AX	;Add bytes read
		SUB	DX,SI			;Calculate ending address
		ADD	AX,DX			; of our buffer
		MOV	INPUT_BUF_END,AX	; and save it

		POP	DX			;Restore registers
		POP	CX
		POP	BX
		RET

REFRESH_BUFFER	ENDP

;======================================================================
;  Copy the word at SI into a buffer and make it asciiz
;----------------------------------------------------------------------  
MAKEZ		PROC	NEAR

		PUSH	DI
		MOV	DI,OFFSET PATH_BUF	;Destination
		PUSH	DI
MZ_1:
		CALL	IS_WHITE		;Examine char at SI
		JNC	MZ_2

		MOV	AL,[SI]			;Get the char
		CMP	AL,CR			;Is it CR?
		JE	MZ_2			; yes, terminate string
		CALL	MAKE_UC			; else, change to lower case
		STOSB				;  save at DI
		CALL	GET_CHAR		;Get next char
		JMP	MZ_1
MZ_2:
		XOR	AL,AL			;Make ASCIIZ
		STOSB

		POP	AX			;Return buffer address
		POP	DI			;Restore pointer
		RET

MAKEZ		ENDP

;======================================================================
;  Get a char from the input buffer.  If past the end of the buffer,
;  refresh the buffer.  Check for EOF (SI = INPUT_BUF_END != BUF_LEN)
;  If comments are detected, they are weeded out.
;----------------------------------------------------------------------
COMMENT_FLAG	DB	0			;=1 if inside comment

GET_CHAR	PROC	NEAR
;----------------------------------------------------------------------
;  Check buffer for pointer past end.
;----------------------------------------------------------------------
		PUSH	AX			;Save register
		INC	SI			;Advance pointer
		MOV	AX,SI			;Current location
		SUB	AX,OFFSET INPUT_BUF	; minus start
		CMP	AX,INPUT_BUF_END	; longer than allowed
		POP	AX			;(restore pointer)
		JB	GC_1			; no need to refresh
		CALL	REFRESH_BUFFER		;Attempt to load buffer

;----------------------------------------------------------------------
;  AX contains the number of chars read.  If AX=0, unexpected EOF.
;----------------------------------------------------------------------
		OR	AX,AX			;# chars read
		JNZ	GC_1			;jump if not 0
		MOV	DX,OFFSET EOF_MSG
		JMP	ERROR_EXIT

;----------------------------------------------------------------------
;  check for, and eliminate comments
;----------------------------------------------------------------------
GC_1:
		MOV	AL,[SI]			;Get new char
		CMP	AL,CR			;If new line
		JNE	GC_3
		MOV	COMMENT_FLAG,0		; reset comment
		INC	SOURCE_LINE		; next line
GC_2:
		CMP	COMMENT_FLAG,0		;If inside comment
		JNE	GET_CHAR		; read until CR
		RET
GC_3:
		CMP	AL,';'			;If this isn't a comment
		JNE	GC_2			; then continue
		INC	COMMENT_FLAG		;else read until CR
		JMP	GET_CHAR

GET_CHAR	ENDP

;======================================================================
PUT_MENUBUF	PROC	NEAR

		MOV	[BX],AL			;Write byte to [bx]
		INC	BX			;Move pointer
		RET

PUT_MENUBUF	ENDP

;======================================================================
;  Buffer Allocation area
;----------------------------------------------------------------------
PC		=	$
LAST_BYTE	=	PC

PATH_BUF	=	PC			;DB 64 DUP (?)
PC		=	PC + 64

INPUT_BUF	=	PC			;DB INPUT_BUF_LEN DUP(?)
PC		=	PC + INPUT_BUF_LEN

OUTPUT_BUF	=	PC			;DB OUTPUT_BUF_LEN DUP(?)
PC		=	PC + OUTPUT_BUF_LEN

MENU_BUF	=	PC			;DB MENU_BUF_LEN DUP(?)
PC		=	PC + MENU_BUF_LEN

MENU_NAME_TBL	=	PC			;DB MENU_TBL_ELN DUP(?)
PC		=	PC + MENU_TBL_LEN

;----------------------------------------------------------------------
CSEG	ENDS
	END	ENTPT
