Wow. You really thought about it. 221 lines of code!

I have this notion that I need to scan through the characters and split the
input into words. I can simplify a lot because the bounds are known and very
limited.

For example, " S " INSTR cmd$ is a very simple case and so is " L " - so for
these simply extracting the flight and the target is straightforward.

When " C " INSTR cmd$, if I check for a modifier (X or L) as the last
character, it makes it as simple as the previous example.

Let me play with some code and see what I come up with over the next couple
of days. I think I can be a lot more computationally economical, but my code
will not flex easily to other cases, whereas your code is applicable in a
lot of other cases.

If I can't do it, may I use your code example as a guide? It's well labeled,
flexible and explicit.

Dave

On Sun, Feb 6, 2011 at 2:14 PM, Tobias Fröschle <
tobias.froesc...@t-online.de> wrote:

> Dave,
> had a lazy Sunday afternoon and was thinking about your problem - And,
> being a bit challenged and had nothing else to do, wrote a parser/analyzer
> for your "Language":
> Ended up with quite a bit of code, the problem is not as simple as it seems
> (Hope I didn't over-complicate things). But I wanted to have a generic
> parser that could easily be extended and also probably be used for other
> purposes.
> It seems to understand most of the commands you mentioned and could be a
> starting point for you. Note it's currently only accepting uppercase
> commands.
> If you don't use Turbo and its toolkit, just remove the MANIFEST statemens
> at the beginning of lines 110 to 130, they declare the variables in the
> lines "constant" - I just like to use symbolic names for the states and
> commands instead of values, it's just easier to read.
> Now go ahead and tear it apart.....
>
> Cheers,
> Tobias
>
> 100 DIM command$(100)
> 110 MANIFEST : S_REJECT_LINE = -1 : S_START = 1 : S_HAVE_FNO = 2 : S_DONE =
> 3 : S_GET_VALUE = 4
> 120 REMark some constants for the commands
> 130 MANIFEST : C_INVALID% = -1 : C_CHANGE% = 1 : C_SPEED% = 2 : C_TAKEOFF%
> = 3 : C_LAND% = 4
> 140 MANIFEST : C_CHANGEALT% = 5 : C_CHANGEHEAD% = 6
> 150 REPeat InpLoop
> 160   INPUT #1,"Please enter a command Line:",command$
> 170   valid = parseLine(command$)
> 180   IF (valid) THEN
> 190     PRINT "Flight #";fNo$;", please ";
> 200     SELect ON command%
> 210       = C_SPEED%
> 220         PRINT "Change speed to "; value
> 230       = C_TAKEOFF%
> 240         PRINT "Take off"
> 250       = C_LAND%
> 260         PRINT "Land"
> 270       = C_CHANGEALT%
> 280         PRINT "Change altitude to "; value
> 290       = C_CHANGEHEAD%
> 300         PRINT "Change heading to "; value
> 310     END SELect
> 320   ELSE
> 330     PRINT "Invalid line"
> 340   END IF
> 350 END REPeat InpLoop
> 360 :
> 370 DEFine PROCedure InitParser (l$)
> 380   linePos = 1
> 390   lineToParse$ = l$
> 400 END DEFine
> 410 :
> 430 :
> 440 REMark
> ************************************************************************
> 450 REMark * this procedure parses an entered command line into the parts
> needed
> 460 REMark * returns 1 in case of success. The variables are set as follows
> 470 REMark *   fno$             holds the flight number
> 480 REMark *   command%         holds the command to execute (see line 130)
> 490 REMark *   value            holds numeric value of command
> 500 REMark
> ************************************************************************
> 510 DEFine FuNction parseLine(command$)
> 520   InitParser command$
> 530   REMark Set status to "Start parsing line"
> 540   state = S_START
> 550 :
> 560   REMark enter the loop that walks through the state machine
> 570   REPeat parseLoop
> 580     token$ = getNextToken$
> 590     REMark did we hit the end of line?
> 600     IF token$ = CHR$(10) THEN
> 610       REMark check whether we're done or would have needed more input
> to be valid
> 620       REMark anything except S_DONE at the end of input is a wrong line
> 630       SELect ON state
> 640         = S_REJECT_LINE
> 650           PRINT "Line "&cmd$& " invalid at line end"
> 660           RETurn 0
> 670         = S_START
> 680           PRINT "Empty line entered"
> 690           RETurn 0
> 700         = S_HAVE_FNO
> 710           PRINT "Something after flight number is missing"
> 720           RETurn 0
> 730         = S_DONE
> 740           REMark valid end of command line
> 750           RETurn 1
> 760         = REMAINDER
> 770           PRINT "Invalid state"
> 780           RETurn 0
> 790       END SELect
> 800     ELSE
> 810       REMark Got a valid token, no line end
> 820 :
> 830       SELect ON state
> 840         = S_REJECT_LINE
> 850           PRINT "Line rejected: Line "& cmd$ & "invalid at "& token$ &
> " State is:"&state
> 860           RETurn 0
> 870         = S_START
> 880           fNo$ = getFlightNo$ (token$)
> 890           IF fNo$ <> "INVALID" THEN
> 900             state = S_HAVE_FNO
> 910           ELSE
> 920             PRINT "Invalid Flight number"
> 930             state = S_REJECT_LINE
> 940           END IF
> 950         = S_HAVE_FNO
> 960           command% = getCommand% (token$)
> 970           SELect ON command%
> 980             = C_INVALID%
> 990               state = S_REJECT_LINE
> 1000             = C_CHANGE%
> 1010               REMark special handling of numerical input according to
> # of digits
> 1020               token$ = peekNextToken$
> 1030               tl% = LEN(token$)
> 1040               SELect ON tl%
> 1050                 = 2
> 1060                   command% = C_CHANGEALT%
> 1070                 = 3
> 1080                  command% = C_CHANGEHEAD%
> 1090                = REMAINDER
> 1100                  state = S_REJECT_LINE
> 1110                  PRINT "Invalid number of digits after C command"
> 1120               END SELect
> 1130               state = S_GET_VALUE
> 1140             = C_SPEED%
> 1150               state = S_GET_SPEED
> 1160             = C_TAKEOFF%
> 1170               state = S_DONE
> 1180             = C_LAND%
> 1190               state = S_DONE
> 1200            END SELect
> 1210         = S_GET_VALUE
> 1220           value = getNumericValue (token$)
> 1230           state = S_DONE
> 1240         = S_NEW_ALT
> 1250           value = getNumericValue (token$)
> 1260           IF value <> -1 THEN
> 1270             state = S_DONE
> 1280           ELSE
> 1290             state = S_REJECT_LINE
> 1300             PRINT "Invalid numeric value "; token$; " encountered"
> 1310           END IF
> 1320         = REMAINDER
> 1330             PRINT "Invalid state:"&state
> 1340       END SELect
> 1350     END IF
> 1360   END REPeat parseLoop
> 1370 END DEFine parseLine
> 1380 :
> 1390 DEFine FuNction getCommand% (token$)
> 1400   LOCal cret%
> 1410   cret% = C_INVALID%
> 1420   IF token$(1) = "C"
> 1430     cret% = C_CHANGE%
> 1440   END IF
> 1450   IF token$(1) = "S"
> 1460     cret% = C_SPEED%
> 1470   END IF
> 1480   IF token$(1) = "T"
> 1490     cret% = C_TAKEOFF%
> 1500   END IF
> 1510   IF token$(1) = "L"
> 1520     cret% = C_LAND%
> 1530   END IF
> 1540   RETurn cret%
> 1550 END DEFine
> 1560 :
> 1570 DEFine FuNction getFlightNo$ (token$)
> 1580   REMark this should check for a valid flight number, but just returns
> the string it got for now
> 1590   RETurn token$
> 1600 END DEFine
> 1610 :
> 1620 DEFine FuNction getNumericValue (token$)
> 1630 LOCal newValue
> 1640   newValue = -1 : REMark this is the "invalid" marker
> 1650   REMark add some checks here that the conversion to numeric is
> actually a valid number
> 1660   newValue = token$
> 1670   RETurn newValue
> 1680 END DEFine
> 1690 :
> 1700 REMark this fn returns the next token from the input line, separated
> by any number of "white space'
> 1710 REMark characters. The token is removed from the line
> 1720 DEFine FuNction getNextToken$
> 1730   LOCal tmp$(100)
> 1740   tmp$ = peekNextToken$
> 1750   IF tmp$ <> CHR$(10)
> 1760     REMark remove the token from the input line
> 1770     lineToParse$ = lineToParse$ (linePos TO)
> 1780   END IF
> 1790   RETurn tmp$
> 1800 END DEFine
> 1810 :
> 1820 REMark this line returns the next token from the line, without
> removing it. Used to "peek forward"
> 1830 REMark Needed when the syntax is not LR(1)
> 1840 DEFine FuNction peekNextToken$
> 1850   LOCal startPos, endPos, llen, token$(100), inChar
> 1860   startPos = 1 : endPos = 1 : llen = LEN(lineToParse$)
> 1870   IF llen = 0 THEN
> 1880     RETurn CHR$(10)
> 1890   END IF
> 1900   REMark skip any white space before
> 1910   REPeat s1lp
> 1920     inChar = CODE (lineToParse$(startPos))
> 1930     SELect ON inChar
> 1940       = 32
> 1950         REMark space
> 1960         startPos = startPos + 1
> 1970       = 9
> 1980         REMark tab
> 1990         startPos = startPos + 1
> 2000       = 33 TO 128
> 2010         REMark ASCII
> 2020         EXIT s1lp
> 2030       = REMAINDER
> 2040         PRINT "Invalid input character "&inChar
> 2050     END SELect
> 2060     IF startPos > LEN (lineToParse$) THEN
> 2070       RETurn CHR$(10)
> 2080     END IF
> 2090   END REPeat s1lp
> 2100   REMark now we have startPos at the first character of the token.
> Advance endPos to the end of it
> 2110   endPos = startPos + 1
> 2120   REPeat s2lp
> 2130     IF (endPos > LEN(lineToParse$)) THEN
> 2140       EXIT s2lp
> 2150     END IF
> 2160     inChar = CODE (lineToParse$(endPos))
> 2170     SELect ON inChar
> 2180       = 32,9
> 2190         EXIT s2lp
> 2200       = 33 TO 128
> 2210         endPos = endPos + 1
> 2220       = REMAINDER
> 2230         PRINT "Invalid character in input line"
> 2240     END SELect
> 2250   END REPeat s2lp
> 2260   REMark remember where we were
> 2270   linePos = endPos
> 2280   REMark and deliver the found token
> 2290   token$ = lineToParse$(startPos TO endPos)
> 2300   RETurn token$
> 2310 END DEFine peekNextToken$
>
>
> _______________________________________________
> QL-Users Mailing List
> http://www.q-v-d.demon.co.uk/smsqe.htm
>
_______________________________________________
QL-Users Mailing List
http://www.q-v-d.demon.co.uk/smsqe.htm

Reply via email to