home *** CD-ROM | disk | FTP | other *** search
- BSLP.P
-
- '------------------------------------------------------
- '-(c) Bendorf Associates, 1984-85 -
- '------------------------------------------------------
- '- Program:BSLP (BASIC STRUCTURED LANGUAGE PREPROCESSOR)
- '- System :PPE
- '- Module :TOOLS
- '- Task :COMPILE 'SSS' CODE INTO STANDARD BASIC CODE.
- '- Created:10.1.82
- '- By :D. L. BENDORF
- '- Version:PUBLIC DOMAIN
- '- Notes :THIS PROGRAM IS NOT FOR RESALE.
- '- History:
- '- BSLP translates source text written in 'SSS' structure language to
- '- standard BASIC code. BSLP is a BASIC language version of the PPE
- '- structure translater. It is slow but very usable, and has served well
- '- as a tool for prototype extensions to the structure language. BSLP is
- '- written in BSLP structure language and should be a useful learning
- '- tool.
- '- Invocation:
- '- Entering 'BSLP' at the DOS prompt will envoke the compiled version
- '- (.EXE) of BSLP. The (.BAS) version will have to be run using the
- '- interpreter by entering 'BASICA BSLP' at the DOS prompt. BSLP will
- '- then prompt for the input file name and the output file name. The
- '- default for the input file extension is '.P', and the default for the
- '- output file is 'input-file.BAS'. The slash (/) following the input
- '- file name will cause all non-referenced line numbers to be deleted
- '- from the output file (.BAS). This allows a smaller compiled (.EXE)
- '- program.
- '- Hints and Restrictions:
- '- 'SSS' keywords are not case or position sensitive, and they must
- '- (except for spaces and tabs) be the first words on a line. Do NOT use
- '- comments on the same line with keywords. The vertical bar (|) may be
- '- use to provide line continuation. Continued lines will be appended,
- '- separating them with a colon (:).
- '- 'SSS' Keywords:
- '- PROG / PEND
- '- PROC <label> / ENDP
- '- REPEAT / UNTIL <condition>
- '- LOOP [<when/unless> <condition>] / ENDL [<when/unless> <condition>]
- '- WHEN <condition> / ELSE [<when/unless> <condition>] / ENDW
- '- UNLESS <condition> / ENDU
- '- SWITCH <left operand> / CASE <right operand> / BREAK / ENDC
- '------------------------------------------------------
- '- ** Data Division -
- '------------------------------------------------------
- DATA proc...
- DATA prog...
- DATA when...
- DATA unless.
- DATA repeat.
- DATA loop...
- DATA switch.
- DATA case...
- DATA else...
- DATA break..
- DATA endp...
- DATA pend...
- DATA endw...
- DATA endu...
- DATA until..
- DATA endl...
- DATA endc...
- PROC.% = 1
- PROG.% = 2
- WHEN.% = 3
- UNLESS.% = 4
- REPEAT.% = 5
- LOOP.% = 6
- SWITCH.% = 7
- CASE.% = 8
- ELSE.% = 9
- BREAK.% = 10
- ENDP.% = 11
- PEND.% = 12
- ENDW.% = 13
- ENDU.% = 14
- UNTIL.% = 15
- ENDL.% = 16
- ENDC.% = 17
- DATA 11,12,13,14,15,16,17,17,13,17
- DOT$ = "."
- DOTS$ = "...."
- SKIP$ = " "
- SKIP1$ = " '"
- OEXT$ = ".BAS"
- IEXT$ = ".P"
- EEXT$ = ".E"
- INCL$ = ".INC"
- TM$ = " ,="
- T.FILE$ = "BSLP.$$$"
- T.FILE% = 1
- E.FILE% = 2
- I.FILE% = 3
- O.FILE% = 3
- ERRORS% = 0
- KERR% = 1
- LEVELS% = 0
- PUSH% = 0
- NUM% = 0
- STACK.% = 0
- NKEY% = 17
- INCS% = 1
- INC% = 0
- FILE% = 2
- BASIC$ = "restore.resume.return.goto.gosub"
- DIM CLOSING%(10) ' For error messages.
- DIM INC$(50) ' Include file stack.
- DIM STACK$(500)
- DIM STACK%(500)
- DIM NUM.%(500)
- DIM KEYWORD.%(99,2)
- DIM XN.%(99)
- DIM LOOPS%(99)
- DIM SWITCH$(10) ' For the left operand of SWITCH.
- DIM KEYWORD$(22) ' For error messages.
- FOR I%=1 TO NKEY%|
- READ BUF$|
- TABLE$=TABLE$+BUF$|
- KEYWORD$(I%)=BUF$|
- NEXT I%
- FOR I%=1 TO 10|
- READ CLOSING%(I%)|
- NEXT I%
- '------------------------------------------------------
- '- ** Procedure Division -
- '------------------------------------------------------
- prog BSLP
- PRINT "BSLP V1.1B (C) BENDORF ASSOCIATES, 1984-85"
- PRINT|
- GoSub FILENAMES
- when GOOD%
- GoSub BEGIN
- else when I.FILE$<>""
- PRINT"CANNOT OPEN ";I.FILE$
- endw
- pend
- proc BEGIN
- GoSub PASS_1
- '
- ' Kill the error file if no errors in PASS_1.
- ' Kill the temp file after PASS_2.
- ' Kill the output file if errors in PASS_2.
- '
- CLOSE
- when ERRORS%=0
- KILL E.FILE$|
- GoSub PASS_2|
- CLOSE|
- KILL T.FILE$
- else
- KILL T.FILE$|
- PRINT E.FILE$;" PRODUCED WITH ";STR$(ERRORS%);" ERROR(S)."
- END
- endw
- when ERRORS%>0
- KILL O.FILE$|
- PRINT O.FILE$;" ABORTED WITH ";STR$(ERRORS%);" ERROR(S)."
- else
- PRINT"<";O.FILE$;"> DONE!"
- endw
- endp
- proc PASS_1
- '
- ' This is the first phase of processing.
- ' All included file will be processed here.
- ' The error file is written during this pass.
- '
- Open"O",T.FILE%,T.FILE$|
- Open"O",E.FILE%,E.FILE$|
- GoSub PUSH|
- INC$(INCS%)=I.FILE$
- loop
- INC%=INC%+1|
- FILE%=FILE%+1|
- FILE$=INC$(INC%)|
- Open"I",FILE%,FILE$
- loop
- GoSub INPUT-SOURCE|
- GoSub POP_ERRORS
- until FILE%=2
- until INC%=INCS%
- endp
- proc INPUT-SOURCE
- '
- ' Read the input file and look for SLP keywords.
- ' Look for include file operators(+-).
- ' Write error file just in case there is a PASS_1 error.
- '
- loop
- LINE INPUT #FILE%,BUF$
- when LEN(BUF$)>2
- XLINE$=BUF$:GoSub STRIP
- unless LEN(BUF$)=0
- INDEX%=0:GoSub PARSER
- when RIGHT$(TEXT$,1)=":"
- IF(LEN(SBUFF$)>0)THEN GoSub DUMP
- FLAG%=2:LEVEL$=LEFT$(TEXT$,LEN(TEXT$)-1)|
- COMMENT$=SKIP1$+LEVEL$|
- GoSub OUT_LINE
- else
- L$=LEFT$(TEXT$,1):KEYWORD%=0
- unless LEN(TEXT$)<4 OR LEN(TEXT$)>6
- C.$=TEXT$:GoSub _Fold|
- KEYS$=C.$+DOTS$|
- KEYWORD%=INSTR(1,TABLE$,LEFT$(KEYS$,7))|
- KEYWORD%=(KEYWORD%+6)\7
- endu
- when KEYWORD%>0
- IF(LEN(SBUFF$)>0)THEN GoSub DUMP
- GoSub KEYWORDS
- else when L$="-"
- GoSub SUBROUTINE
- else when L$="+"
- IF(LEN(SBUFF$)>0)THEN GoSub DUMP
- GoSub INCLUDES
- else
- GoSub OUT_PUT
- endw
- endw
- endu
- NERR%=NERR%+1|
- PRINT #E.FILE%,STR$(NERR%);SKIP$;XLINE$
- endw
- until EOF(FILE%)
- CLOSE #FILE%|
- FILE%=FILE%-1
- unless SBUFF$=""
- BUF$="":CFLAG%=0:GoSub OUT_PUT
- endu
- endp
- proc STRIP
- '
- ' Strip the leading and trailing spaces,tabs and linefeeds off of
- ' the input buffer.
- ' Look for the continuation operator.
- '
- Z1%=INSTR(BUF$,CHR$(9)):Z2%=INSTR(BUF$,CHR$(10))
- WHILE (Z1% OR Z2%)
- IF Z1% THEN MID$(BUF$,Z1%,1)=" "
- IF Z2% THEN MID$(BUF$,Z2%,1)=" "
- Z1%=INSTR(BUF$,CHR$(9)):Z2%=INSTR(BUF$,CHR$(10))|
- WEND
- Z1%=1|
- WHILE (MID$(BUF$,Z1%,1)=" " AND Z1%<LEN(BUF$))|
- Z1%=Z1%+1|
- WEND
- Z2%=LEN(BUF$)|
- WHILE (MID$(BUF$,Z2%,1)=" " AND Z2%>1)|
- Z2%=Z2%-1|
- WEND
- when Z2%<Z1%
- BUF$=""
- else
- BUF$=MID$(BUF$,Z1%,Z2%-Z1%+1)
- when LEN(BUF$)>0
- IF(LEFT$(BUF$,1)="'" OR LEFT$(BUF$,3)="REM" OR BUF$=STRING$(LEN(BUF$),32))THEN BUF$=""
- endw
- endw
- LN.%=LEN(BUF$):CFLAG%=0
- unless LN.%=0
- CFLAG%=(RIGHT$(BUF$,1)="|")
- IF(CFLAG%)THEN BUF$=LEFT$(BUF$,LN.%-1):LN.%=LEN(BUF$)
- endu
- endp
- proc OUT_PUT
- '
- ' Process lines not beginning with keywords.
- ' If CFLAG% flag is set, append input lines together
- ' and always check the total length first.
- '
- when CFLAG%=0
- when LEN(SBUFF$)>0
- when LEN(SBUFF$+BUF$)<=250
- BUF$=SBUFF$+BUF$:SBUFF$=""
- else
- GoSub DUMP
- endw
- endw
- PBUF$=BUF$:FLAG%=3:GoSub OUT_LINE
- else when LEN(SBUFF$+BUF$)<=250
- SBUFF$=SBUFF$+BUF$+":"
- else
- GoSub DUMP:PBUF$=BUF$:GoSub OUT_LINE
- endw
- BUF$=""
- endp
- proc DUMP
- PBUF$=LEFT$(SBUFF$,LEN(SBUFF$)-1)|
- FLAG%=3:GoSub OUT_LINE:SBUFF$="":CFLAG%=0
- endp
- proc KEYWORDS
- '
- ' Branch to the right keyword processing.
- ' This is one of the few acceptable uses of the `GOTO'.
- '
- KERR%=NERR%+1
- ON KEYWORD% GOTO _PROC,_PROG,_WHEN,_UNLESS,_REPEAT,_REPEAT
- ON KEYWORD%-6 GOTO _SWITCH,_CASE,_ELSE,_BREAK,_ENDP,_PEND,_ENDW
- ON KEYWORD%-13 GOTO _ENDU,_UNTIL,_ENDL,_ENDC
- endp
- proc POP_ERRORS
- '
- ' Resolve all un-closed processes and report errors.
- '
- KER%=KERR%:KWDS%=KEYWORD%:GoSub POP
- while KEYWORD%>0
- GoSub RESOLVE-ERRORS
- wend
- GoSub PUSH:KEYWORD%=KWDS%:KERR%=KER%
- endp
- proc RESOLVE-ERRORS
- IF(KEYWORD%<11)THEN KEYWORD%=CLOSING%(KEYWORD%)
- EBUF$=KEYWORD$(KEYWORD%):GoSub ERRORS
- when KEYWORD%=ENDW.% OR KEYWORD%=ENDU.% OR KEYWORD%=ENDC.%
- IF(KEYWORD%=ENDC.%)THEN GoSub POP
- GoSub POP
- endw
- GoSub POP
- endp
- proc PUSH
- PUSH%=PUSH%+1|
- KEYWORD.%(PUSH%,0)=KEYWORD%|
- KEYWORD.%(PUSH%,1)=KERR%|
- KEYWORD.%(PUSH%,2)=LEVEL%
- endp
- proc POP
- when PUSH%>0
- KEYWORD%=KEYWORD.%(PUSH%,0)|
- KERR%=KEYWORD.%(PUSH%,1)|
- LEVEL%=KEYWORD.%(PUSH%,2)|
- PUSH%=PUSH%-1
- else
- LEVEL%=-1|
- KEYWORD%=-1
- endw
- endp
- proc LEVEL
- LEVELS%=LEVELS%+1:LEVEL%=LEVELS%|
- TK%=LEVEL%:GoSub PUSH
- endp
- proc _PROC
- GoSub POP_ERRORS|
- GoSub PUSH|
- GoSub PARSER
- when LEN(TEXT$)>0
- COMMENT$=SKIP1$+TEXT$:LPROC$=TEXT$|
- FLAG%=2:LEVEL$=TEXT$:GoSub OUT_LINE
- else
- EBUF$="procedure name":GoSub ERRORS
- endw
- endp
- proc _ENDP
- GoSub POP
- WHILE KEYWORD%<>PROC.% AND KEYWORD%>0
- GoSub RESOLVE-ERRORS
- WEND
- when KEYWORD%=PROC.%
- FLAG%=3:PBUF$="RETURN":GoSub OUT_LINE
- else
- EBUF$=KEYWORD$(PROC.%):GoSub ERRORS
- endw
- endp
- proc _PROG
- PROG..%=1
- endp
- proc _PEND
- when PROG..%=1
- FLAG%=3:PBUF$="END":GoSub OUT_LINE
- else
- EBUF$=KEYWORD$(PROG.%):GoSub ERRORS
- endw
- endp
- proc _WHEN
- GoSub LEVEL:GoSub LEVEL|
- FLAG%=1:GoSub OUT_LINE
- endp
- proc _ELSE
- GoSub POP
- when KEYWORD%=WHEN.%
- F.%=LEVEL%:GoSub POP:T.%=LEVEL%:TK%=T.%|
- FLAG%=4:PBUF$="GOTO ":GoSub OUT_LINE|
- XN%=XN%+1:XN.%(XN%)=F.%|
- GoSub PARSER:C.$=TEXT$:GoSub _Fold
- when C.$="when" OR C.$="unless"
- GoSub LEVEL:F.%=LEVEL%|
- FLAG%=ABS(C.$="when"):GoSub OUT_LINE:GoSub POP
- else
- F.%=0
- endw
- KEYWORD%=WHEN.%|
- LEVEL%=T.%:GoSub PUSH|
- LEVEL%=F.%:GoSub PUSH
- else
- GoSub PUSH|
- EBUF$=KEYWORD$(WHEN.%):GoSub ERRORS
- endw
- endp
- proc _ENDW
- GoSub POP
- when KEYWORD%=WHEN.%
- F.%=LEVEL%:GoSub POP:T.%=LEVEL%:GoSub POPOFF
- else
- GoSub PUSH|
- EBUF$=KEYWORD$(WHEN.%):GoSub ERRORS
- endw
- endp
- proc POPOFF
- IF(F.%>0)THEN XN%=XN%+1:XN.%(XN%)=F.%
- IF(T.%>0)THEN XN%=XN%+1:XN.%(XN%)=T.%
- endp
- proc _UNLESS
- GoSub LEVEL:GoSub LEVEL|
- FLAG%=0:GoSub OUT_LINE
- endp
- proc _ENDU
- GoSub POP
- when KEYWORD%=UNLESS.%
- F.%=LEVEL%:GoSub POP:T.%=LEVEL%:GoSub POPOFF
- else
- GoSub PUSH|
- EBUF$=KEYWORD$(UNLESS.%):GoSub ERRORS
- endw
- endp
- proc _REPEAT
- GoSub PARSER:C.$=TEXT$:GoSub _Fold|
- LOOP%=LOOP%+1:GoSub LEVEL|
- XN%=XN%+1:XN.%(XN%)=LEVEL%
- when C.$<>"when" AND C.$<>"unless"
- LOOPS%(LOOP%)=LEVEL%|
- else
- LOOPS%(LOOP%)=LEVEL%*-1|
- GoSub POP:LEVEL%=LEVEL%*-1:GoSub PUSH|
- GoSub LEVEL|
- FLAG%=ABS(C.$="when")|
- GoSub OUT_LINE
- endw
- endp
- proc _UNTIL
- when LOOP%>0
- GoSub POP
- when KEYWORD%=REPEAT.% OR KEYWORD%=LOOP.%
- LOOP%=LOOP%-1:TK%=LOOPS%(LOOP%+1)|
- FLAG%=1:GoSub OUT_LINE
- else
- GoSub PUSH|
- EBUF$=KEYWORD$(REPEAT.%):GoSub ERRORS
- endw
- else
- EBUF$=KEYWORD$(REPEAT.%):GoSub ERRORS
- endw
- endp
- proc _ENDL
- when LOOP%>0
- GoSub POP
- when KEYWORD%=REPEAT.% OR KEYWORD%=LOOP.%
- GoSub PARSER:C.$=TEXT$:GoSub _Fold|
- LOOP%=LOOP%-1
- when LOOPS%(LOOP%+1)>0
- TK%=LOOPS%(LOOP%+1)
- when C.$="when" OR C.$="unless"
- FLAG%=ABS(C.$="when"):GoSub OUT_LINE
- else
- EBUF$=KEYWORD$(WHEN.%):GoSub ERRORS
- endw
- else
- TK%=LOOPS%(LOOP%+1)*-1
- when C.$="when" OR C.$="unless"
- FLAG%=ABS(C.$="when")
- else
- FLAG%=4:PBUF$="GOTO "
- endw
- GoSub OUT_LINE
- F.%=LEVEL%:GoSub POP:T.%=LEVEL%:GoSub POPOFF
- endw
- else
- GoSub PUSH|
- EBUF$=KEYWORD$(LOOP.%):GoSub ERRORS
- endw
- else
- EBUF$=KEYWORD$(LOOP.%):GoSub ERRORS
- endw
- endp
- proc _SWITCH
- when C.LN.%>0
- GoSub LEVEL:GoSub LEVEL:GoSub LEVEL|
- SWITCH$(SWITCH%+1)=COND$|
- SWITCH%=SWITCH%+1
- else
- EBUF$="operand":GoSub ERRORS
- endw
- endp
- proc _CASE
- GoSub POP
- when KEYWORD%=SWITCH.% AND SWITCH%>0
- when C.LN.%>0
- XN%=XN%+1:XN.%(XN%)=LEVEL%|
- GoSub LEVEL:FLAG%=4|
- PBUF$="IF("+SWITCH$(SWITCH%)+"<>"+COND$+") GOTO "|
- GoSub OUT_LINE
- else
- EBUF$="operand":GoSub ERRORS
- endw
- else
- GoSub PUSH|
- EBUF$=KEYWORD$(SWITCH.%):GoSub ERRORS
- endw
- endp
- proc _BREAK
- GoSub POP
- when KEYWORD%=SWITCH.%
- F.%=LEVEL%:GoSub POP:T.%=LEVEL%:TK%=T.%|
- FLAG%=4:PBUF$="GOTO ":GoSub OUT_LINE|
- KEYWORD%=SWITCH.%|
- LEVEL%=T.%:GoSub PUSH|
- LEVEL%=F.%:GoSub PUSH
- else
- GoSub PUSH|
- EBUF$=KEYWORD$(SWITCH.%):GoSub ERRORS
- endw
- endp
- proc _ENDC
- GoSub POP
- when KEYWORD%=SWITCH.%
- F.%=LEVEL%:GoSub POP:T.%=LEVEL%:GoSub POP|
- GoSub POPOFF:SWITCH%=SWITCH%-1
- else
- GoSub PUSH|
- EBUF$=KEYWORD$(SWITCH.%):GoSub ERRORS
- endw
- endp
- proc OUT_LINE
- '
- ' Build and output lines to the temp file.
- '
- when FLAG%<2 AND C.LN.%=0
- EBUF$="condition":GoSub ERRORS
- else
- NUM%=NUM%+1:OFFSET%=1
- IF(FLAG%<2 OR FLAG%>3)THEN LEVEL$=STR$(TK%):MID$(LEVEL$,1,1)="@"
- switch FLAG%
- case 0
- PBUF$="IF("+COND$+") GOTO "+LEVEL$
- break
- case 1
- PBUF$="IF NOT("+COND$+") GOTO "+LEVEL$
- break
- case 2
- GoSub STACK_IT
- break
- case 4
- PBUF$=PBUF$+LEVEL$
- endc
- PRINT #T.FILE%,RIGHT$(STR$(NUM%),LEN(STR$(NUM%))-1);SKIP$;PBUF$;COMMENT$
- IF(XN%>0 AND FLAG%<>2)THEN GoSub STORE_IT
- endw
- COMMENT$="":PBUF$="":LEVEL$=""
- endp
- proc STORE_IT
- '
- ' Pop off the target place savers and make tokens of them.
- '
- OFFSET%=0|
- FOR I%=1 TO XN%|
- LEVEL$=STR$(XN.%(I%)):MID$(LEVEL$,1,1)="@"|
- GoSub STACK_IT|
- NEXT I%|
- XN%=0
- endp
- proc STACK_IT
- '
- ' Store the tokens and labels with their corresponding line numbers.
- '
- STACK.%=STACK.%+1|
- STACK%(STACK.%)=NUM%+OFFSET%|
- STACK$(STACK.%)=LEVEL$|
- IF(COMPIL%)THEN NUM.%(STACK.%)=NUM%+OFFSET%
- OFFSET%=0
- endp
- proc PASS_2
- '
- ' This is the second phase of processing.
- ' First the stack has to be sorted in ascending order,
- ' so we can use a binary search on it.
- ' Then we read the temp file and process it a line at
- ' a time.
- '
- GoSub SORT|
- OFFSET%=2|
- Open"I",T.FILE%,T.FILE$|
- Open"O",O.FILE%,O.FILE$
- loop
- LINE INPUT #T.FILE%,BUF$|
- GoSub PROCESS_1
- until EOF(T.FILE%)
- endp
- proc PROCESS_1
- '
- ' Scan the input line a word at a time.
- ' The first word will be the line number.
- ' Then write the line to the output file.
- '
- INDEX%=0:ONFLAG%=0:LN.%=LEN(BUF$)|
- GoSub PARSER|
- IF(COMPIL%)THEN GoSub COMPIL
- while FIRST%<=LEN(BUF$)
- unless LEN(TEXT$)>7 OR LEN(TEXT$)<2 OR VAL(TEXT$)>0
- GoSub FIND_IT
- endu
- GoSub PARSER
- wend
- PRINT #O.FILE%,BUF$
- endp
- proc COMPIL
- '
- ' Binary search the number stack to see if the line number is used.
- '
- TEXT%=VAL(TEXT$):HIGH%=STACK.%+1:LOW%=0
- unless TEXT%<NUM.%(1) OR TEXT%>NUM.%(STACK.%)
- while((HIGH%-LOW%)>1)|
- I%=(HIGH%+LOW%)\2
- when NUM.%(I%)=TEXT%
- TEXT%=-1:LOW%=HIGH%
- else when NUM.%(I%)<TEXT%
- LOW%=I%
- else
- HIGH%=I%
- endw
- wend
- endu
- IF(TEXT%>0)THEN BUF$=SPACE$(LEN(TEXT$)+1)+COND$
- endp
- proc FIND_IT
- '
- ' Look for BASIC'S keywords and get the token/label to replace
- ' with the corresponding line number.
- '
- C.$=TEXT$:GoSub _Fold
- when C.$="on"
- ONFLAG%=-1
- else when LEN(C.$)>3
- unless INSTR(BASIC$,C.$)=0 OR COLN%
- GoSub PARSER:I$=LEFT$(TEXT$,1)
- unless I$="@" OR LEN(TEXT$)<>4
- C.$=TEXT$:GoSub _Fold|
- IF(C.$="else")THEN RETURN
- endu
- unless I$="0" AND ONFLAG%
- IF(ONFLAG%)THEN GoSub ON_FLAG ELSE GoSub SEARCH
- endu
- endu
- endw
- endp
- proc ON_FLAG
- '
- ' Resolve the `ON GOTO' or `ON GoSub' statements.
- ' Parse all the way to the end of the input line.
- '
- OFFSET%=1
- while(FIRST%<=LEN(BUF$))
- IF(TEXT$<>"")THEN GoSub SEARCH
- GoSub PARSER
- wend
- OFFSET%=2
- endp
- proc SEARCH
- '
- ' Binary search the token stack to get the corresponding line number.
- '
- HIGH%=STACK.%+1:LOW%=0:FIND%=-1
- while((HIGH%-LOW%)>1)|
- I%=(HIGH%+LOW%)\2
- when STACK$(I%)=TEXT$
- FIND%=STACK%(I%):LOW%=HIGH%
- else when STACK$(I%)<TEXT$
- LOW%=I%
- else
- HIGH%=I%
- endw
- wend
- when FIND%>0
- GoSub STUFF_IT
- else when TEXT$<>""
- ERRORS%=ERRORS%+1|
- PRINT"MISSING LABEL (";TEXT$;")"
- endw
- endp
- proc STUFF_IT
- '
- ' Replace the token/label with the corresponding line number.
- '
- NUM$=STR$(FIND%):SP$=""|
- L$=LEFT$(BUF$,FIRST%-OFFSET%)
- IF(LEFT$(COND$,1)<>" " AND LEFT$(COND$,1)<>":" AND ONFLAG%=0)THEN SP$=" "
- BUF$=L$+NUM$+SP$+COND$|
- INDEX%=LEN(L$)+LEN(NUM$)|
- LN.%=LEN(BUF$)
- endp
- proc SORT
- '
- ' Shell-Metzner in-memory sort of the token/label stack.
- ' Sort the line number stack if the compile flag is set.
- '
- PT.%=STACK.%|
- while (PT.%>0)|
- PT.%=PT.%\2
- when PT.%>0
- JT.%=1:KT.%=STACK.%-PT.%|
- while (JT.%<=KT.%)|
- LT.%=JT.%:CT.%=LT.%+PT.%
- while (LT.%>0 AND STACK$(LT.%)>=STACK$(CT.%))
- SWAP STACK$(LT.%),STACK$(CT.%)|
- SWAP STACK%(LT.%),STACK%(CT.%)
- CT.%=LT.%:LT.%=LT.%-PT.%:LT.%=LT.%*(1+(LT.%<0))
- wend
- when COMPIL%
- LT.%=JT.%:CT.%=LT.%+PT.%
- while (LT.%>0 AND NUM.%(LT.%)>=NUM.%(CT.%))
- SWAP NUM.%(LT.%),NUM.%(CT.%)|
- CT.%=LT.%:LT.%=LT.%-PT.%:LT.%=LT.%*(1+(LT.%<0))
- wend
- endw
- JT.%=JT.%+1|
- wend
- endw
- wend
- endp
- '------------------------------------------------------
- '- ** Sub-Routine Division -
- '------------------------------------------------------
- proc PARSER
- C.LN.%=0:I.%=0:COLN%=0:II%=32:TEXT%=0:COND$=""|
- TRM$=TM$+CHR$(58*ABS(INDEX%>0))
- while(INSTR(TRM$,CHR$(II%))>0)|
- INDEX%=INDEX%+1|
- IF(INDEX%<=LEN(BUF$))THEN II%=ASC(MID$(BUF$,INDEX%,1)) ELSE II%=7
- wend|
- FIRST%=INDEX%
- while(II%<>32 AND II%<>7)
- when INSTR(TRM$,CHR$(II%))>0 AND TEXT%=0
- COLN%=(CHR$(II%)=":"):I.%=1:II%=32
- else
- when II%=34 OR II%=40 OR II%=41
- IF(II%=34)THEN INDEX%=INSTR(INDEX%+1,BUF$,CHR$(34))
- IF(II%=40)THEN TEXT%=TEXT%+1 ELSE IF(II%=41)THEN TEXT%=TEXT%-1
- endw
- loop
- INDEX%=INDEX%+1|
- IF(INDEX%<=LEN(BUF$))THEN II%=ASC(MID$(BUF$,INDEX%,1)) ELSE II%=7
- endl unless II%=32 AND TEXT%<>0
- endw
- wend
- TEXT$=MID$(BUF$,FIRST%,INDEX%-FIRST%)|
- IF(LEN(BUF$)>INDEX%)THEN COND$=RIGHT$(BUF$,(LEN(BUF$)-INDEX%)+I.%):C.LN.%=LEN(COND$)
- endp
- proc FILENAMES
- LINE INPUT"INPUT FILE [.P]:",I.FILE$
- unless I.FILE$=""
- COMPIL%=(INSTR(I.FILE$,"/")>0)
- IF(COMPIL%)THEN I.FILE$=LEFT$(I.FILE$,LEN(I.FILE$)-1)
- IF(INSTR(I.FILE$,DOT$)=0)THEN I.FILE$=I.FILE$+IEXT$
- LK.$=I.FILE$:LK.%=I.FILE%:GoSub _Lookup:I.FILE%=LK.%|
- GOOD%=(I.FILE%<>FALSE%)
- unless GOOD%=FALSE%
- I%=INSTR(1,I.FILE$,DOT$)
- IF(I%=0)THEN I%=LEN(I.FILE$)+1
- E.FILE$=LEFT$(I.FILE$,I%-1)|
- LINE INPUT"OUTPUT FILE [.BAS]:",O.FILE$
- IF(O.FILE$="")THEN O.FILE$=E.FILE$
- IF(INSTR(O.FILE$,DOT$)=0)THEN O.FILE$=O.FILE$+OEXT$
- E.FILE$=E.FILE$+EEXT$
- endu
- endu
- endp
- proc INCLUDES
- GoSub FILES
- when FILE.%>0
- Open"I",FILE.%,FILE$|
- FILE%=FILE.%
- else
- EBUF$="include "+FILE$:GoSub ERRORS
- endw
- endp
- proc SUBROUTINE
- GoSub FILES
- when FILE.%>0
- TEXT%=0
- while(TEXT%<INCS%)
- TEXT%=TEXT%+1|
- IF(FILE$=INC$(TEXT%))THEN TEXT%=INCS%+1
- wend
- IF(TEXT%=INCS%)THEN INCS%=INCS%+1:INC$(INCS%)=FILE$
- else
- EBUF$="include "+FILE$:GoSub ERRORS
- endw
- endp
- proc FILES
- FILE$=RIGHT$(TEXT$,LEN(TEXT$)-1)|
- IF(INSTR(FILE$,DOT$)=0)THEN FILE$=FILE$+INCL$
- FILE.%=FILE%+1|
- LK.$=FILE$:LK.%=FILE.%:GoSub _Lookup:FILE.%=LK.%
- endp
- proc ERRORS
- ERRORS%=ERRORS%+1|
- EBUF$="ERR#"+STR$(ERRORS%)+" MISSING ("+EBUF$+") PROC <"+LPROC$+">"|
- EBUF$=EBUF$+" AT"+STR$(KERR%)|
- PRINT EBUF$:PRINT #E.FILE%,EBUF$
- endp
- proc _Fold
- f.0%=1
- while(f.0%<=LEN(C.$))
- f.2%=ASC(MID$(C.$,f.0%,1))
- f.2%=f.2%+(32*ABS(f.2%>64 AND f.2%<91))
- MID$(C.$,f.0%,1)=CHR$(f.2%):f.0%=f.0%+1
- wend
- endp
- proc _Lookup
- OPEN"R",LK.%,LK.$:L.K!=LOF(LK.%):CLOSE LK.%
- IF(L.K!<1)THEN LK.%=0:KILL LK.$
- endp