home *** CD-ROM | disk | FTP | other *** search
- SUB PREP (Prg$)
- ' Prep can do a lot of things depending on how complicated you want your
- ' language to be. EXEC simply parses the line apart and looks for three
- ' things which it can handle. It looks for statements (PRINT, INPUT), it
- ' looks for functions (UCASE, VAL) and it looks for arguments (numbers or
- ' variables like A,B,GRANNY,USERNAME). If this is all we need for our
- ' language then PREP is not necessary, PREP is required to do at least 2
- ' very necessary things in order to make our language truly viable. First,
- ' EXEC "parses" what is passed to it by looking for spaces, commas and
- ' semicolons (these are interchangeable). EXEC does not understand the
- ' concept of QUOTED STRINGS since quoted strings may contain spaces and
- ' punctuation that would confuse the parsing technique. Of course, we
- ' could teach EXEC to look for begin and end quotes and not parse or
- ' attempt to interpret what is between them, and to simply push the
- ' entire quoted string onto the argument stack, but this would really
- ' slow things down. It is better to deal with quoted strings all at once
- ' beforehand. Of course, it would be even better to PREP the WHOLE PROGRAM
- ' before it is executed, and this would give us an added opportunity to
- ' strip REMarks, pre-establish the positions of labels, and pack out blank
- ' lines, but this would start to make this source code harder and harder
- ' to understand, and we're trying to make this as easy as we can.
-
- ' Remove all quoted strings and make temporary variables out of them.
- X%=65
- DO
- a%=INSTR(PRG$,CHR$(34))
- IF a% THEN
- VALUE$=MID$(PRG$, a%)
- b%=INSTR(2,VALUE$,CHR$(34))
- IF b% THEN VALUE$=LEFT$(VALUE$,b%)
- REPLACE VALUE$ WITH CHR$(1,X%) IN PRG$
- ARRAY SCAN VAR$(1), COLLATE UCASE, =CHR$(1,X%), TO i%
- IF i% THEN
- VALUE$(i%)=REMOVE$(VALUE$,CHR$(34))
- ELSE
- INCR NextVar%
- VALUE$(NextVar%)=REMOVE$(VALUE$,CHR$(34))
- VAR$(NextVar%)=CHR$(1,X%)
- END IF
- ELSE
- EXIT LOOP
- END IF
- INCR X%
- LOOP
-
- ' Secondly, we have to deal with the harsh realities of NUMERIC EXPRESSIONS.
- ' We could certainly work that into EXEC as well, using a technique called
- ' RECURSIVE DESCENT PARSING, but that, too would start making things a bit
- ' hideous.
- ' Being able to handle an line like ...
- ' PRINT B*20/C+(INT(D/100))
- ' ... where a statement is followed by an expression which includes
- ' literal numbers and variables and functions (like INT) would require a
- ' much more complex parsing algorithm than we are introducing here.
- ' Another way to deal with expressions is to force any arithmetic to
- ' be performed in special arithmetic functions, like ...
- '
- ' PRINT ADD(DIV(MUL(B,20),C),INT(DIV(D,100))
- '
- ' with the stack-parsing technique we are using for language processing
- ' this type of expression would be much much much easier to implement, BUT
- ' it starts to make our language seem pretty silly, so what we are going to
- ' do is this: By pushing arithmetic symbols onto the argument stack along
- ' with the rest of the arguments, a variable-free, statement-free expression
- ' can be built whenever the stack is popped clean by the CALC function.
- ' in other words, the above expression would wind up looking like this:
- '
- ' PRINT CALC B*20/C+(INT(CALC D/100))
- '
- ' ... which I would consider more of a fair compromise, and for the burden
- ' of forcing you to use the CALC command before every arithmetic expression
- ' you can still use natural arithmetic without having to make your language
- ' look like FrameWork Fred. (ick!) To accomplish this, we have to make
- ' sure that arithmetic symbols get parsed and pushed as individuals. In
- ' order for that to happen, we must ensure that they are separated by a
- ' parsing character, such as a SPACE.
-
- REPLACE "+" WITH " + " IN PRG$
- REPLACE "-" WITH " - " IN PRG$
- REPLACE "*" WITH " * " IN PRG$
- REPLACE "\" WITH " \ " IN PRG$
- REPLACE "/" WITH " / " IN PRG$
- REPLACE "^" WITH " ^ " IN PRG$
- REPLACE "<" WITH " < " IN PRG$
- REPLACE ">" WITH " > " IN PRG$
- REPLACE "(" WITH " ( " IN PRG$
- REPLACE ")" WITH " ) " IN PRG$
- REPLACE "=" WITH " = " IN PRG$
-
- ' Now, finally, we will be dealing in a free-form program structure where
- ' the single string being processed here may contain carriage returns and
- ' line feeds. In the case of multiple lines, we don't want the whole
- ' module executed in reverse (which is what stack-parsing does) so we will
- ' remove all carriage returns and line feeds, and we'll be flipping the
- ' lines, so the last lines come first and the first come last. To fully
- ' understand why we are doing this, you must fully understand stack-parsing.
- ' In stack parsing, we push every item in a single statement onto a stack,
- ' processing it as it goes, from last to first. If you have a line which
- ' read like this:
- '
- ' print mid$ (A$, Y%, 1)
- ' ^^^^^ ^^^^ ^^^^ ^^^ ^^
- ' STATEMENT FUNCTION VARIABLE VARIABLE ARGUMENT
- ' ... the stack-parser start out by pushing the argument 1 as a literal
- ' number. Then it would evaluate Y% and push it's value as a literal
- ' number. Then it would evaluate A$ and push it's contents as a literal
- ' string. Then it would get to the function MID$. It would POP the three
- ' arguments in order to see what it needs to MID$ with, and then push the
- ' result as a literal string. Finally, PRINT would see that one single
- ' item on the stack (the result of MID$) and print it. For more information
- ' about stack parsing, go back 20 lines and read this again until you get it.
-
- IF INSTR(PRG$,ANY CHR$(13,58)) THEN
- ' remove all line feeds (PBWrite and other text editors produce them)
- ' Add a closing carriage return, just in case, and then reverse
- ' the order of every line of text.
- PRG$=REVERSE$(REMOVE$(PRG$,CHR$(10)))
- ' and remove blank lines
- END IF
-
- REPLACE " " WITH " " IN PRG$ ' elimate double spaces
-
- END SUB
-
- FUNCTION REVERSE$(X$)
- IF X$="" THEN EXIT FUNCTION
- IF INSTR(X$,ANY CHR$(13,58)) = 0 THEN
- REVERSE$=X$
- EXIT FUNCTION
- ELSE
- Y$=LEFT$(X$,INSTR(X$,ANY CHR$(13,58))-1)
- Z$=MID$(X$,INSTR(X$,ANY CHR$(13,58))+1)
- REVERSE$=REVERSE$(Z$)+" " + Y$
- END IF
-
- END FUNCTION