forked from nanochess/bootBASIC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
basic.lst
599 lines (599 loc) · 39.6 KB
/
basic.lst
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
1 ;
2 ; bootBASIC interpreter in 512 bytes (boot sector)
3 ;
4 ; by Oscar Toledo G.
5 ; http://nanochess.org/
6 ;
7 ; (c) Copyright 2019-2020 Oscar Toledo G.
8 ;
9 ; Creation date: Jul/19/2019. 10pm to 12am.
10 ; Revision date: Jul/20/2019. 10am to 2pm.
11 ; Added assignment statement. list now
12 ; works. run/goto now works. Added
13 ; system and new.
14 ; Revision date: Jul/22/2019. Boot image now includes 'system'
15 ; statement.
16 ;
17
18 ;
19 ; USER'S MANUAL:
20 ;
21 ; Line entry is done with keyboard, finish the line with Enter.
22 ; Only 19 characters per line as maximum.
23 ;
24 ; Backspace can be used, don't be fooled by the fact
25 ; that screen isn't deleted (it's all right in the buffer).
26 ;
27 ; All statements must be in lowercase.
28 ;
29 ; Line numbers can be 1 to 999.
30 ;
31 ; 26 variables are available (a-z)
32 ;
33 ; Numbers (0-65535) can be entered and display as unsigned.
34 ;
35 ; To enter new program lines:
36 ; 10 print "Hello all!"
37 ;
38 ; To erase program lines:
39 ; 10
40 ;
41 ; To test statements directly (interactive syntax):
42 ; print "Hello all!"
43 ;
44 ; To erase the current program:
45 ; new
46 ;
47 ; To run the current program:
48 ; run
49 ;
50 ; To list the current program:
51 ; list
52 ;
53 ; To exit to command-line:
54 ; system
55 ;
56 ; Statements:
57 ; var=expr Assign expr value to var (a-z)
58 ;
59 ; print expr Print expression value, new line
60 ; print expr; Print expression value, continue
61 ; print "hello" Print string, new line
62 ; print "hello"; Print string, continue
63 ;
64 ; input var Input value into variable (a-z)
65 ;
66 ; goto expr Goto to indicated line in program
67 ;
68 ; if expr1 goto expr2
69 ; If expr1 is non-zero then go to line,
70 ; else go to following line.
71 ;
72 ; Examples of if:
73 ;
74 ; if c-5 goto 20 If c isn't 5, go to line 20
75 ;
76 ; Expressions:
77 ;
78 ; The operators +, -, / and * are available with
79 ; common precedence rules and signed operation.
80 ; Integer-only arithmetic.
81 ;
82 ; You can also use parentheses:
83 ;
84 ; 5+6*(10/2)
85 ;
86 ; Variables and numbers can be used in expressions.
87 ;
88 ; The rnd function (without arguments) returns a
89 ; value between 0 and 255.
90 ;
91 ; Sample program (counting 1 to 10):
92 ;
93 ; 10 a=1
94 ; 20 print a
95 ; 30 a=a+1
96 ; 40 if a-11 goto 20
97 ;
98 ; Sample program (Pascal's triangle, each number is the sum
99 ; of the two over it):
100 ;
101 ; 10 input n
102 ; 20 i=1
103 ; 30 c=1
104 ; 40 j=0
105 ; 50 t=n-i
106 ; 60 if j-t goto 80
107 ; 70 goto 110
108 ; 80 print " ";
109 ; 90 j=j+1
110 ; 100 goto 50
111 ; 110 k=1
112 ; 120 if k-i-1 goto 140
113 ; 130 goto 190
114 ; 140 print c;
115 ; 150 c=c*(i-k)/k
116 ; 160 print " ";
117 ; 170 k=k+1
118 ; 180 goto 120
119 ; 190 print
120 ; 200 i=i+1
121 ; 210 if i-n-1 goto 30
122 ;
123 ; Sample program of guessing the dice:
124 ;
125 ; 10 print "choose ";
126 ; 20 print "a number ";
127 ; 30 print "(1-6)"
128 ; 40 input a
129 ; 50 b=rnd
130 ; 60 b=b-b/6*6
131 ; 70 b=b+1
132 ; 80 if a-b goto 110
133 ; 90 print "good"
134 ; 100 goto 120
135 ; 110 print "miss"
136 ; 120 print b
137 ;
138
139 cpu 8086
140
141 %ifndef com_file ; If not defined create a boot sector
142 com_file: equ 0
143 %endif
144
145 %if com_file
146 org 0x0100
147 %else
148 org 0x7c00
149 %endif
150
151 vars: equ 0x7e00 ; Variables (multiple of 256)
152 line: equ 0x7e80 ; Line input
153
154 program: equ 0x8000 ; Program address
155 ; (notice optimizations dependent on this address)
156
157 stack: equ 0xff00 ; Stack address
158 max_line: equ 1000 ; First unavailable line number
159 max_length: equ 20 ; Maximum length of line
160 max_size: equ max_line*max_length ; Max. program size
161
162 start:
163 %if com_file
164 %else
165 00000000 0E push cs ; For boot sector
166 00000001 0E push cs ; it needs to setup
167 00000002 0E push cs ; DS, ES and SS.
168 00000003 1F pop ds
169 00000004 07 pop es
170 00000005 17 pop ss
171 %endif
172 00000006 FC cld ; Clear Direction flag
173 00000007 BF0080 mov di,program ; Point to program
174 0000000A C6050D f14: mov byte [di],0x0d ; Fill with Carriage Return (CR) character
175 0000000D 47 inc di ; Until reaching maximum 64K (DI becomes zero)
176 0000000E 75FA jne f14
177
178 ;
179 ; Main loop
180 ;
181 main_loop:
182 00000010 BC00FF mov sp,stack ; Reinitialize stack pointer
183 00000013 B8[1000] mov ax,main_loop
184 00000016 50 push ax
185 00000017 B03E mov al,'>' ; Show prompt
186 00000019 E84F01 call input_line ; Accept line
187 0000001C E81101 call input_number ; Get number
188 0000001F 09C0 or ax,ax ; No number or zero?
189 00000021 740E je statement ; Yes, jump
190 00000023 E89601 call find_line ; Find the line
191 00000026 97 xchg ax,di
192 ; mov cx,max_length ; CX loaded with this value in 'find_line'
193 00000027 F3A4 rep movsb ; Copy entered line into program
194 00000029 C3 ret
195
196 ;
197 ; Handle 'if' statement
198 ;
199 if_statement:
200 0000002A E86C00 call expr ; Process expression
201 0000002D 09C0 or ax,ax ; Is it zero?
202 0000002F 7458 je f6 ; Yes, return (ignore if)
203 statement:
204 00000031 E8E200 call spaces ; Avoid spaces
205 00000034 803C0D cmp byte [si],0x0d ; Empty line?
206 00000037 7450 je f6 ; Yes, return
207 00000039 BF[C501] mov di,statements ; Point to statements list
208 0000003C 8A05 f5: mov al,[di] ; Read length of the string
209 0000003E 47 inc di ; Avoid length byte
210 0000003F 98 cbw ; Make AH zero
211 00000040 48 dec ax ; Is it zero?
212 00000041 7413 je f4 ; Yes, jump
213 00000043 91 xchg ax,cx
214 00000044 56 push si ; Save current position
215 00000045 F3A6 f16: rep cmpsb ; Compare statement
216 00000047 7506 jne f3 ; Equal? No, jump
217 00000049 58 pop ax
218 0000004A E8C900 call spaces ; Avoid spaces
219 0000004D FF25 jmp word [di] ; Jump to process statement
220
221 0000004F 01CF f3: add di,cx ; Advance the list pointer
222 00000051 47 inc di ; Avoid the address
223 00000052 47 inc di
224 00000053 5E pop si
225 00000054 EBE6 jmp f5 ; Compare another statement
226
227 00000056 E8B400 f4: call get_variable ; Try variable
228 00000059 50 push ax ; Save address
229 0000005A AC lodsb ; Read a line letter
230 0000005B 3C3D cmp al,'=' ; Is it assignment '=' ?
231 0000005D 7434 je assignment ; Yes, jump to assignment.
232
233 ;
234 ; An error happened
235 ;
236 error:
237 0000005F BE[6700] mov si,error_message
238 00000062 E82601 call print_2 ; Show error message
239 00000065 EBA9 jmp main_loop ; Exit to main loop
240
241 error_message:
242 00000067 4023210D db "@#!",0x0d ; Guess the words :P
243
244 ;
245 ; Handle 'list' statement
246 ;
247 list_statement:
248 0000006B 31C0 xor ax,ax ; Start from line zero
249 0000006D 50 f29: push ax
250 0000006E E84B01 call find_line ; Find program line
251 00000071 96 xchg ax,si
252 00000072 803C0D cmp byte [si],0x0d ; Empty line?
253 00000075 740B je f30 ; Yes, jump
254 00000077 58 pop ax
255 00000078 50 push ax
256 00000079 E8A000 call output_number ; Show line number
257 0000007C AC f32: lodsb ; Show line contents
258 0000007D E82901 call output
259 00000080 75FA jne f32 ; Jump if it wasn't 0x0d (CR)
260 00000082 58 f30: pop ax
261 00000083 40 inc ax ; Go to next line
262 00000084 3DE803 cmp ax,max_line ; Finished?
263 00000087 75E4 jne f29 ; No, continue
264 f6:
265 00000089 C3 ret
266
267 ;
268 ; Handle 'input' statement
269 ;
270 input_statement:
271 0000008A E88000 call get_variable ; Get variable address
272 0000008D 50 push ax ; Save it
273 0000008E B03F mov al,'?' ; Prompt
274 00000090 E8D800 call input_line ; Wait for line
275 ;
276 ; Second part of the assignment statement
277 ;
278 assignment:
279 00000093 E80300 call expr ; Process expression
280 00000096 5F pop di
281 00000097 AB stosw ; Save onto variable
282 00000098 C3 ret
283
284 ;
285 ; Handle an expression.
286 ; First tier: addition & subtraction.
287 ;
288 expr:
289 00000099 E81C00 call expr1 ; Call second tier
290 0000009C 803C2D f20: cmp byte [si],'-' ; Subtraction operator?
291 0000009F 740E je f19 ; Yes, jump
292 000000A1 803C2B cmp byte [si],'+' ; Addition operator?
293 000000A4 75E3 jne f6 ; No, return
294 000000A6 50 push ax
295 000000A7 E80D00 call expr1_2 ; Call second tier
296 000000AA 59 f15: pop cx
297 000000AB 01C8 add ax,cx ; Addition
298 000000AD EBED jmp f20 ; Find more operators
299
300 f19:
301 000000AF 50 push ax
302 000000B0 E80400 call expr1_2 ; Call second tier
303 000000B3 F7D8 neg ax ; Negate it (a - b converted to a + -b)
304 000000B5 EBF3 jmp f15
305
306 ;
307 ; Handle an expression.
308 ; Second tier: division & multiplication.
309 ;
310 expr1_2:
311 000000B7 46 inc si ; Avoid operator
312 expr1:
313 000000B8 E81F00 call expr2 ; Call third tier
314 000000BB 803C2F f21: cmp byte [si],'/' ; Division operator?
315 000000BE 740E je f23 ; Yes, jump
316 000000C0 803C2A cmp byte [si],'*' ; Multiplication operator?
317 000000C3 75C4 jne f6 ; No, return
318
319 000000C5 50 push ax
320 000000C6 E81000 call expr2_2 ; Call third tier
321 000000C9 59 pop cx
322 000000CA F7E9 imul cx ; Multiplication
323 000000CC EBED jmp f21 ; Find more operators
324
325 f23:
326 000000CE 50 push ax
327 000000CF E80700 call expr2_2 ; Call third tier
328 000000D2 59 pop cx
329 000000D3 91 xchg ax,cx
330 000000D4 99 cwd ; Expand AX to DX:AX
331 000000D5 F7F9 idiv cx ; Signed division
332 000000D7 EBE2 jmp f21 ; Find more operators
333
334 ;
335 ; Handle an expression.
336 ; Third tier: parentheses, numbers and vars.
337 ;
338 expr2_2:
339 000000D9 46 inc si ; Avoid operator
340 expr2:
341 000000DA E83900 call spaces ; Jump spaces
342 000000DD AC lodsb ; Read character
343 000000DE 3C28 cmp al,'(' ; Open parenthesis?
344 000000E0 750B jne f24
345 000000E2 E8B4FF call expr ; Process inner expr.
346 000000E5 803C29 cmp byte [si],')' ; Closing parenthesis?
347 000000E8 742B je spaces_2 ; Yes, avoid spaces
348 000000EA E972FF jmp error ; No, jump to error
349
350 000000ED 3C40 f24: cmp al,0x40 ; Variable?
351 000000EF 7306 jnc f25 ; Yes, jump
352 000000F1 4E dec si ; Back one letter...
353 000000F2 E83B00 call input_number ; ...to read number
354 000000F5 EB1F jmp short spaces
355
356 000000F7 3C72 f25: cmp al,0x72
357 000000F9 750B jne f22
358 000000FB 803C6E cmp byte [si],0x6e
359 000000FE 7506 jne f22
360 00000100 AD lodsw ; Advance SI by 2
361 00000101 E440 in al,0x40 ; Read timer counter 0
362 00000103 B400 mov ah,0
363 00000105 C3 ret
364
365 00000106 E80500 f22: call get_variable_2 ; Get variable address
366 00000109 93 xchg ax,bx
367 0000010A 8B07 mov ax,[bx] ; Read
368 0000010C C3 ret ; Return
369
370 ;
371 ; Get variable address.
372 ; Also avoid spaces.
373 ;
374 get_variable:
375 0000010D AC lodsb ; Read source
376 get_variable_2:
377 0000010E 241F and al,0x1f ; 0x61-0x7a -> 0x01-0x1a
378 00000110 00C0 add al,al ; x 2 (each variable = word)
379 00000112 B47E mov ah,vars>>8 ; Setup high-byte of address
380 00000114 4E dec si
381 ;
382 ; Avoid spaces after current character
383 ;
384 spaces_2:
385 00000115 46 inc si
386 ;
387 ; Avoid spaces
388 ; The interpreter depends on this routine not modifying AX
389 ;
390 spaces:
391 00000116 803C20 cmp byte [si],' ' ; Space found?
392 00000119 74FA je spaces_2 ; Yes, move one character ahead.
393 0000011B C3 ret ; No, return.
394
395 ;
396 ; Output unsigned number
397 ; AX = value
398 ;
399 output_number:
400 f26:
401 0000011C 31D2 xor dx,dx ; DX:AX
402 0000011E B90A00 mov cx,10 ; Divisor = 10
403 00000121 F7F1 div cx ; Divide
404 00000123 09C0 or ax,ax ; Nothing at left?
405 00000125 52 push dx
406 00000126 7403 je f8 ; No, jump
407 00000128 E8F1FF call f26 ; Yes, output left side
408 0000012B 58 f8: pop ax
409 0000012C 0430 add al,'0' ; Output remainder as...
410 0000012E EB79 jmp short output ; ...ASCII digit
411
412 ;
413 ; Read number in input.
414 ; AX = result
415 ;
416 input_number:
417 00000130 31DB xor bx,bx ; BX = 0
418 00000132 AC f11: lodsb ; Read source
419 00000133 2C30 sub al,'0'
420 00000135 3C0A cmp al,10 ; Digit valid?
421 00000137 98 cbw
422 00000138 93 xchg ax,bx
423 00000139 7309 jnc f12 ; No, jump
424 0000013B B90A00 mov cx,10 ; Multiply by 10
425 0000013E F7E1 mul cx
426 00000140 01C3 add bx,ax ; Add new digit
427 00000142 EBEE jmp f11 ; Continue
428
429 00000144 4E f12: dec si ; SI points to first non-digit
430 00000145 C3 ret
431
432 ;
433 ; Handle 'system' statement
434 ;
435 system_statement:
436 00000146 CD20 int 0x20
437
438 ;
439 ; Handle 'goto' statement
440 ;
441 goto_statement:
442 00000148 E84EFF call expr ; Handle expression
443 0000014B B9 db 0xb9 ; MOV CX to jump over XOR AX,AX
444
445 ;
446 ; Handle 'run' statement
447 ; (equivalent to 'goto 0')
448 ;
449 run_statement:
450 0000014C 31C0 xor ax,ax
451 f10:
452 0000014E E86B00 call find_line ; Find line in program
453 00000151 81FCFEFE f27: cmp sp,stack-2 ; In interactive mode?
454 00000155 7404 je f31 ; Yes, jump.
455 00000157 A3FCFE mov [stack-4],ax ; No, replace the saved address of next line
456 0000015A C3 ret
457 f31:
458 0000015B 50 push ax
459 0000015C 5E pop si
460 0000015D 051400 add ax,max_length ; Point to next line
461 00000160 50 push ax ; Save for next time (this goes into address stack-4)
462 00000161 E8CDFE call statement ; Process current statement
463 00000164 58 pop ax ; Restore address of next line (could have changed)
464 00000165 3D20CE cmp ax,program+max_size ; Reached the end?
465 00000168 75F1 jne f31 ; No, continue
466 0000016A C3 ret ; Yes, return
467
468 ;
469 ; Input line from keyboard
470 ; Entry:
471 ; al = prompt character
472 ; Result:
473 ; buffer 'line' contains line, finished with CR
474 ; SI points to 'line'.
475 ;
476 input_line:
477 0000016B E83B00 call output
478 0000016E BE807E mov si,line
479 00000171 56 push si
480 00000172 5F pop di ; Target for writing line
481 00000173 E82F00 f1: call input_key ; Read keyboard
482 00000176 AA stosb ; Save key in buffer
483 00000177 3C08 cmp al,0x08 ; Backspace?
484 00000179 7502 jne f2 ; No, jump
485 0000017B 4F dec di ; Get back one character
486 0000017C 4F dec di
487 0000017D 3C0D f2: cmp al,0x0d ; CR pressed?
488 0000017F 75F2 jne f1 ; No, wait another key
489 00000181 C3 ret ; Yes, return
490
491 ;
492 ; Handle "print" statement
493 ;
494 print_statement:
495 00000182 AC lodsb ; Read source
496 00000183 3C0D cmp al,0x0d ; End of line?
497 00000185 7426 je new_line ; Yes, generate new line and return
498 00000187 3C22 cmp al,'"' ; Double quotes?
499 00000189 750D jne f7 ; No, jump
500 print_2:
501 f9:
502 0000018B AC lodsb ; Read string contents
503 0000018C 3C22 cmp al,'"' ; Double quotes?
504 0000018E 740F je f18 ; Yes, jump
505 00000190 E81600 call output ; Output character
506 00000193 3C0D cmp al,0x0d ;
507 00000195 75F4 jne f9 ; Jump if not finished with 0x0d (CR)
508 00000197 C3 ret ; Return
509
510 00000198 4E f7: dec si
511 00000199 E8FDFE call expr ; Handle expression
512 0000019C E87DFF call output_number ; Output result
513 0000019F AC f18: lodsb ; Read next character
514 000001A0 3C3B cmp al,';' ; Is it semicolon?
515 000001A2 7509 jne new_line ; No, jump to generate new line
516 000001A4 C3 ret ; Yes, return
517
518 ;
519 ; Read a key into al
520 ; Also outputs it to screen
521 ;
522 input_key:
523 000001A5 B400 mov ah,0x00
524 000001A7 CD16 int 0x16
525 ;
526 ; Screen output of character contained in al
527 ; Expands 0x0d (CR) into 0x0a 0x0d (LF CR)
528 ;
529 output:
530 000001A9 3C0D cmp al,0x0d
531 000001AB 7507 jne f17
532 ;
533 ; Go to next line (generates LF+CR)
534 ;
535 new_line:
536 000001AD B00A mov al,0x0a
537 000001AF E80200 call f17
538 000001B2 B00D mov al,0x0d
539 f17:
540 000001B4 B40E mov ah,0x0e
541 000001B6 BB0700 mov bx,0x0007
542 000001B9 CD10 int 0x10
543 000001BB C3 ret
544
545 ;
546 ; Find line in program
547 ; Entry:
548 ; ax = line number
549 ; Result:
550 ; ax = pointer to program.
551 ; cx = max. length allowed for line.
552 find_line:
553 000001BC B91400 mov cx,max_length
554 000001BF F7E1 mul cx
555 000001C1 050080 add ax,program
556 000001C4 C3 ret
557
558 ;
559 ; List of statements of bootBASIC
560 ; First one byte with length of string
561 ; Then string with statement
562 ; Then a word with the address of the code
563 ;
564 statements:
565 000001C5 046E6577 db 4,"new"
566 000001C9 [0000] dw start
567
568 000001CB 056C697374 db 5,"list"
569 000001D0 [6B00] dw list_statement
570
571 000001D2 0472756E db 4,"run"
572 000001D6 [4C01] dw run_statement
573
574 000001D8 067072696E74 db 6,"print"
575 000001DE [8201] dw print_statement
576
577 000001E0 06696E707574 db 6,"input"
578 000001E6 [8A00] dw input_statement
579
580 000001E8 036966 db 3,"if"
581 000001EB [2A00] dw if_statement
582
583 000001ED 05676F746F db 5,"goto"
584 000001F2 [4801] dw goto_statement
585
586 000001F4 0773797374656D db 7,"system"
587 000001FB [4601] dw system_statement
588
589 000001FD 01 db 1
590
591 ;
592 ; Boot sector filler
593 ;
594 %if com_file
595 %else
596 times 510-($-$$) db 0x4f
597 000001FE 55AA db 0x55,0xaa ; Make it a bootable sector
598 %endif
599