Skip to content

Commit 5c84203

Browse files
committed
Improved BASIC interpreter sample:
- Allow trailing REM comments. - Fix non-working DATA and READ statements. - Read extra whitespace before reading a new line of text, fixes issues with double '> ' prompt after reading variables from stdin during a program run. - Added bfact.bas, bhaunted.bas, blaunch.bas, bnbody.bas, bspring.bas sample programs.
1 parent c6f497c commit 5c84203

File tree

6 files changed

+212
-13
lines changed

6 files changed

+212
-13
lines changed

samples/basic.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ class basic_interpreter
8787
| "-"_sx > r2_%Term <[this]{ *r1_ -= *r2_; }
8888
) <[this]{ return *r1_; };
8989

90-
rule FnEval = r1_%Expr > eoi <[this]{ fn_result_ = *r1_; };
90+
rule Rem = "REM"_isx > *(!NL > any);
91+
92+
rule FnEval = r1_%Expr > ~Rem > eoi <[this]{ fn_result_ = *r1_; };
9193

9294
rule DimEl = id_%Var > "(" > r1_%Expr > ","
9395
> r2_%Expr > ")" <[this]{ dim(tables_[*id_], *r1_, *r2_); }
@@ -114,14 +116,14 @@ class basic_interpreter
114116
| "DIM"_isx > DimEl > *("," > DimEl)
115117
| "RESTORE"_isx <[this]{ read_itr_ = data_.cbegin(); }
116118
| "READ"_isx > ReadEl > *("," > ReadEl)
119+
| "DATA"_isx > DataEl > *("," > DataEl)
117120
| "INPUT"_isx > InptEl > *("," > InptEl)
118121
| "PRINT"_isx > ~PrntEl > *("," > PrntEl) <[] { std::cout << std::endl; }
119122
| "GOSUB"_isx > no_%LineNo <[this]{ gosub(*no_); }
120123
| "RETURN"_isx <[this]{ retsub(); }
121124
| "STOP"_isx <[this]{ haltline_ = line_; line_ = lines_.end(); }
122-
| "END"_isx <[this]{ if (line_ == lines_.end()) std::exit(EXIT_SUCCESS); line_ = lines_.end(); }
123-
| ("EXIT"_isx | "QUIT"_isx) <[] { std::exit(EXIT_SUCCESS); }
124-
| "REM"_isx > *(!NL > any);
125+
| "END"_isx <[this]{ line_ = lines_.end(); }
126+
| ("EXIT"_isx | "QUIT"_isx) <[] { std::exit(EXIT_SUCCESS); };
125127

126128
rule Cmnd = "CLEAR"_isx <[this]{ lines_.clear(); }
127129
| "CONT"_isx <[this]{ cont(); }
@@ -130,8 +132,9 @@ class basic_interpreter
130132
| "RUN"_isx <[this]{ line_ = lines_.begin(); read_itr_ = data_.cbegin(); }
131133
| "SAVE"_isx > txt_%String <[this]{ save(*txt_); };
132134

133-
rule Line = Stmnt > NL
134-
| Cmnd > NL
135+
rule Line = Rem > NL
136+
| Stmnt > ~Rem > NL
137+
| Cmnd > ~Rem > NL
135138
| no_%LineNo
136139
> capture(txt_)[*(!NL > any) > NL] <[this]{ update_line(*no_, *txt_); }
137140
| NL
@@ -154,6 +157,7 @@ class basic_interpreter
154157
} else {
155158
if (stdin_tty_)
156159
std::cout << "> " << std::flush;
160+
std::cin >> std::ws;
157161
if (!std::getline(std::cin, out))
158162
return false;
159163
out.push_back('\n');
@@ -202,7 +206,8 @@ class basic_interpreter
202206
if (lastline_ != lines_.end())
203207
std::cerr << "LINE " << lastline_->first << ": " << lastline_->second << std::flush;
204208
line_ = lastline_ = lines_.end();
205-
stack_.clear(), for_stack_.clear();
209+
stack_.clear();
210+
for_stack_.clear();
206211
}
207212
}
208213

@@ -257,10 +262,12 @@ class basic_interpreter
257262

258263
void retsub()
259264
{
260-
if (!stack_.empty())
261-
line_ = stack_.back(), stack_.pop_back();
262-
else
265+
if (!stack_.empty()) {
266+
line_ = stack_.back();
267+
stack_.pop_back();
268+
} else {
263269
print_error("ILLEGAL RETURN");
270+
}
264271
}
265272

266273
void for_to_step(std::string const& id, double from, double to, double step)
@@ -272,7 +279,7 @@ class basic_interpreter
272279
for_stack_.emplace_back(id, lastline_);
273280
v = from;
274281
}
275-
if ((step >= 0 && v <= to) || (step < 0 && v >= to))
282+
if (((step >= 0) && (v <= to)) || ((step < 0) && (v >= to)))
276283
return;
277284
for_stack_.pop_back();
278285
for (auto k = id.size(); line_ != lines_.end(); ++line_) {
@@ -291,7 +298,7 @@ class basic_interpreter
291298

292299
void next(std::string const& id)
293300
{
294-
if (lastline_ != lines_.end() && !for_stack_.empty() && for_stack_.back().first == id) {
301+
if ((lastline_ != lines_.end()) && !for_stack_.empty() && (for_stack_.back().first == id)) {
295302
lastline_ = line_;
296303
line_ = for_stack_.back().second;
297304
} else {
@@ -336,7 +343,7 @@ class basic_interpreter
336343

337344
void dim(Table& tab, double m, double n)
338345
{
339-
if (m < 0.0 || n < 0.0) {
346+
if ((m < 0.0) || (n < 0.0)) {
340347
print_error("ARRAY SIZE OUT OF RANGE");
341348
return;
342349
}

samples/bfact.bas

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
REM THIS PROGRAM CALCULATES THE FACTORIAL OF A GIVEN NUMBER
2+
10 PRINT "Enter a number: "
3+
20 INPUT N
4+
30 LET F = 1
5+
40 FOR I = 1 TO N
6+
50 LET F = F * I
7+
60 NEXT I
8+
70 PRINT "The factorial of ", N, " is ", F
9+
80 END

samples/bhaunted.bas

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
REM HAUNTED MANSION TEXT ADVENTURE GAME
2+
3+
10 RESTORE
4+
20 DATA 0, 0, 0
5+
30 READ O, S, K
6+
40 PRINT "WELCOME TO THE HAUNTED MANSION ADVENTURE!"
7+
8+
50 REM ENTRANCE
9+
60 PRINT "YOU FIND YOURSELF IN THE ENTRANCE HALL."
10+
70 PRINT "WHAT DO YOU WANT TO DO?"
11+
80 PRINT "1. GO UPSTAIRS"
12+
90 PRINT "2. GO TO THE KITCHEN"
13+
100 PRINT "3. EXAMINE THE HALL"
14+
110 IF S = 1 THEN PRINT "4. ATTEMPT TO ESCAPE"
15+
120 INPUT C
16+
130 IF C = 1 THEN GOTO 200 REM UPSTAIRS
17+
140 IF C = 2 THEN GOTO 300 REM KITCHEN
18+
150 IF C = 3 THEN GOTO 400 REM EXAMINE HALL
19+
160 IF S <> 1 THEN GOTO 180 REM TRY AGAIN
20+
170 IF C = 4 THEN GOTO 500 REM ESCAPE
21+
180 PRINT "INVALID CHOICE, TRY AGAIN."
22+
190 GOTO 70 REM WHAT TO DO
23+
24+
200 REM UPSTAIRS
25+
210 PRINT "YOU GO UPSTAIRS AND ENTER A BEDROOM."
26+
220 PRINT "THERE IS A GLOWING ORB ON THE DRESSER."
27+
230 PRINT "1. TAKE THE ORB"
28+
240 PRINT "2. LEAVE THE ROOM"
29+
250 INPUT C
30+
260 IF C = 1 THEN GOTO 270 REM TAKE ORB
31+
261 IF C = 2 THEN GOTO 60 REM LEAVE ROOM
32+
262 GOTO 180 REM INVALID CHOICE
33+
270 PRINT "YOU TAKE THE ORB AND FEEL A SURGE OF POWER!"
34+
280 LET O = 1
35+
290 GOTO 50 REM ENTRANCE
36+
37+
300 REM KITCHEN
38+
310 PRINT "YOU ENTER THE KITCHEN. IT SMELLS TERRIBLE."
39+
320 PRINT "THERE IS A MOLDY SANDWICH ON THE TABLE."
40+
330 PRINT "1. EAT THE SANDWICH"
41+
340 PRINT "2. LEAVE THE KITCHEN"
42+
350 INPUT C
43+
360 IF C = 1 THEN GOTO 370 REM EAT SANDWICH
44+
361 IF C = 2 THEN GOTO 50 REM LEAVE KITCHEN
45+
362 GOTO 180 REM INVALID CHOICE
46+
370 PRINT "YOU EAT THE SANDWICH AND FEEL QUEASY."
47+
375 LET S = 1
48+
380 IF 20 * RND > 8 THEN GOTO 50 REM ENTRANCE HALL
49+
390 PRINT "YOU BECOME SICK AND COLLAPSE."
50+
391 PRINT "YOUR ADVENTURE ENDS HERE. GAME OVER."
51+
392 END
52+
53+
400 REM EXAMINE HALL
54+
410 PRINT "YOU EXAMINE THE ENTRANCE HALL CLOSELY."
55+
420 PRINT "YOU FIND A RUSTY KEY UNDER THE CARPET."
56+
430 LET K = 1
57+
440 GOTO 50 REM ENTRANCE
58+
59+
500 REM ESCAPE
60+
510 IF O <> 1 THEN GOTO 640 REM LOCKED DOOR
61+
520 IF K <> 1 THEN GOTO 640 REM LOCKED DOOR
62+
600 PRINT "YOU USE THE KEY TO UNLOCK THE FRONT DOOR."
63+
610 PRINT "WITH THE ORB'S POWER, YOU ESCAPE THE MANSION!"
64+
620 PRINT "CONGRATULATIONS, YOU WON!"
65+
630 END
66+
640 PRINT "THE FRONT DOOR IS LOCKED. YOU CANNOT ESCAPE."
67+
650 GOTO 50 REM ENTRANCE

samples/blaunch.bas

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
REM THIS PROGRAM CALCULATES THE TRAJECTORY OF A PROJECTILE LAUNCHED
2+
REM WITH A GIVEN INITIAL VELOCITY, LAUNCH ANGLE AND HEIGHT
3+
10 PRINT "Enter the initial velocity (in m/s): "
4+
20 INPUT V
5+
30 PRINT "Enter the launch angle (in degrees): "
6+
40 INPUT A
7+
50 PRINT "Enter the initial height (in meters): "
8+
60 INPUT H0
9+
70 LET G = 9.81
10+
80 GOSUB 200 REM CALCULATE TRAJECTORY
11+
90 PRINT "Time of flight is ", T, " seconds"
12+
100 PRINT "Maximum height is ", H, " meters"
13+
110 PRINT "Range is ", R, " meters"
14+
120 END
15+
200 REM SUBROUTINE TO CALCULATE TRAJECTORY
16+
210 LET R = A * 3.1415926535 / 180
17+
220 LET T = (V * SIN(R) + SQR((V * SIN(R)) ^ 2 + 2 * G * H0)) / G
18+
230 LET H = H0 + V * V * SIN(R) * SIN(R) / (2 * G)
19+
240 LET R = V * COS(R) * T
20+
250 RETURN

samples/bnbody.bas

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
10 REM N-BODY GRAVITATIONAL SIMULATION
2+
20 PRINT "ENTER NUMBER OF PARTICLES: "
3+
30 INPUT N
4+
40 DEF FNS(X) = X * X
5+
50 DIM M(N), X(N), Y(N), V1(N), V2(N), A1(N), A2(N)
6+
60 GOSUB 1000 REM INITIALIZE PARTICLE PROPERTIES
7+
8+
100 REM MAIN SIMULATION LOOP
9+
110 PRINT "ENTER NUMBER OF TIME STEPS: "
10+
120 INPUT T
11+
130 PRINT "ENTER TIME STEP SIZE (S): "
12+
140 INPUT T0
13+
150 FOR T1 = 1 TO T
14+
160 GOSUB 2000 REM CALCULATE FORCES
15+
170 GOSUB 3000 REM UPDATE POSITIONS AND VELOCITIES
16+
180 GOSUB 4000 REM PRINT PARTICLE POSITIONS
17+
190 NEXT T1
18+
200 END
19+
20+
1000 REM INITIALIZE PARTICLE PROPERTIES
21+
1010 FOR I = 1 TO N
22+
1020 PRINT "ENTER MASS (KG) FOR PARTICLE", I, ": "
23+
1030 INPUT M(I)
24+
1040 PRINT "ENTER X POSITION (M) FOR PARTICLE", I, ": "
25+
1050 INPUT X(I)
26+
1060 PRINT "ENTER Y POSITION (M) FOR PARTICLE", I, ": "
27+
1070 INPUT Y(I)
28+
1080 PRINT "ENTER X VELOCITY (M/S) FOR PARTICLE", I, ": "
29+
1090 INPUT V1(I)
30+
1100 PRINT "ENTER Y VELOCITY (M/S) FOR PARTICLE", I, ": "
31+
1110 INPUT V2(I)
32+
1120 NEXT I
33+
1130 RETURN
34+
35+
2000 REM CALCULATE FORCES
36+
2010 FOR I = 1 TO N
37+
2020 LET A1(I) = 0
38+
2030 LET A2(I) = 0
39+
2040 FOR J = 1 TO N
40+
2050 IF I <> J THEN GOSUB 5000 REM CALCULATE GRAVITATIONAL FORCE
41+
2060 NEXT J
42+
2070 NEXT I
43+
2080 RETURN
44+
45+
3000 REM UPDATE POSITIONS AND VELOCITIES
46+
3010 FOR I = 1 TO N
47+
3020 LET V1(I) = V1(I) + A1(I) * T0
48+
3030 LET V2(I) = V2(I) + A2(I) * T0
49+
3040 LET X(I) = X(I) + V1(I) * T0
50+
3050 LET Y(I) = Y(I) + V2(I) * T0
51+
3060 NEXT I
52+
3070 RETURN
53+
54+
4000 REM PRINT PARTICLE POSITIONS
55+
4010 PRINT "TIME STEP: ", T1 * T0, " S"
56+
4020 FOR K = 1 TO N
57+
4030 PRINT "PARTICLE", K, " POSITION: (", X(K), ",", Y(K), ") M"
58+
4040 NEXT K
59+
4050 RETURN
60+
61+
5000 REM CALCULATE GRAVITATIONAL FORCE
62+
5020 LET G = 6.67430E-11
63+
5030 LET X0 = X(J) - X(I)
64+
5040 LET Y0 = Y(J) - Y(I)
65+
5050 LET R = SQR(FNS(X0) + FNS(Y0))
66+
5060 IF R > 0 THEN GOTO 5080
67+
5070 RETURN
68+
5080 LET F = G * M(I) * M(J) / (R * R)
69+
5090 LET A1(I) = A1(I) + F * X0 / (R * M(I))
70+
5100 LET A2(I) = A2(I) + F * Y0 / (R * M(I))
71+
5110 RETURN

samples/bspring.bas

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
REM THIS PROGRAM MODELS A SIMPLE HARMONIC OSCILLATOR (A MASS ON A SPRING)
2+
10 PRINT "Enter the spring constant (in N/m): "
3+
20 INPUT K
4+
30 PRINT "Enter the mass (in kg): "
5+
40 INPUT M
6+
50 PRINT "Enter the initial displacement (in m): "
7+
60 INPUT X0
8+
70 PRINT "Enter the simulation time (in s): "
9+
80 INPUT T
10+
90 PRINT "Enter the time step (in s): "
11+
100 INPUT D
12+
110 LET N = INT(T / D)
13+
120 DIM X(N)
14+
130 GOSUB 200 REM CALCULATE POSITIONS
15+
140 PRINT "Time (s)", " ", "Position (m)"
16+
150 FOR I = 1 TO N
17+
160 PRINT I * D, " ", X(I)
18+
170 NEXT I
19+
180 END
20+
200 REM SUBROUTINE TO CALCULATE POSITIONS
21+
220 LET O = SQR(K / M)
22+
230 FOR I = 1 TO N
23+
240 LET X(I) = X0 * COS(O * (I * D))
24+
250 NEXT I
25+
260 RETURN

0 commit comments

Comments
 (0)