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