* mikeOS 16 bit and amd64 baremetal
[mascara-docs.git] / amd64 / bareMetalOS-0.5.3 / programs / mbasic.asm
blob385a460c7b512af9c15b6a757c391ccf62e15e60
1 ; ==================================================================
2 ; MikeOS -- The Mike Operating System kernel
3 ; Copyright (C) 2006 - 2011 MikeOS Developers -- see doc/LICENSE.TXT
5 ; BASIC CODE INTERPRETER
6 ; ==================================================================
9 [BITS 64]
10 [ORG 0x0000000000200000]
12 %INCLUDE "bmdev.asm"
14 ; ------------------------------------------------------------------
15 ; Token types
17 %DEFINE VARIABLE 1
18 %DEFINE STRING_VAR 2
19 %DEFINE NUMBER 3
20 %DEFINE STRING 4
21 %DEFINE QUOTE 5
22 %DEFINE CHAR 6
23 %DEFINE UNKNOWN 7
24 %DEFINE LABEL 8
27 ; ------------------------------------------------------------------
28 ; The BASIC interpreter execution starts here...
30 b_run_basic:
31 mov [orig_stack], rsp ; Save stack pointer -- we might jump to the
32 ; error printing code and quit in the middle
33 ; some nested loops, and we want to preserve
34 ; the stack
35 mov rax, basic_prog ;embedded test program for a quick DOS test
36 mov rbx, 8192 ;default size for test program (not critical)
37 mov [load_point], rax ; rax was passed as starting location of code
39 mov [prog], rax ; prog = pointer to current execution point in code
41 add rbx, rax ; We were passed the .BAS byte size in rbx
42 sub rbx, 2
43 mov [prog_end], rbx ; Make note of program end point
46 call clear_ram ; Clear variables etc. from previous run
47 ; of a BASIC program
51 mainloop:
52 call get_token ; Get a token from the start of the line
54 cmp rax, STRING ; Is the type a string of characters?
55 je .keyword ; If so, let's see if it's a keyword to process
57 cmp rax, VARIABLE ; If it's a variable at the start of the line,
58 je near assign ; this is an assign (eg "X = Y + 5")
60 cmp rax, STRING_VAR ; Same for a string variable (eg $1)
61 je near assign
63 cmp rax, LABEL ; Don't need to do anything here - skip
64 je mainloop
66 mov rsi, err_syntax ; Otherwise show an error and quit
67 jmp error
70 .keyword:
71 mov rsi, token ; Start trying to match commands
73 mov rdi, alert_cmd
74 call b_string_compare
75 jc near do_alert
77 mov rdi, call_cmd
78 call b_string_compare
79 jc near do_call
81 mov rdi, cls_cmd
82 call b_string_compare
83 jc near do_cls
85 mov rdi, cursor_cmd
86 call b_string_compare
87 jc near do_cursor
89 mov rdi, curschar_cmd
90 call b_string_compare
91 jc near do_curschar
93 mov rdi, end_cmd
94 call b_string_compare
95 jc near do_end
97 mov rdi, for_cmd
98 call b_string_compare
99 jc near do_for
101 mov rdi, getkey_cmd
102 call b_string_compare
103 jc near do_getkey
105 mov rdi, gosub_cmd
106 call b_string_compare
107 jc near do_gosub
109 mov rdi, goto_cmd
110 call b_string_compare
111 jc near do_goto
113 mov rdi, input_cmd
114 call b_string_compare
115 jc near do_input
117 mov rdi, if_cmd
118 call b_string_compare
119 jc near do_if
121 mov rdi, load_cmd
122 call b_string_compare
123 jc near do_load
125 mov rdi, move_cmd
126 call b_string_compare
127 jc near do_move
129 mov rdi, next_cmd
130 call b_string_compare
131 jc near do_next
133 mov rdi, pause_cmd
134 call b_string_compare
135 jc near do_pause
137 mov rdi, peek_cmd
138 call b_string_compare
139 jc near do_peek
141 mov rdi, poke_cmd
142 call b_string_compare
143 jc near do_poke
145 mov rdi, port_cmd
146 call b_string_compare
147 jc near do_port
149 mov rdi, print_cmd
150 call b_string_compare
151 jc near do_print
153 mov rdi, rand_cmd
154 call b_string_compare
155 jc near do_rand
157 mov rdi, rem_cmd
158 call b_string_compare
159 jc near do_rem
161 mov rdi, return_cmd
162 call b_string_compare
163 jc near do_return
165 mov rdi, save_cmd
166 call b_string_compare
167 jc near do_save
169 mov rdi, serial_cmd
170 call b_string_compare
171 jc near do_serial
173 mov rdi, sound_cmd
174 call b_string_compare
175 jc near do_sound
177 mov rdi, waitkey_cmd
178 call b_string_compare
179 jc near do_waitkey
181 mov rsi, err_cmd_unknown ; Command not found?
182 jmp error
185 ; ------------------------------------------------------------------
186 ; CLEAR RAM
188 clear_ram:
189 xor eax, eax
191 mov rdi, variables
192 mov rcx, 52
193 rep stosb
195 mov rdi, for_variables
196 mov rcx, 52
197 rep stosb
199 mov rdi, for_code_points
200 mov rcx, 52
201 rep stosb
203 mov byte [gosub_depth], 0
205 mov rdi, gosub_points
206 mov rcx, 20
207 rep stosb
209 mov rdi, string_vars
210 mov rcx, 1024
211 rep stosb
216 ; ------------------------------------------------------------------
217 ; ASSIGNMENT
219 assign:
220 cmp rax, VARIABLE ; Are we starting with a number var?
221 je .do_num_var
223 mov rdi, string_vars ; Otherwise it's a string var
224 mov rax, 128
225 mul rbx ; (rbx = string number, passed back from get_token)
226 add rdi, rax
228 push rdi
230 call get_token
231 mov byte al, [token]
232 cmp al, '='
233 jne near .error
235 call get_token
236 cmp rax, QUOTE
237 je .second_is_quote
239 cmp rax, STRING_VAR
240 jne near .error
242 mov rsi, string_vars ; Otherwise it's a string var
243 mov rax, 128
244 mul rbx ; (rbx = string number, passed back from get_token)
245 add rsi, rax
247 pop rdi
248 call b_string_copy
250 jmp mainloop
253 .second_is_quote:
254 mov rsi, token
255 pop rdi
256 call b_string_copy
258 jmp mainloop
261 .do_num_var:
262 xor rax, rax
263 mov byte al, [token]
264 mov byte [.tmp], al
266 call get_token
267 mov byte al, [token]
268 cmp al, '='
269 jne near .error
271 call get_token
272 cmp rax, NUMBER
273 je .second_is_num
275 cmp rax, VARIABLE
276 je .second_is_variable
278 cmp rax, STRING
279 je near .second_is_string
281 cmp rax, UNKNOWN
282 jne near .error
284 mov byte al, [token] ; Address of string var?
285 cmp al, '&'
286 jne near .error
288 call get_token ; Let's see if there's a string var
289 cmp rax, STRING_VAR
290 jne near .error
292 mov rdi, string_vars
293 mov rax, 128
294 mul rbx
295 add rdi, rax
297 mov rbx, rdi
299 mov byte al, [.tmp]
300 call set_var
302 jmp mainloop
305 .second_is_variable:
306 xor rax, rax
307 mov byte al, [token]
309 call get_var
310 mov rbx, rax
311 mov byte al, [.tmp]
312 call set_var
314 jmp .check_for_more
317 .second_is_num:
318 mov rsi, token
319 call b_string_to_int
321 mov rbx, rax ; Number to insert in variable table
323 xor rax, rax
324 mov byte al, [.tmp]
326 call set_var
329 ; The assignment could be simply "X = 5" etc. Or it could be
330 ; "X = Y + 5" -- ie more complicated. So here we check to see if
331 ; there's a delimiter...
333 .check_for_more:
334 mov rax, [prog] ; Save code location in case there's no delimiter
335 mov [.tmp_loc], rax
337 call get_token ; Any more to deal with in this assignment?
338 mov byte al, [token]
339 cmp al, '+'
340 je .theres_more
341 cmp al, '-'
342 je .theres_more
343 cmp al, '*'
344 je .theres_more
345 cmp al, '/'
346 je .theres_more
347 cmp al, '%'
348 je .theres_more
350 mov rax, [.tmp_loc] ; Not a delimiter, so step back before the token
351 mov [prog], rax ; that we just grabbed
353 jmp mainloop ; And go back to the code interpreter!
356 .theres_more:
357 mov byte [.delim], al
359 call get_token
360 cmp rax, VARIABLE
361 je .handle_variable
363 mov rsi, token
364 call b_string_to_int
365 mov rbx, rax
367 xor rax, rax
368 mov byte al, [.tmp]
370 call get_var ; This also points rsi at right place in variable table
372 cmp byte [.delim], '+'
373 jne .not_plus
375 add rax, rbx
376 jmp .finish
378 .not_plus:
379 cmp byte [.delim], '-'
380 jne .not_minus
382 sub rax, rbx
383 jmp .finish
385 .not_minus:
386 cmp byte [.delim], '*'
387 jne .not_times
389 mul rbx
390 jmp .finish
392 .not_times:
393 cmp byte [.delim], '/'
394 jne .not_divide
396 xor rdx, rdx
397 div rbx
398 jmp .finish
400 .not_divide:
401 xor rdx, rdx
402 div rbx
403 mov rax, rdx ; Get remainder
405 .finish:
406 mov rbx, rax
407 mov byte al, [.tmp]
408 call set_var
410 jmp .check_for_more
413 .handle_variable:
414 xor rax, rax
415 mov byte al, [token]
417 call get_var
419 mov rbx, rax
421 xor rax, rax
422 mov byte al, [.tmp]
424 call get_var
426 cmp byte [.delim], '+'
427 jne .vnot_plus
429 add rax, rbx
430 jmp .vfinish
432 .vnot_plus:
433 cmp byte [.delim], '-'
434 jne .vnot_minus
436 sub rax, rbx
437 jmp .vfinish
439 .vnot_minus:
440 cmp byte [.delim], '*'
441 jne .vnot_times
443 mul rbx
444 jmp .vfinish
446 .vnot_times:
447 cmp byte [.delim], '/'
448 jne .vnot_divide
450 mov dx, 0
451 div rbx
452 jmp .finish
454 .vnot_divide:
455 mov dx, 0
456 div rbx
457 mov rax, rdx ; Get remainder
459 .vfinish:
460 mov rbx, rax
461 mov byte al, [.tmp]
462 call set_var
464 jmp .check_for_more
467 .second_is_string:
468 mov rdi, token
469 mov rsi, progstart_keyword
470 call b_string_compare
471 je .is_progstart
473 mov rsi, ramstart_keyword
474 call b_string_compare
475 je .is_ramstart
477 jmp .error
479 .is_progstart:
480 xor rax, rax
481 mov byte al, [.tmp]
483 mov rbx, [load_point]
484 call set_var
486 jmp mainloop
490 .is_ramstart:
491 xor rax, rax
492 mov byte al, [.tmp]
494 mov rbx, [prog_end]
495 inc rbx
496 inc rbx
497 inc rbx
498 call set_var
500 jmp mainloop
503 .error:
504 mov rsi, err_syntax
505 jmp error
508 .tmp db 0
509 .tmp_loc dq 0
510 .delim db 0
513 ; ==================================================================
514 ; SPECIFIC COMMAND CODE STARTS HERE
516 ; ------------------------------------------------------------------
517 ; ALERT
519 do_alert:
520 call get_token
522 cmp rax, QUOTE
523 je .is_quote
525 mov rsi, err_syntax
526 jmp error
528 .is_quote:
529 mov rax, token ; First string for alert box
530 xor rbx, rbx ; Others are blank
531 xor rcx, rcx
532 mov dx, 0 ; One-choice box
533 jmp mainloop
536 ; ------------------------------------------------------------------
537 ; CALL
539 do_call:
540 call get_token
541 cmp rax, NUMBER
542 je .is_number
544 xor rax, rax
545 mov byte al, [token]
546 call get_var
547 jmp .execute_call
549 .is_number:
550 mov rsi, token
551 call b_string_to_int
553 .execute_call:
554 xor rbx, rbx
555 xor rcx, rcx
556 mov dx, 0
557 mov rdi, 0
558 mov rsi, 0
560 call rax
562 jmp mainloop
566 ; ------------------------------------------------------------------
567 ; CLS
569 do_cls:
570 call b_screen_clear
571 jmp mainloop
574 ; ------------------------------------------------------------------
575 ; CURSOR
577 do_cursor:
578 call get_token
580 mov rsi, token
581 mov rdi, .on_str
582 call b_string_compare
583 jc .turn_on
585 mov rsi, token
586 mov rdi, .off_str
587 call b_string_compare
588 jc .turn_off
590 mov rsi, err_syntax
591 jmp error
593 .turn_on:
594 call b_show_cursor
595 jmp mainloop
597 .turn_off:
598 call b_hide_cursor
599 jmp mainloop
602 .on_str db "ON", 0
603 .off_str db "OFF", 0
606 ; ------------------------------------------------------------------
607 ; CURSCHAR
609 do_curschar:
610 call get_token
612 cmp rax, VARIABLE
613 je .is_ok
615 mov rsi, err_syntax
616 jmp error
618 .is_ok:
619 xor rax, rax
620 mov byte al, [token]
622 push rax ; Store variable we're going to use
624 ; mov ah, 08h
625 ; xor rbx, rbx
626 ; int 10h ; Get char at current cursor location
628 xor rbx, rbx ; We only want the lower byte (the char, not attribute)
629 mov bl, al
631 pop rax ; Get the variable back
633 call set_var ; And store the value
635 jmp mainloop
638 ; ------------------------------------------------------------------
639 ; END
641 do_end:
642 mov rsp, [orig_stack]
646 ; ------------------------------------------------------------------
647 ; FOR
649 do_for:
650 call get_token ; Get the variable we're using in this loop
652 cmp rax, VARIABLE
653 jne near .error
655 xor rax, rax
656 mov byte al, [token]
657 mov byte [.tmp_var], al ; Store it in a temporary location for now
659 call get_token
661 xor rax, rax ; Check it's followed up with '='
662 mov byte al, [token]
663 cmp al, '='
664 jne .error
666 call get_token ; Next we want a number
668 cmp rax, NUMBER
669 jne .error
671 mov rsi, token ; Convert it
672 call b_string_to_int
675 ; At this stage, we've read something like "FOR X = 1"
676 ; so let's store that 1 in the variable table
678 mov rbx, rax
679 xor rax, rax
680 mov byte al, [.tmp_var]
681 call set_var
684 call get_token ; Next we're looking for "TO"
686 cmp rax, STRING
687 jne .error
689 mov rax, token
690 call b_string_uppercase
692 mov rsi, token
693 mov rdi, .to_string
694 call b_string_compare
695 jnc .error
697 ; So now we're at "FOR X = 1 TO"
699 call get_token
701 cmp rax, NUMBER
702 jne .error
704 mov rsi, token ; Get target number
705 call b_string_to_int
707 mov rbx, rax
709 xor rax, rax
710 mov byte al, [.tmp_var]
712 sub al, 65 ; Store target number in table
713 mov rdi, for_variables
714 add rdi, rax
715 add rdi, rax
716 mov rax, rbx
717 stosw
720 ; So we've got the variable, assigned it the starting number, and put into
721 ; our table the limit it should reach. But we also need to store the point in
722 ; code after the FOR line we should return to if NEXT X doesn't complete the loop...
723 ; xor rax, rax
724 xor rax, rax
725 ; xor eax, eax
726 mov byte al, [.tmp_var]
728 sub al, 65 ; Store code position to return to in table
729 mov rdi, for_code_points
730 ; add rdi, rax
731 ; add rdi, rax
732 shl rax, 3
733 add rdi, rax
734 mov rax, [prog]
735 stosq
737 jmp mainloop
740 .error:
741 mov rsi, err_syntax
742 jmp error
745 .tmp_var db 0
746 .to_string db 'TO', 0
749 ; ------------------------------------------------------------------
750 ; GETKEY
752 do_getkey:
753 call get_token
754 cmp rax, VARIABLE
755 je .is_variable
757 mov rsi, err_syntax
758 jmp error
760 .is_variable:
761 xor rax, rax
762 mov byte al, [token]
764 push rax
766 call b_input_key_check
768 xor rbx, rbx
769 mov bl, al
771 pop rax
773 call set_var
775 jmp mainloop
778 ; ------------------------------------------------------------------
779 ; GOSUB
781 do_gosub:
782 call get_token ; Get the number (label)
784 cmp rax, STRING
785 je .is_ok
787 mov rsi, err_goto_notlabel
788 jmp error
790 .is_ok:
791 mov rsi, token ; Back up this label
792 mov rdi, .tmp_token
793 call b_string_copy
795 mov rax, .tmp_token
796 call b_string_length
798 mov rdi, .tmp_token ; Add ':' char to end for searching
799 add rdi, rax
800 mov al, ':'
801 stosb
802 mov al, 0
803 stosb
805 inc byte [gosub_depth]
807 xor rax, rax
808 mov byte al, [gosub_depth] ; Get current GOSUB nest level
810 cmp al, 9
811 jle .within_limit
813 mov rsi, err_nest_limit
814 jmp error
816 .within_limit:
817 mov rdi, gosub_points ; Move into our table of pointers
818 add rdi, rax ; Table is words (not bytes)
819 add rdi, rax
820 mov rax, [prog]
821 stosw ; Store current location before jump
824 mov rax, [load_point]
825 mov [prog], rax ; Return to start of program to find label
827 .loop:
828 call get_token
830 cmp rax, LABEL
831 jne .line_loop
833 mov rsi, token
834 mov rdi, .tmp_token
835 call b_string_compare
836 jc mainloop
838 .line_loop: ; Go to end of line
839 mov rsi, [prog]
840 mov byte al, [rsi]
841 inc qword [prog]
842 cmp al, 10
843 jne .line_loop
845 mov rax, [prog]
846 mov rbx, [prog_end]
847 cmp rax, rbx
848 jg .past_end
850 jmp .loop
852 .past_end:
853 mov rsi, err_label_notfound
854 jmp error
856 .tmp_token times 30 db 0
859 ; ------------------------------------------------------------------
860 ; GOTO
862 do_goto:
863 call get_token ; Get the next token
865 cmp rax, STRING
866 je .is_ok
868 mov rsi, err_goto_notlabel
869 jmp error
871 .is_ok:
872 mov rsi, token ; Back up this label
873 mov rdi, .tmp_token
874 call b_string_copy
876 mov rax, .tmp_token
877 call b_string_length
879 mov rdi, .tmp_token ; Add ':' char to end for searching
880 add rdi, rax
881 mov al, ':'
882 stosb
883 mov al, 0
884 stosb
886 mov rax, [load_point]
887 mov [prog], rax ; Return to start of program to find label
889 .loop:
890 call get_token
892 cmp rax, LABEL
893 jne .line_loop
895 mov rsi, token
896 mov rdi, .tmp_token
897 call b_string_compare
898 jc mainloop
900 .line_loop: ; Go to end of line
901 mov rsi, [prog]
902 mov byte al, [rsi]
903 inc qword [prog]
905 cmp al, 10
906 jne .line_loop
908 mov rax, [prog]
909 mov rbx, [prog_end]
910 cmp rax, rbx
911 jg .past_end
913 jmp .loop
915 .past_end:
916 mov rsi, err_label_notfound
917 jmp error
919 .tmp_token times 30 db 0
922 ; ------------------------------------------------------------------
923 ; IF
925 do_if:
926 call get_token
928 cmp rax, VARIABLE ; If can only be followed by a variable
929 je .num_var
931 cmp rax, STRING_VAR
932 je near .string_var
934 mov rsi, err_syntax
935 jmp error
937 .num_var:
938 xor rax, rax
939 mov byte al, [token]
940 call get_var
942 mov rdx, rax ; Store value of first part of comparison
944 call get_token ; Get the delimiter
945 mov byte al, [token]
946 cmp al, '='
947 je .equals
948 cmp al, '>'
949 je .greater
950 cmp al, '<'
951 je .less
953 mov rsi, err_syntax ; If not one of the above, error out
954 jmp error
956 .equals:
957 call get_token ; Is this 'X = Y' (equals another variable?)
959 cmp rax, CHAR
960 je .equals_char
962 mov byte al, [token]
963 call is_letter
964 jc .equals_var
966 mov rsi, token ; Otherwise it's, eg 'X = 1' (a number)
967 call b_string_to_int
969 cmp rax, rdx ; On to the THEN bit if 'X = num' matches
970 je near .on_to_then
972 jmp .finish_line ; Otherwise skip the rest of the line
974 .equals_char:
975 xor rax, rax
976 mov byte al, [token]
978 cmp rax, rdx
979 je near .on_to_then
981 jmp .finish_line
983 .equals_var:
984 xor rax, rax
985 mov byte al, [token]
987 call get_var
989 cmp rax, rdx ; Do the variables match?
990 je near .on_to_then ; On to the THEN bit if so
992 jmp .finish_line ; Otherwise skip the rest of the line
994 .greater:
995 call get_token ; Greater than a variable or number?
996 mov byte al, [token]
997 call is_letter
998 jc .greater_var
1000 mov rsi, token ; Must be a number here...
1001 call b_string_to_int
1003 cmp rax, rdx
1004 jl near .on_to_then
1006 jmp .finish_line
1008 .greater_var: ; Variable in this case
1009 xor rax, rax
1010 mov byte al, [token]
1012 call get_var
1014 cmp rax, rdx ; Make the comparison!
1015 jl .on_to_then
1017 jmp .finish_line
1019 .less:
1020 call get_token
1021 mov byte al, [token]
1022 call is_letter
1023 jc .less_var
1025 mov rsi, token
1026 call b_string_to_int
1028 cmp rax, rdx
1029 jg .on_to_then
1031 jmp .finish_line
1033 .less_var:
1034 xor rax, rax
1035 mov byte al, [token]
1037 call get_var
1039 cmp rax, rdx
1040 jg .on_to_then
1042 jmp .finish_line
1044 .string_var:
1045 mov byte [.tmp_string_var], bl
1047 call get_token
1049 mov byte al, [token]
1050 cmp al, '='
1051 jne .error
1053 call get_token
1054 cmp rax, STRING_VAR
1055 je .second_is_string_var
1057 cmp rax, QUOTE
1058 jne .error
1060 mov rsi, string_vars
1061 mov rax, 128
1062 mul rbx
1063 add rsi, rax
1064 mov rdi, token
1065 call b_string_compare
1066 je .on_to_then
1068 jmp .finish_line
1070 .second_is_string_var:
1071 mov rsi, string_vars
1072 mov rax, 128
1073 mul rbx
1074 add rsi, rax
1076 mov rdi, string_vars
1077 xor rbx, rbx
1078 mov byte bl, [.tmp_string_var]
1079 mov rax, 128
1080 mul rbx
1081 add rdi, rax
1083 call b_string_compare
1084 jc .on_to_then
1086 jmp .finish_line
1088 .on_to_then:
1089 call get_token
1091 mov rsi, token
1092 mov rdi, then_keyword
1093 call b_string_compare
1095 jc .then_present
1097 mov rsi, err_syntax
1098 jmp error
1100 .then_present: ; Continue rest of line like any other command!
1101 jmp mainloop
1103 .finish_line: ; IF wasn't fulfilled, so skip rest of line
1104 mov rsi, [prog]
1105 mov byte al, [rsi]
1106 inc qword [prog]
1107 cmp al, 10
1108 jne .finish_line
1110 jmp mainloop
1112 .error:
1113 mov rsi, err_syntax
1114 jmp error
1116 .tmp_string_var db 0
1119 ; ------------------------------------------------------------------
1120 ; INPUT
1122 do_input:
1123 mov al, 0 ; Clear string from previous usage
1124 mov rdi, .tmpstring
1125 mov rcx, 128
1126 rep stosb
1128 call get_token
1130 cmp rax, VARIABLE ; We can only INPUT to variables!
1131 je .number_var
1133 cmp rax, STRING_VAR
1134 je .string_var
1136 mov rsi, err_syntax
1137 jmp error
1139 .number_var:
1140 mov rdi, .tmpstring ; Get input from the user
1141 mov rcx, 50
1142 call b_input_string
1144 mov rsi, .tmpstring
1145 call b_string_length
1146 cmp rcx, 0
1147 jne .char_entered
1149 mov byte [.tmpstring], '0' ; If enter hit, fill variable with zero
1150 mov byte [.tmpstring + 1], 0
1152 .char_entered:
1153 mov rsi, .tmpstring ; Convert to integer format
1154 call b_string_to_int
1155 mov rbx, rax
1157 xor rax, rax
1158 mov byte al, [token] ; Get the variable where we're storing it...
1159 call set_var ; ...and store it!
1161 call b_print_newline
1163 jmp mainloop
1165 .string_var:
1166 push rbx
1168 mov rdi, .tmpstring
1169 mov rcx, 50
1170 call b_input_string
1172 mov rsi, .tmpstring
1173 mov rdi, string_vars
1175 pop rbx
1177 mov rax, 128
1178 mul rbx
1180 add rdi, rax
1181 call b_string_copy
1183 call b_print_newline
1185 jmp mainloop
1187 .tmpstring times 128 db 0
1190 ; ------------------------------------------------------------------
1191 ; LOAD
1193 do_load:
1194 call get_token
1195 cmp rax, QUOTE
1196 je .is_quote
1198 cmp rax, STRING_VAR
1199 jne .error
1201 mov rsi, string_vars
1202 mov rax, 128
1203 mul rbx
1204 add rsi, rax
1205 jmp .get_position
1207 .is_quote:
1208 mov rsi, token
1210 .get_position:
1211 mov rax, rsi
1212 ; call b_file_exists
1213 jc .file_not_exists
1215 mov rdx, rax ; Store for now
1217 call get_token
1219 cmp rax, VARIABLE
1220 je .second_is_var
1222 cmp rax, NUMBER
1223 jne .error
1225 mov rsi, token
1226 call b_string_to_int
1228 .load_part:
1229 mov rcx, rax
1231 mov rax, rdx
1233 ; call b_load_file
1235 xor rax, rax
1236 mov byte al, 'S'
1237 call set_var
1239 xor rax, rax
1240 mov byte al, 'R'
1241 xor rbx, rbx
1242 call set_var
1244 jmp mainloop
1246 .second_is_var:
1247 xor rax, rax
1248 mov byte al, [token]
1249 call get_var
1250 jmp .load_part
1252 .file_not_exists:
1253 xor rax, rax
1254 mov byte al, 'R'
1255 mov rbx, 1
1256 call set_var
1258 call get_token ; Skip past the loading point -- unnecessary now
1260 jmp mainloop
1262 .error:
1263 mov rsi, err_syntax
1264 jmp error
1267 ; ------------------------------------------------------------------
1268 ; MOVE
1270 do_move:
1271 call get_token
1273 cmp rax, VARIABLE
1274 je .first_is_var
1276 mov rsi, token
1277 call b_string_to_int
1278 mov dl, al
1279 jmp .onto_second
1281 .first_is_var:
1282 xor rax, rax
1283 mov byte al, [token]
1284 call get_var
1285 mov dl, al
1287 .onto_second:
1288 call get_token
1290 cmp rax, VARIABLE
1291 je .second_is_var
1293 mov rsi, token
1294 call b_string_to_int
1295 mov dh, al
1296 jmp .finish
1298 .second_is_var:
1299 xor rax, rax
1300 mov byte al, [token]
1301 call get_var
1302 mov dh, al
1304 .finish:
1305 call b_move_cursor
1307 jmp mainloop
1310 ; ------------------------------------------------------------------
1311 ; NEXT
1313 do_next:
1314 call get_token
1316 cmp rax, VARIABLE ; NEXT must be followed by a variable
1317 jne .error
1319 xor rax, rax
1320 mov byte al, [token]
1321 call get_var
1323 inc rax ; NEXT increments the variable, of course!
1325 mov rbx, rax
1327 xor rax, rax
1328 mov byte al, [token]
1330 sub al, 65
1331 mov rsi, for_variables
1332 add rsi, rax
1333 add rsi, rax
1334 lodsw ; Get the target number from the table
1336 inc rax ; (Make the loop inclusive of target number)
1337 cmp rax, rbx ; Do the variable and target match?
1338 je .loop_finished
1340 xor rax, rax ; If not, store the updated variable
1341 mov byte al, [token]
1342 call set_var
1344 xor rax, rax ; Find the code point and go back
1345 mov byte al, [token]
1346 sub al, 65
1347 mov rsi, for_code_points
1348 ; add rsi, rax
1349 ; add rsi, rax
1350 shl rax, 3
1351 add rsi, rax
1352 lodsq
1354 mov [prog], rax
1355 jmp mainloop
1357 .loop_finished:
1358 jmp mainloop
1360 .error:
1361 mov rsi, err_syntax
1362 jmp error
1365 ; ------------------------------------------------------------------
1366 ; PAUSE
1368 do_pause:
1369 call get_token
1371 cmp rax, VARIABLE
1372 je .is_var
1374 mov rsi, token
1375 call b_string_to_int
1376 jmp .finish
1378 .is_var:
1379 xor rax, rax
1380 mov byte al, [token]
1381 call get_var
1383 .finish:
1384 ; call b_pause
1385 jmp mainloop
1388 ; ------------------------------------------------------------------
1389 ; PEEK
1391 do_peek:
1392 call get_token
1394 cmp rax, VARIABLE
1395 jne .error
1397 xor rax, rax
1398 mov byte al, [token]
1399 mov byte [.tmp_var], al
1401 call get_token
1403 cmp rax, VARIABLE
1404 je .dereference
1406 cmp rax, NUMBER
1407 jne .error
1409 mov rsi, token
1410 call b_string_to_int
1412 .store:
1413 mov rsi, rax
1414 xor rbx, rbx
1415 mov byte bl, [rsi]
1416 xor rax, rax
1417 mov byte al, [.tmp_var]
1418 call set_var
1420 jmp mainloop
1422 .dereference:
1423 mov byte al, [token]
1424 call get_var
1425 jmp .store
1427 .error:
1428 mov rsi, err_syntax
1429 jmp error
1432 .tmp_var db 0
1435 ; ------------------------------------------------------------------
1436 ; POKE
1438 do_poke:
1439 call get_token
1441 cmp rax, VARIABLE
1442 je .first_is_var
1444 cmp rax, NUMBER
1445 jne .error
1447 mov rsi, token
1448 call b_string_to_int
1450 cmp rax, 255
1451 jg .error
1453 mov byte [.first_value], al
1454 jmp .onto_second
1457 .first_is_var:
1458 xor rax, rax
1459 mov byte al, [token]
1460 call get_var
1462 mov byte [.first_value], al
1464 .onto_second:
1465 call get_token
1467 cmp rax, VARIABLE
1468 je .second_is_var
1470 cmp rax, NUMBER
1471 jne .error
1473 mov rsi, token
1474 call b_string_to_int
1476 .got_value:
1477 mov rdi, rax
1478 xor rax, rax
1479 mov byte al, [.first_value]
1480 mov byte [rdi], al
1482 jmp mainloop
1484 .second_is_var:
1485 xor rax, rax
1486 mov byte al, [token]
1487 call get_var
1488 jmp .got_value
1490 .error:
1491 mov rsi, err_syntax
1492 jmp error
1494 .first_value db 0
1497 ; ------------------------------------------------------------------
1498 ; PORT
1500 do_port:
1501 call get_token
1502 mov rsi, token
1504 mov rdi, .out_cmd
1505 call b_string_compare
1506 jc .do_out_cmd
1508 mov rdi, .in_cmd
1509 call b_string_compare
1510 jc .do_in_cmd
1512 jmp .error
1514 .do_out_cmd:
1515 call get_token
1516 cmp rax, NUMBER
1517 jne .error
1519 mov rsi, token
1520 call b_string_to_int ; Now rax = port number
1521 mov rdx, rax
1523 call get_token
1524 cmp rax, NUMBER
1525 je .out_is_num
1527 cmp rax, VARIABLE
1528 je .out_is_var
1530 jmp .error
1532 .out_is_num:
1533 mov rsi, token
1534 call b_string_to_int
1535 ; call b_port_byte_out
1536 jmp mainloop
1538 .out_is_var:
1539 xor rax, rax
1540 mov byte al, [token]
1541 call get_var
1543 ; call b_port_byte_out
1544 jmp mainloop
1546 .do_in_cmd:
1547 call get_token
1548 cmp rax, NUMBER
1549 jne .error
1551 mov rsi, token
1552 call b_string_to_int
1553 mov rdx, rax
1555 call get_token
1556 cmp rax, VARIABLE
1557 jne .error
1559 mov byte cl, [token]
1561 ; call b_port_byte_in
1562 xor rbx, rbx
1563 mov bl, al
1565 mov al, cl
1566 call set_var
1568 jmp mainloop
1570 .error:
1571 mov rsi, err_syntax
1572 jmp error
1575 .out_cmd db "OUT", 0
1576 .in_cmd db "IN", 0
1579 ; ------------------------------------------------------------------
1580 ; PRINT
1582 do_print:
1583 call get_token ; Get part after PRINT
1585 cmp rax, QUOTE ; What type is it?
1586 je .print_quote
1588 cmp rax, VARIABLE ; Numerical variable (eg X)
1589 je .print_var
1591 cmp rax, STRING_VAR ; String variable (eg $1)
1592 je .print_string_var
1594 cmp rax, STRING ; Special keyword (eg CHR or HEX)
1595 je .print_keyword
1597 mov rsi, err_print_type ; We only print quoted strings and vars!
1598 jmp error
1600 .print_var:
1601 xor rax, rax
1602 mov byte al, [token]
1603 call get_var ; Get its value
1604 mov rdi, tstring
1605 mov rsi, rdi
1606 call b_int_to_string ; Convert to string
1607 call b_print_string
1609 jmp .newline_or_not
1611 .print_quote: ; If it's quoted text, print it
1612 mov rsi, token
1613 call b_print_string
1615 jmp .newline_or_not
1617 .print_string_var:
1618 mov rsi, string_vars
1619 mov rax, 128
1620 mul rbx
1621 add rsi, rax
1622 call b_print_string
1624 jmp .newline_or_not
1626 .print_keyword:
1627 mov rsi, token
1628 mov rdi, chr_keyword
1629 call b_string_compare
1630 jc .is_chr
1632 mov rdi, hex_keyword
1633 call b_string_compare
1634 jc .is_hex
1636 mov rsi, err_syntax
1637 jmp error
1639 .is_chr:
1640 call get_token
1642 cmp rax, VARIABLE
1643 jne .error
1645 xor rax, rax
1646 mov byte al, [token]
1647 call get_var
1649 ; mov ah, 0Eh
1650 ; int 10h
1652 jmp .newline_or_not
1654 .is_hex:
1655 call get_token
1657 cmp rax, VARIABLE
1658 jne .error
1660 xor rax, rax
1661 mov byte al, [token]
1662 call get_var
1664 call b_debug_dump_al ;print_2hex
1666 jmp .newline_or_not
1668 .error:
1669 mov rsi, err_syntax
1670 jmp error
1672 .newline_or_not:
1673 ; We want to see if the command ends with ';' -- which means that
1674 ; we shouldn't print a newline after it finishes. So we store the
1675 ; current program location to pop ahead and see if there's the ';'
1676 ; character -- otherwise we put the program location back and resume
1677 ; the main loop
1678 mov rax, [prog]
1679 mov [.tmp_loc], rax
1681 call get_token
1682 cmp rax, UNKNOWN
1683 jne .ignore
1685 xor rax, rax
1686 mov al, [token]
1687 cmp al, ';'
1688 jne .ignore
1690 jmp mainloop ; And go back to interpreting the code!
1692 .ignore:
1693 call b_print_newline
1695 mov rax, [.tmp_loc]
1696 mov [prog], rax
1698 jmp mainloop
1700 .tmp_loc dq 0
1703 ; ------------------------------------------------------------------
1704 ; RAND
1706 do_rand:
1707 call get_token
1708 cmp rax, VARIABLE
1709 jne .error
1711 mov byte al, [token]
1712 mov byte [.tmp], al
1714 call get_token
1715 cmp rax, NUMBER
1716 jne .error
1718 mov rsi, token
1719 call b_string_to_int
1720 mov [.num1], rax
1722 call get_token
1723 cmp rax, NUMBER
1724 jne .error
1726 mov rsi, token
1727 call b_string_to_int
1728 mov [.num2], rax
1730 mov rax, [.num1]
1731 mov rbx, [.num2]
1732 ; call b_get_random
1734 mov rbx, rcx
1735 xor rax, rax
1736 mov byte al, [.tmp]
1737 call set_var
1739 jmp mainloop
1741 .tmp db 0
1742 .num1 dq 0
1743 .num2 dq 0
1745 .error:
1746 mov rsi, err_syntax
1747 jmp error
1750 ; ------------------------------------------------------------------
1751 ; REM
1753 do_rem:
1754 mov rsi, [prog]
1755 mov byte al, [rsi]
1756 inc qword [prog]
1757 cmp al, 10 ; Find end of line after REM
1758 jne do_rem
1760 jmp mainloop
1763 ; ------------------------------------------------------------------
1764 ; RETURN
1766 do_return:
1767 xor rax, rax
1768 mov byte al, [gosub_depth]
1769 cmp al, 0
1770 jne .is_ok
1772 mov rsi, err_return
1773 jmp error
1775 .is_ok:
1776 mov rsi, gosub_points
1777 add rsi, rax ; Table is words (not bytes)
1778 add rsi, rax
1779 lodsw
1780 mov [prog], rax
1781 dec byte [gosub_depth]
1783 jmp mainloop
1786 ; ------------------------------------------------------------------
1787 ; SAVE
1789 do_save:
1790 call get_token
1791 cmp rax, QUOTE
1792 je .is_quote
1794 cmp rax, STRING_VAR
1795 jne near .error
1797 mov rsi, string_vars
1798 mov rax, 128
1799 mul rbx
1800 add rsi, rax
1801 jmp .get_position
1803 .is_quote:
1804 mov rsi, token
1806 .get_position:
1807 mov rdi, .tmp_filename
1808 call b_string_copy
1810 call get_token
1812 cmp rax, VARIABLE
1813 je .second_is_var
1815 cmp rax, NUMBER
1816 jne .error
1818 mov rsi, token
1819 call b_string_to_int
1821 .set_data_loc:
1822 mov [.data_loc], rax
1824 call get_token
1826 cmp rax, VARIABLE
1827 je .third_is_var
1829 cmp rax, NUMBER
1830 jne .error
1832 mov rsi, token
1833 call b_string_to_int
1835 .set_data_size:
1836 mov [.data_size], rax
1838 mov rax, .tmp_filename
1839 mov rbx, [.data_loc]
1840 mov rcx, [.data_size]
1842 ; call b_write_file
1843 jc .save_failure
1845 xor rax, rax
1846 mov byte al, 'R'
1847 xor rbx, rbx
1848 call set_var
1850 jmp mainloop
1852 .second_is_var:
1853 xor rax, rax
1854 mov byte al, [token]
1855 call get_var
1856 jmp .set_data_loc
1858 .third_is_var:
1859 xor rax, rax
1860 mov byte al, [token]
1861 call get_var
1862 jmp .set_data_size
1864 .save_failure:
1865 xor rax, rax
1866 mov byte al, 'R'
1867 mov rbx, 1
1868 call set_var
1870 jmp mainloop
1872 .error:
1873 mov rsi, err_syntax
1874 jmp error
1877 .filename_loc dw 0
1878 .data_loc dw 0
1879 .data_size dw 0
1881 .tmp_filename times 15 db 0
1884 ; ------------------------------------------------------------------
1885 ; SERIAL
1887 do_serial:
1888 call get_token
1889 mov rsi, token
1891 mov rdi, .on_cmd
1892 call b_string_compare
1893 jc .do_on_cmd
1895 mov rdi, .send_cmd
1896 call b_string_compare
1897 jc .do_send_cmd
1899 mov rdi, .rec_cmd
1900 call b_string_compare
1901 jc .do_rec_cmd
1903 jmp .error
1905 .do_on_cmd:
1906 call get_token
1907 cmp rax, NUMBER
1908 je .do_on_cmd_ok
1909 jmp .error
1911 .do_on_cmd_ok:
1912 mov rsi, token
1913 call b_string_to_int
1914 cmp rax, 1200
1915 je .on_cmd_slow_mode
1916 cmp rax, 9600
1917 je .on_cmd_fast_mode
1919 jmp .error
1921 .on_cmd_fast_mode:
1922 xor rax, rax
1923 ; call b_serial_port_enable
1924 jmp mainloop
1926 .on_cmd_slow_mode:
1927 mov rax, 1
1928 ; call b_serial_port_enable
1929 jmp mainloop
1931 .do_send_cmd:
1932 call get_token
1933 cmp rax, NUMBER
1934 je .send_number
1936 cmp rax, VARIABLE
1937 je .send_variable
1939 jmp .error
1941 .send_number:
1942 mov rsi, token
1943 call b_string_to_int
1944 ; call b_send_via_serial
1945 jmp mainloop
1947 .send_variable:
1948 xor rax, rax
1949 mov byte al, [token]
1950 call get_var
1951 ; call b_send_via_serial
1952 jmp mainloop
1954 .do_rec_cmd:
1955 call get_token
1956 cmp rax, VARIABLE
1957 jne .error
1959 mov byte al, [token]
1961 xor rcx, rcx
1962 mov cl, al
1963 ; call b_get_via_serial
1965 xor rbx, rbx
1966 mov bl, al
1967 mov al, cl
1968 call set_var
1970 jmp mainloop
1972 .error:
1973 mov rsi, err_syntax
1974 jmp error
1976 .on_cmd db "ON", 0
1977 .send_cmd db "SEND", 0
1978 .rec_cmd db "REC", 0
1981 ; ------------------------------------------------------------------
1982 ; SOUND
1984 do_sound:
1985 call get_token
1987 cmp rax, VARIABLE
1988 je .first_is_var
1990 mov rsi, token
1991 call b_string_to_int
1992 jmp .done_first
1994 .first_is_var:
1995 xor rax, rax
1996 mov byte al, [token]
1997 call get_var
1999 .done_first:
2000 call b_speaker_tone
2002 call get_token
2004 cmp rax, VARIABLE
2005 je .second_is_var
2007 mov rsi, token
2008 call b_string_to_int
2009 jmp .finish
2011 .second_is_var:
2012 xor rax, rax
2013 mov byte al, [token]
2014 call get_var
2016 .finish:
2017 ; call b_pause
2018 call b_speaker_off
2020 jmp mainloop
2023 ; ------------------------------------------------------------------
2024 ; WAITKEY
2026 do_waitkey:
2027 call get_token
2028 cmp rax, VARIABLE
2029 je .is_variable
2031 mov rsi, err_syntax
2032 jmp error
2034 .is_variable:
2035 xor rax, rax
2036 mov byte al, [token]
2038 push rax
2040 call b_input_key_wait
2042 cmp rax, 48E0h
2043 je .up_pressed
2045 cmp rax, 50E0h
2046 je .down_pressed
2048 cmp rax, 4BE0h
2049 je .left_pressed
2051 cmp rax, 4DE0h
2052 je .right_pressed
2054 .store:
2055 xor rbx, rbx
2056 mov bl, al
2058 pop rax
2060 call set_var
2062 jmp mainloop
2064 .up_pressed:
2065 mov rax, 1
2066 jmp .store
2068 .down_pressed:
2069 mov rax, 2
2070 jmp .store
2072 .left_pressed:
2073 mov rax, 3
2074 jmp .store
2076 .right_pressed:
2077 mov rax, 4
2078 jmp .store
2081 ; ==================================================================
2082 ; INTERNAL ROUTINES FOR INTERPRETER
2084 ; ------------------------------------------------------------------
2085 ; Get value of variable character specified in AL (eg 'A')
2087 get_var:
2088 sub al, 65
2089 mov rsi, variables
2090 add rsi, rax
2091 add rsi, rax
2092 lodsw
2096 ; ------------------------------------------------------------------
2097 ; Set value of variable character specified in AL (eg 'A')
2098 ; with number specified in rbx
2100 set_var:
2101 mov ah, 0
2102 sub al, 65 ; Remove ASCII codes before 'A'
2104 mov rdi, variables ; Find position in table (of words)
2105 add rdi, rax
2106 add rdi, rax
2107 mov rax, rbx
2108 stosw
2112 ; ------------------------------------------------------------------
2113 ; Get token from current position in prog
2115 get_token:
2116 mov rsi, [prog]
2117 lodsb
2119 cmp al, 13
2120 je .newline
2122 cmp al, 10
2123 je .newline
2125 cmp al, ' '
2126 je .newline
2128 call is_number
2129 jc get_number_token
2131 cmp al, '"'
2132 je get_quote_token
2134 cmp al, 39 ; Quote mark (')
2135 je get_char_token
2137 cmp al, '$'
2138 je near get_string_var_token
2140 jmp get_string_token
2142 .newline:
2143 inc qword [prog]
2144 jmp get_token
2146 get_number_token:
2147 mov rsi, [prog]
2148 mov rdi, token
2150 .loop:
2151 lodsb
2152 cmp al, 13
2153 je .done
2154 cmp al, 10
2155 je .done
2156 cmp al, ' '
2157 je .done
2158 call is_number
2159 jc .fine
2161 mov rsi, err_char_in_num
2162 jmp error
2164 .fine:
2165 stosb
2166 inc qword [prog]
2167 jmp .loop
2169 .done:
2170 mov al, 0 ; Zero-terminate the token
2171 stosb
2173 mov rax, NUMBER ; Pass back the token type
2176 get_char_token:
2177 inc qword [prog] ; Move past first quote (')
2179 mov rsi, [prog]
2180 lodsb
2182 mov byte [token], al
2184 lodsb
2185 cmp al, 39 ; Needs to finish with another quote
2186 je .is_ok
2188 mov rsi, err_quote_term
2189 jmp error
2191 .is_ok:
2192 inc qword [prog]
2193 inc qword [prog]
2195 mov rax, CHAR
2198 get_quote_token:
2199 inc qword [prog] ; Move past first quote (") char
2200 mov qword rsi, [prog]
2201 mov rdi, token
2202 .loop:
2203 lodsb
2204 cmp al, '"'
2205 je .done
2206 cmp al, 10
2207 je .error
2208 stosb
2209 inc qword [prog]
2210 jmp .loop
2212 .done:
2213 mov al, 0 ; Zero-terminate the token
2214 stosb
2215 inc qword [prog] ; Move past final quote
2217 mov rax, QUOTE ; Pass back token type
2220 .error:
2221 mov rsi, err_quote_term
2222 jmp error
2224 get_string_var_token:
2225 lodsb
2226 xor rbx, rbx ; If it's a string var, pass number of string in rbx
2227 mov bl, al
2228 sub bl, 49
2230 inc qword [prog]
2231 inc qword [prog]
2233 mov rax, STRING_VAR
2236 get_string_token:
2237 mov qword rsi, [prog]
2238 mov rdi, token
2239 .loop:
2240 lodsb
2241 cmp al, 13
2242 je .done
2243 cmp al, 10
2244 je .done
2245 cmp al, ' '
2246 je .done
2247 stosb
2248 inc qword [prog]
2249 jmp .loop
2250 .done:
2251 mov al, 0 ; Zero-terminate the token
2252 stosb
2254 mov rax, token
2255 call b_string_uppercase
2257 mov rsi, token
2258 call b_string_length ; How long was the token?
2259 cmp rcx, 1 ; If 1 char, it's a variable or delimiter
2260 je .is_not_string
2262 mov rsi, token ; If the token ends with ':', it's a label
2263 add rsi, rax
2264 dec rsi
2265 lodsb
2266 cmp al, ':'
2267 je .is_label
2269 mov rax, STRING ; Otherwise it's a general string of characters
2272 .is_label:
2273 mov rax, LABEL
2276 .is_not_string:
2277 mov byte al, [token]
2278 call is_letter
2279 jc .is_var
2281 mov rax, UNKNOWN
2284 .is_var:
2285 mov rax, VARIABLE ; Otherwise probably a variable
2289 ; ------------------------------------------------------------------
2290 ; Set carry flag if AL contains ASCII number
2292 is_number:
2293 cmp al, 48
2294 jl .not_number
2295 cmp al, 57
2296 jg .not_number
2299 .not_number:
2304 ; ------------------------------------------------------------------
2305 ; Set carry flag if AL contains ASCII letter
2307 is_letter:
2308 cmp al, 65
2309 jl .not_letter
2310 cmp al, 90
2311 jg .not_letter
2315 .not_letter:
2320 ; ------------------------------------------------------------------
2321 ; Print error message and quit out
2323 error:
2324 call b_print_newline
2325 call b_print_string ; Print error message
2326 call b_print_newline
2328 mov rsp, [orig_stack] ; Restore the stack to as it was when BASIC started
2330 ret ; And finish
2333 ; Error messages text...
2335 err_char_in_num db "Error: unexpected character in number", 0
2336 err_quote_term db "Error: quoted string or character not terminated correctly", 0
2337 err_print_type db "Error: PRINT command not followed by quoted text or variable", 0
2338 err_cmd_unknown db "Error: unknown command", 0
2339 err_goto_notlabel db "Error: GOTO or GOSUB not followed by label", 0
2340 err_label_notfound db "Error: GOTO or GOSUB label not found", 0
2341 err_return db "Error: RETURN without GOSUB", 0
2342 err_nest_limit db "Error: FOR or GOSUB nest limit exceeded", 0
2343 err_next db "Error: NEXT without FOR", 0
2344 err_syntax db "Error: syntax error", 0
2348 ; ==================================================================
2349 ; DATA SECTION
2351 orig_stack dq 0 ; Original stack location when BASIC started
2353 prog dq 0 ; Pointer to current location in BASIC code
2354 prog_end dq 0 ; Pointer to final byte of BASIC code
2356 load_point dq 0
2358 token_type db 0 ; Type of last token read (eg NUMBER, VARIABLE)
2359 token times 255 db 0 ; Storage space for the token
2360 tstring times 255 db 0
2362 align 16
2363 variables times 26 dq 0 ; Storage space for variables A to Z
2364 align 16
2365 for_variables times 26 dq 0 ; Storage for FOR loops
2366 align 16
2367 for_code_points times 26 dq 0 ; Storage for code positions where FOR loops start
2369 alert_cmd db "ALERT", 0
2370 call_cmd db "CALL", 0
2371 cls_cmd db "CLS", 0
2372 cursor_cmd db "CURSOR", 0
2373 curschar_cmd db "CURSCHAR", 0
2374 end_cmd db "END", 0
2375 for_cmd db "FOR", 0
2376 gosub_cmd db "GOSUB", 0
2377 goto_cmd db "GOTO", 0
2378 getkey_cmd db "GETKEY", 0
2379 if_cmd db "IF", 0
2380 input_cmd db "INPUT", 0
2381 load_cmd db "LOAD", 0
2382 move_cmd db "MOVE", 0
2383 next_cmd db "NEXT", 0
2384 pause_cmd db "PAUSE", 0
2385 peek_cmd db "PEEK", 0
2386 poke_cmd db "POKE", 0
2387 port_cmd db "PORT", 0
2388 print_cmd db "PRINT", 0
2389 rem_cmd db "REM", 0
2390 rand_cmd db "RAND", 0
2391 return_cmd db "RETURN", 0
2392 save_cmd db "SAVE", 0
2393 serial_cmd db "SERIAL", 0
2394 sound_cmd db "SOUND", 0
2395 waitkey_cmd db "WAITKEY", 0
2397 then_keyword db "THEN", 0
2398 chr_keyword db "CHR", 0
2399 hex_keyword db "HEX", 0
2401 progstart_keyword db "PROGSTART", 0
2402 ramstart_keyword db "RAMSTART", 0
2404 gosub_depth db 0
2405 gosub_points times 10 dq 0 ; Points in code to RETURN to
2407 string_vars times 1024 db 0 ; 8 * 128 byte strings
2410 ; ------------------------------------------------------------------
2411 basic_prog:
2412 DB 'CLS',13,10
2413 DB 'PRINT "Please type your name: ";',13,10
2414 DB 'INPUT $N',13,10
2415 DB 'PRINT ""',13,10
2416 DB 'PRINT "Hello ";',13,10
2417 DB 'PRINT $N;',13,10
2418 DB 'PRINT ", welcome to MikeOS Basic (in 64-bit mode)!"',13,10
2419 DB 'PRINT ""',13,10
2420 DB 'PRINT "It supports FOR...NEXT loops and simple integer maths..."',13,10
2421 DB 'PRINT ""',13,10
2422 DB 'FOR I = 1 TO 15',13,10
2423 DB 'J = I * I',13,10
2424 DB 'K = J * I',13,10
2425 DB 'L = K * I',13,10
2426 DB 'PRINT I ;',13,10
2427 DB 'PRINT " ";',13,10
2428 DB 'PRINT J ;',13,10
2429 DB 'PRINT " ";',13,10
2430 DB 'PRINT K ;',13,10
2431 DB 'PRINT " ";',13,10
2432 DB 'PRINT L',13,10
2433 DB 'NEXT I',13,10
2434 DB 'PRINT ""',13,10
2435 DB 'PRINT " ...and IF...THEN and GOSUB and lots of other stuff. Bye!"',13,10
2436 DB 'END',13,10