-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtinybctut.txt
1057 lines (876 loc) · 47.4 KB
/
tinybctut.txt
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
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Tiny BASIC manual for beginners
-------------------------------
Why Tiny BASIC?
---------------
You don't know anything about programming? OK, no problem, then Tiny
BASIC for Curses is for you. Yes you can make things to move around on
screen, yes you can control everything with your keys. But still it
is primitive, of course everyone who knows that there is more, wants
more. Nothing more advanced is simple though, or when it is simple then
it is not complete.
Think that it is how it was, there was such BASIC on old microcomputers,
and the most important about it was that it was very simple. So simple
that no programming language can be simpler. You may ask how can a
programming language with some twenty of pages of programming manual be
simple. But this is how complex programming is that explaining even the
simplest programming language takes that many pages.
This manual is a part of the Tiny BASIC for Curses project, the project's
page in freecode is http://freecode.com/projects/tinybc and the download
page in SourceForge is http://sourceforge.net/projects/tinybc . Also
read the manual page http://tinybc.sourceforge.net which you can read in
Linux with man tinybc if Tiny BASIC for Curses is installed. The online
version is the latest version of this manual.
Starting Tiny BASIC
-------------------
What do you need for programming in Tiny BASIC for Curses? All you
need for that is terminal. In Linux it is called terminal or Konsole,
in Windows it is called cmd, console or command prompt. I assume that you
have a terminal icon on your desktop, simply run it. I also assume that
your terminal is configured properly, like the font is large enough,
there are right colors and right encoding for pseudo graphics (IBM850
for Linux terminal). This terminal is where all your world will be.
It may sometimes happen that your program remains running in a loop, if
you did not code it so that you can exit it normally. No problem, ctrl-c
in Linux and ctrl-break in Windows (hold down ctrl and press the break
key at the upper right corner of the keyboard) exits the program. But
if nothing helps, clicking on the x button on the terminal window will
always close the terminal. So you always remain in control.
All you need to start Tiny BASIC for Curses from command prompt,
is typing tinybc and pressing Enter. Tiny BASIC for Curses greets
you and gives you a tinybc prompt. There you can start to enter your
program. Every line which you write after that prompt followed by Enter,
which begins with a number and space, is stored as a program line. Usually
the numbers are increased by 10, because then you can enter new lines
between any two lines already there. You can enter the lines in any order,
though mostly you would like to do it in the increasing order.
That all lines have to begin with a number is the peculiarity of Tiny
BASIC. Writing a number before every line is tedious of course, but it
has also some benefits for beginners. When every line has a number then
every line is identified, which makes finding it, remembering it and
referring to it much easier. Tiny BASIC is designed to be as simple as
possible, but not efficient and convenient to use.
All commands have to be in upper case, just because this is how it
once was in that BASIC, and you can write only the first letter of a
command. If you type L (LIST) after the tinybc prompt and press Enter,
you will see the program which you entered. When your program is longer
than the screen, it prints a part of it and stops, press any key after
that when you want to see the next part. That way you can see all your
code until the prompt appears. You may also follow L with one or two
numbers. For example L 100 prints your code starting from the line
which begins with the number 100, L 100-200 prints all lines of your
code between 100 and 200.
If you browse your code and decide that some lines must be deleted,
for deleting a line you simply have to write the number of that line
after the tinybc prompt, and press Enter. To change a line which is
already there, you can simply write another line with the same number
after the tinybc prompt, and press Enter. So that way you can write
your code and change everything in it whenever you want. Try it out by
writing whatever text after the line numbers, and then deleting, adding
and changing the lines. Tiny BASIC for Curses will not complain before
you run your program.
C (CLEAR) clears the program so that you can write a new one. H (HELP)
prints help, Q (QUIT) exits tinybc. You can use Backspace to delete
wrongly written characters, this is the key above Enter with a left
arrow on it, ctrl-u deletes the whole line.
Writing your first program
--------------------------
Now you know how to enter a program, and you certainly want to know
what you should write in these lines so that your program would also
do something. Tiny BASIC for Curses is an interpreter. Interpreter is
something which executes the program line after line. So as you likely
already understood, when you run your program, the lines shall be executed
one after another, in the order of their numbers. So write this program:
10 PRINT "Hello ";
20 PRINT "World!"
Type L to see that you have only these two lines in your program. To
run the program, type R followed by Enter. If you wrote the program
exactly as above, the terminal screen will be cleared and the text
"Hello world!" will appear at the top of the screen. As you can see,
this program has only two lines, after executing the last line there is
nothing more to execute and the program exits. After the program exits,
the interpreter waits you to press any key, so always remember to press
any key when the program ends and you want to return to the prompt. Thus
after pressing any key, the terminal screen will be cleared and you will
see the tinybc prompt again.
Now you have written your first program and run it. The line which
starts with a number is called statement, and there are different kind of
statements. What the PRINT statement does is that it prints everything
which follows it, as you could guess. The text which you want to print
always has to be between quotation marks, this text is called string.
Thus far it is simple. But why is there semicolon at the end of the
first statement? You can write several strings in one statement, and
you must separate them either by comma or by semicolon. Comma means
that the next string shall be printed after the previous one with a
space between the strings, semicolon means the same except that there
shall be no space between the strings. So semicolon in the end of the
PRINT statement means that anything which will be printed later, shall
be printed immediately after the text written by that statement, without
going to the next line. If the PRINT statement does not end with comma
or semicolon, any text printed after that statement shall be printed
starting from the beginning of the next line on the screen.
Jumping to other places in the program
--------------------------------------
So as you now know, the statements in the program are executed one
after another. But there is a joker, a statement which can change all
that. And this joker statement is called GOTO. The GOTO statement is
simple, it is just GOTO followed by space and a line number. This line
number is the number of the line which will be executed after the GOTO
statement. So after that statement the interpreter starts to execute
statements starting from the statement with that number, in increasing
order as usual, until there would be another GOTO statement. Consider
the following code:
10 PRINT "Hello World!"
20 GOTO 10
This code shall cause a problem in that it never stops. So you can
see that there can be programs which work forever, unless stopped by
some means. You may think whether you actually run that program, but you
had to see it to have some idea. If you are courageous and still run that
program, what you will see is a screen where "Hello World!" is printed
on every line. This is because the program printed a screenful of these
texts so quickly that you did not see how it happened, and after that
it continues to print that text on the last line. After printing on the
last line of the screen, all that is on the screen moves up by one line,
so that new text can be written on the last line.
So you now know one of the most powerful statements called GOTO. The
way GOTO was used in the example above was not a good use though. Because
GOTO is a very powerful statement, one should be careful to use it only
in the correct way. What you saw in the program above is called loop, but
it was not a correctly written loop. In some other programming languages
there are loops like for and while loops, if blocks and statements like
break and continue, but no GOTO statement. The standard Tiny BASIC has
no such loops and statements, so later it would be explained how to
write these loops and statements with GOTO, and how to use GOTO correctly.
Variables, the places to store data
-----------------------------------
So now you know how the program statements are executed. Next you
should know something equally important, the variables. Variables
are places of data storage where numbers can be stored. Numbers can
be both positive and negative. The letters A to Z denote 26 of such
storage places. And since all the memory space which is left after your
program is used for data storage, the rest of these storage places can
be accessed using @(n). There n is the number of the storage place, also
called index, and @ is the symbol of the array. Thus a lot of numbers
can be stored, and that way any data, as you soon will see. Write and
run the following program:
10 A = 2
20 B = 3
30 @(0) = 4
40 C = A + B * @(0)
50 PRINT "C =", C
As you could guess, PRINT statement there prints the value of the
variable C, which is a number, after the text "C =". So there can
be both strings and numbers in the PRINT statement, separated by commas
or semicolons.
The statements there which contain = are called LET statements. After
= in the LET statement there is expression. Expression there is like a
mathematical expression where the operators +. -, *. / and the function
RND(n) can be used. These operators stand for add, subtract, multiply
and divide, and RND(n) provides a random number 0 to one less than n.
Instead of n there can be any expression, like RND(A + B + 1). The same
is true about array index, like @(B + 1). Parentheses can be used the
same way as in mathematical expressions, to change the order of the
mathematical operations. Before = in the LET statement there is lvalue,
a variable or array element to which the expression which follows the =
shall be assigned.
So what result shall the PRINT statement print in the example
above? The right answer is 14, because the expression is evaluated in
the correct order of mathematical operations, where the multiplication
and division is done before addition and subtraction. Thus 3 multiplied
by 4 equals 12, and 2 plus 12 equals 14. If the calculations were done
in the order in which the operations occur, the answer were 20.
You can safely consider that when your program starts, the values of
all variables and array elements are 0. So now you know what variables
are and what to do with them. Next you would know more about expressions
and array.
More about expressions
----------------------
There is more to expression than the four operators. Also the
relational operators <, <=, >, >=, = and <>, standing for less than,
less than or equal, greater than, greater than or equal, equal to, and
not equal to, can be used in expression. So how can these operators
be used together with other operators? The answer is that it is all
about the precedence of operators, that is, what operations shall be
performed first, what next, etc. The relational operations have the lowest
precedence, which means that they shall be performed last. The value of
the relational operations is 1 or 0 depending on whether the condition
which the relational operator represents, is true or not. Consider
the following:
10 A = 3
20 B = A - 3 > 0
The value of B shall be 0 because A - 3 equals 0, and this shall be
evaluated first. 0 is not greater than 0, so the result of the relational
operation is 0. But even more complex calculations can be done with
relational operators, considering that parts of the expression can be
enclosed in parentheses. Consider the following:
10 A = 3
20 B = (A > 2) * (A < 4)
The result is 1. The parts of the expression in parentheses shall
be evaluated first. The value of both expressions in parentheses is
1, because 3 > 2 and 3 < 4. When both operations in parentheses are
relational operations, the values of both of them can only be 0 or
1. Thus the multiplication there means that the result is 1 only if the
values of both relational operations are 1. This is just another way to
say that the expression is true if both relational operations are true,
which is the same as logical and.
You can also use + for a similar purpose, the result is 0 only when both
relational operations are false, otherwise the result is not 0. This is
another way to say that the expression is true if the value of at least
one relational operation is true, which is the same as logical or.
More about array
----------------
Now more about array. Many expressions can be assigned to array in
one LET statement. Consider the following:
10 A = 3
20 @(7) = 2, 3, A - 4, -6
The numbers 2, 3, -1 and -6 shall be assigned to array elements
starting from the element 7, thus to array elements @(7), @(8), @(9)
and @(10).
And this is not all. In assignment to array, in the comma separated list
which follows =, there can also be strings. Consider the following:
10 @(5) = 2, "abc", -6
There, to the array element 5 shall be assigned number 2, but to the
array elements 6, 7 and 8 shall be assigned the codes of the letters a,
b and c, correspondingly. To the array element 9 shall be assigned number
-6. So letters are numbers too, each letter has its number in the code
table. Search google for ASCII and for IBM850 and you would see what
number corresponds to each character.
So why is all that necessary? Later you would see that assigning
strings to array is necessary for processing text, because that way text
becomes data the same as numbers, thus it can be processed the same way as
any other data. In several programming languages text is stored in arrays.
Assigning many expressions and strings to array at once is useful also
for data driven code. Data driven code means that what your code does is
determined by the data, and you assign that data to the array once. This
is equivalent to the initialization of arrays in other programming
languages such as python. Code thus may become short, simple and flexible,
and you can change a lot by changing data only.
Conditional statement
---------------------
So now you know some statements and you know some variables. There is
one powerful statement which you still have to know to write your first
programs which can do something useful. And this is the conditional
statement called IF statement. The form of the IF statement is IF
expression statement. The expression there is any expression described
above, and statement is any statement without a preceding number.
When the value of the expression is anything different from zero, the
statement shall be executed the way such statement shall normally be
executed. When the value of the expression is zero, the statement shall
not be executed. Write and run the following program:
10 A = 3
20 B = -2
30 IF A > -1 PRINT "A is a positive number"
40 IF B > -1 PRINT "B is a positive number"
The text "A is a positive number" shall be printed, but the next
text shall not be printed, because in case of B the condition is not true.
To understand the importance of IF statements, consider what
your program has to do. Many things are mostly going on in parallel,
and it is often not possible to process them in separate parts of the
program. So processing of them is scattered everywhere in the program,
and if blocks take care of it, thus associating one aspect of the code
with the other. The number of these and other associations determines
the complexity of the code. Later it would be explained how to write
if blocks.
Adding comments to program
--------------------------
Now one more statement which is very simple, it is called REM
statement. This statement is simple because it does nothing. Consider
the following:
10 REM DO
20 PRINT "Hello World!"
30 GOTO 10
This works exactly the same as the previous example of a loop. The
first statement does nothing and thus every time only the string is
printed. Yet it is slightly better than the previous loop example. Because
it is good to always mark the targets of GOTO with REM statements, which
describe the reason of the jump. In this case the reason is loop, thus the
REM statement marks the beginning of the loop. Adding REM statements is
tedious, but there is a lot of benefit of it, because in a big program
it is difficult to see what all these GOTO-s do. But when the targets
are marked like that, it would be easy to see a part of what construct
any GOTO statement really is. How to use GOTO statements will later be
explained more thoroughly.
The text after REM is not processed by the interpreter at all, thus
it can be whatever. REM statements without any text can be used to add
empty lines. Add empty lines between subroutines and between bigger
parts of the code, to make the code clearer.
REM statements are also often used to describe what one or another part of
the program does (called comments), which is also very important. Comments
are mostly written before the blocks and sometimes before statements, to
describe what they do. You yourself would forget quickly what different
parts of your program do, and one day you may look at your own code as
to something written in some unknown language. But do not write too many
comments, because then it would be difficult to read the code.
Loops
-----
Now more about loops, how to write loops which are not endless. Write
the following program and run it:
10 I = 1
20 REM DO
30 IF I > 10 GOTO 70
40 PRINT I
50 I = I + 1
60 GOTO 20
70 REM LOOP
This shall print numbers 1 to 10. The loop is between REM DO and
REM LOOP. Adding these statements to the loop makes the code longer,
but it is very important to always do that, so that it would be easy to
see where the loops begin and end. Clarity of the code is more important
than the length of the code.
The statements 30 and 60 form what is called while loop in other
programming languages, except that the condition I > 10 is inverse, in
while loop that condition has to be I <= 10. The condition means that
when I becomes greater than 10, the loop ends.
The statements 30 and 60 together with the statements 10 and 50
form the for in range loop in python. The for in range loop has a loop
variable, in this case I, provides its initial value, in this case 1,
its final value, in this case 10 in the condition, and the step, which
is the number by which the loop variable would be incremented in each
iteration. In this case the statement 50 provides the increment, and
the step is 1. In python the for in range loop is one statement and the
rest of the loop follows with an indentation, but it works exactly as
the loop in this example. Now write the following program and run it:
10 REM DO
20 I = I + 1
30 PRINT I
40 IF I = 10 GOTO 60
50 GOTO 10
60 REM LOOP
This does exactly the same as the previous example, only in a slightly
different way. I is not initialized, so its value in the beginning of
the program is 0. GOTO in the statement 40 is equivalent to the break
statement. We can also say that the statement 50 is equivalent to the
continue statement, though in other programming languages this jump is
provided by the loop.
The loops in this and in the previous example are used for different
purposes, the difference is that when I is out of range, the loop in
this example iterates one time, and the loop in the previous example
does not iterate at all. In other programming languages, such as python,
there is no GOTO statement, so you have to write loops using only the
loop statements, the continue statement and the break statement. But
you should now know what these statements do, so switching to another
programming language should not be difficult.
Basically, loop is a block, and it is correct to jump only to the
beginning of it or to the end of it, only from inside of the block and not
from inside a contained block. Loop can be inside of another loop. The
main idea of structured programming is really simple, the whole program
consists of blocks, which provides a clear structure. The blocks are
loops, if-else blocks and subroutines.
If-else blocks
--------------
Where you also have to use GOTO statements, is in if-else blocks. These
blocks are also provided by other programming languages, but there you
have to implement them without GOTO, so it is important to know how they
work. Write the following program and run it:
10 N = RND(2) + 1
20 PRINT N
30 IF N <> 1 GOTO 60
40 PRINT "one"
50 GOTO 80
60 REM ELSE
70 PRINT "two"
80 REM END IF
Using if and else together is necessary to do either one or the other,
but not both. The IF condition used in the example above is inverse of the
if condition used in other programming languages for doing the same. As
you can see, if the condition is true, we jump to the else block, but
if it is not true, we enter the if block and in the end of it jump to
the end of the two blocks.
If-else blocks can be inside other if-else blocks. It is also possible
to use multiple else blocks, which does almost the same as the switch
statement in some programming languages. Write the following program
and run it:
10 N = RND(3) + 1
20 PRINT N
30 IF N <> 1 GOTO 60
40 PRINT "one"
50 GOTO 120
60 REM ELSE
70 IF N <> 2 GOTO 100
80 PRINT "two"
90 GOTO 120
100 REM ELSE
110 PRINT "three"
120 REM END IF
The benefit of such chain of else blocks is that when the necessary
operation is done, like in statement 40, a jump is made to the end of
all blocks and no other IF statement is executed. Basically, if-else
block is like several blocks inside a containing block, and jump can be
made from the end of these blocks to the end of the containing block.
In some cases it may be necessary to use flags, variables which value
can only be 0 or 1. Set a flag when an operation is done, and later use
that flag in IF conditions.
All the correct uses of the GOTO statement were described above,
and you should never use GOTO statement for any other purposes, for your
code to be clear and consistent.
Game loop
---------
In addition to loops you should know how the modeless programs, such
as games, are generally written. In such programs there is often one
big loop, which is called game loop. The game loop is an endless loop
which exits only when the user wants to exit. Every iteration of the
game loop usually checks the user input, does the necessary processing,
and then draws the next screenful of graphics, which is called frame.
In the beginning of the game loop there must be a statement named
NAP. NAP is followed by the number of milliseconds, this is the number
of milliseconds during which the program does nothing. Providing
this inactivity period once in every iteration is necessary for two
reasons. First it gives the operating system a time to do other things
than running your program. Not giving that time takes too much computer
resources, and some operating systems such as Windows would become not
responsive when no such time is given. Second, it can be used to adjust
the speed of the game or other program.
For fast output, write the whole screen without line feeds, but
in that case anything which you wrote shall appear on the screen only
after input statements or NAP statement. It is common in programs such
as text editors to rewrite the entire screen after inserting every single
character. For the maximum output speed, in output statements the screen
is only refreshed when printing a line feed.
If it happens that the output becomes crappy, you may also have
to use NAP statement before PRINT or OUT statements. This should not
happen but it depends on your terminal. In some terminals the output to
the terminal is not synchronized, and thus long printing operations may
continue when the program already has to print something else.
Input and output
----------------
Now you know so much about writing programs that you likely want to
write some interactive program. There are several statements for input
and output in Tiny BASIC for Curses. The most straightforward of these
is the INPUT statement. Write the following program and run it:
10 PRINT "A, B",
20 INPUT A, B
30 PRINT "A =", A, "B =", B
The program asks "A, B ?", after which you should write two numbers
separated by either comma or space, and then press Enter. The numbers
which you entered shall be assigned to variables A and B, and then
the values of these variables shall be printed. You may also enter an
upper-case letter instead of a number, in that case the entered value
shall be the value of the variable which corresponds to that letter. If
you do not enter any number, the value of the input variable shall not
change, and thus shall not be 0 unless you assign it so.
INPUT is convenient but rather restricted. Therefore Tiny BASIC
for Curses provides two more general statements for input and output,
INKEY and OUT. Write the following program and run it:
10 PRINT "Please enter your name"
20 REM DO
30 NAP 10
40 INKEY K
50 IF (K = 10) + (I > 40) GOTO 100
60 IF (K < 32) + (K > 126) GOTO 20
70 @(I) = K
80 I = I + 1
90 GOTO 20
100 REM LOOP
110 PRINT "Your name is",
120 REM DO
130 IF @(J) = 0 GOTO 170
140 OUT @(J)
150 J = J + 1
160 GOTO 120
170 REM LOOP
The program asks your name, you write your name followed by Enter,
and the program prints your name. As you can see, in the beginning there
is a loop for inputting the name. The loop sleeps for 10 milliseconds to
not read the key code too often, then writes the key code to the variable
K. The loop ends when the key was Enter. We also check the boundary of
the text. If K is not a letter, we go to the next iteration and skip
the rest of the loop. Then K shall be assigned to the element of the
array with the current index, and the index I shall be incremented. The
variables I and J are mostly used as array indexes.
After the name is stored to the array, the program prints "Your name
is" and starts to print the name letter by letter. As you may notice,
the loop for that is a while loop, because it may happen that no letters
were entered and nothing shall be done then. The letters shall be printed
using the OUT statement, which writes a character to the screen, until
the first array element which is 0. This is how we find the end of the
text, because no letter code is 0.
OUT can output every character, including the pseudo graphics
characters. In IBM850 code page there are characters for a large rectangle
(219), lower square (220) and upper square (223), these characters enable
to draw pseudo graphics very similar to the "graphics" which some old
microcomputers had. There are also other pseudo graphics characters
in the IBM850 code page, such as characters for drawing boxes and
rectangular diagrams.
Subroutines, using the same code many times
-------------------------------------------
Now you may feel that you can write every kind of programs, but
this is not yet all about programming. If you have to do the same thing
several times in different places of the program, don't you think that
it is better to write that piece of code once and then use it every time
with different data? You may think that you will use GOTO to go to that
piece of code every time, but the problem is how can you come back from
there. It is true that variable can be used after GOTO, so that problem
can be solved, but this is not a good way to do it.
For that purpose there are subroutines, which in other programming
languages such as python are called functions. For jumping to a subroutine
there is GOSUB statement with a line number after GOSUB. This is named
calling a subroutine. You can use GOSUB instead of GOTO to go to your
repeatedly used piece of code. How it differs from GOTO is that the line
from which the subroutine was called, is remembered. And there is the
statement RETURN which jumps back to the line next to the GOSUB statement
of the last subroutine call. You can see how that works in the following
example. Write the following program and run it:
10 N = 10
20 @(N) = "Hello World!"
30 C = N
40 GOSUB 1000
50 @(N) = "Hello tinybc"
60 C = N
70 GOSUB 1000
80 END
1000 REM SUBROUTINE
1010 REM DO
1020 IF @(C) = 0 GOTO 1060
1030 OUT @(C)
1040 C = C + 1
1050 GOTO 1010
1060 REM LOOP
1070 PRINT
1080 RETURN
This program has a subroutine which prints the sequence of characters
stored in the array, starting from one particular element. The subroutine
starts from the line 1000, and the start of the subroutine is marked
with REM SUBROUTINE. It starts from the line 1000 simply because it is
easier then to change the main program and the subroutine separately,
this of course changes when you renumber the whole program.
The main program starts by assigning 10 to N. 10 is the index of the
array element from which the text starts, and this number is always the
same, such number is called constant. We could as well write 10 instead
of N everywhere, but it is a good practice not to use "magic numbers"
in the code. At least when some number is used several times, it is a
good practice to assign that number to a variable, and then use that
variable instead. This also makes the code much more flexible, like
if we want to write texts starting from the element 100 instead of 10,
all we have to do is to change that number in one place.
The main program writes two texts using the same subroutine. You can
see how convenient it is, now every time when we need to print a text
from the array, we only need to call that subroutine.
Before calling the subroutine, N is assigned to variable C. Why we
have to do it is that in Tiny BASIC there are no local variables. Local
variables are like a separate set of variables used in the subroutine or
function only, so that changing these variables do not change the same
variables in the main program. So certain variables should be used in
the subroutines which are never used in the main program. Assigning N
to C is like passing arguments to the subroutine, arguments are the only
variables the subroutine uses from outside of it, and the only argument
in our case is N.
In more complex cases, other ways can be used to pass arguments to a
subroutine and get the results from a subroutine, like the first elements
of the array can be used for that. In even more complex cases it is even
possible to simulate local variables by storing some global variables
in the array in the beginning of the subroutine, and retrieving them
from there before returning from the subroutine.
As you can see, the main program ends with the END statement. Running
the program ends after the last statement of it (other than GOTO)
is executed. But in this example there is a subroutine after the last
statement of the main program. So we used END statement which can exit
the program anywhere in the program.
The subroutine outputs the characters in the array, until the array
element which is 0. The PRINT statement only makes the cursor to go
to the next line. As you can see, the subroutine ends with the RETURN
statement, which jumps back to the line 50 or to the line 80, depending
on where the subroutine was called.
Other subroutines can be called inside a subroutine, but it is not
correct to write a subroutine inside another subroutine.
Developing and debugging programs
---------------------------------
Now you know enough to write many kind of programs. So you should
know more about how to develop and debug the programs.
Tiny BASIC for Curses shows errors only when it runs the program. After
finding an error, the program exits. Error messages are printed by the
tokenizer, except the messages about the GOSUB stack. These messages mean
that something is wrong and either too many GOSUB or RETURN statements
were executed. The number of the program line where the error occurred,
is written in every error message, so that you can browse your program
again and find out why the error occurred on that line. It may be just
because you made a simple writing error.
"Statement not implemented" means that something is wrong with
the first word of the statement. "Token type not what was expected",
followed by the wrong token, means that some other word or operator is
not what it had to be. What you should avoid is dividing by zero, because
the program shall be exited then by the system (called "crash"),
and you cannot see where it happened. The token types are the following:
1 -- * 11 -- > 21 -- < 31 -- RND
2 -- @ 12 -- IF 22 -- - 32 -- )
3 -- CLS 13 -- INCHAR 23 -- NAP 33 -- ;
4 -- COLOR 14 -- INKEY 24 -- <> 34 -- SIZE
5 -- , 15 -- INPUT 25 -- Number 35 -- /
6 -- END 16 -- <= 26 -- OUT 36 -- "
7 -- = 17 -- LET 27 -- + 37 -- THEN
8 -- >= 18 -- Line end 28 -- PRINT 38 -- Variable
9 -- GOSUB 19 -- LOCATE 29 -- REM 39 -- SYSTEM
10 -- GOTO 20 -- ( 30 -- RETURN
All people inevitably make mistakes, especially when they make
something so complex as programs. The brain works differently from
conventional machines, it associates things, thus doing things in certain
sequence or order is not natural for the brain, and it cannot for example
follow a code as faultlessly as an interpreter can do it.
When your program does something different from what you expect, do not
guess what it could be, but start to debug the program. Guessing makes
you to think about many possibilities, and the number of possibilities
may be huge in programming. Thus trying to fix something in the code
by guessing is extremely inefficient. And the greatest peculiarity of
software compared to other kind of technology, is that one cannot see
what happens when it works.
To overcome that invisibility, that which happens has to be made
visible. The way to make it visible is adding the so-called debug code
to your program. Debug code is a temporary code which you insert between
the statements. You may separate it by comments, like REM DEBUG BEGIN
and REM DEBUG END, so that you can later easily remove it. This is
not necessary when your debug code consists only of PRINT statement,
and there is some text which you always print in debug messages.
Most importantly the debug code prints the values of some variables.
Most often it is enough to just print "here", to see whether a certain
place in the code was reached or not. Debug code can be used for much
more though, you can use the power of the computer against the computer,
like by analyzing data in every step. You can also use debug code to
emulate a part of the code which you have not written yet.
Color codes and key codes
-------------------------
The codes below are the same in Windows and Linux. The color codes
are the following:
0 -- black,
1 -- red,
2 -- green,
3 -- yellow,
4 -- blue,
5 -- magenta,
6 -- cyan,
7 -- white.
In order not to add large key code tables to the manual for beginners,
the most important input key codes are written below. The input key
codes are the following:
10 -- Enter,
27 -- Escape,
32 -- Space,
258 -- down arrow,
259 -- up arrow,
260 -- left arrow,
261 -- right arrow,
262 -- Home,
338 -- Page Down,
339 -- Page Up.
Screen-oriented programs
------------------------
So far you wrote programs which worked in line mode. This is what one
always learns first in the programming, but it might be a bit boring. Now
it is a time to do something more fun. Use the character screen, let's
bring in the colors and make things to move on the screen.
There are four additional statements for character screen. COLOR
foreground_color, background_color sets the foreground and
background colors for anything printed on the screen after that
statement. Foreground_color and background_color are both the color codes
described above. CLS clears the screen, at that the color of the screen
shall be the background color set by the previous COLOR statement.
LOCATE line_number, column_number moves cursor to the line and
column on the screen set by line_number and column_number. The line and
column numbers start from zero and are counted top to bottom and left
to right. Cursor is the location on the screen where the next PRINT or
OUT statement prints. Printing changes the cursor location to the right
of the printed text. There shall be no error when printing outside the
screen, but curses then prints at the beginning of the screen instead
of the desired location.
There is one more character screen statement which is not often used,
but which is still important. INCHAR variable assigns the code of the
the character at the cursor location to the variable. This is important
for example when a certain pattern of characters forms the background,
and we want to make something to move or change on that background. In
that case before printing any character to the screen, we can store the
character which is at the location where we want to print, to a variable
or to array. INCHAR var1, var2, var3 also assigns the foreground and
background colors to the variables var2 and var3.
When doing so, we can later remove that which we printed, by restoring
the characters. After that we can print again to a new location, which
gives an impression of something moving on the background or something
temporarily written to the background. The sprites moving on the screen
in games and windows in user interfaces are examples of using that
method. Without INCHAR the whole screen had to be stored somewhere,
which would make such processing unnecessarily too complicated.
Now try to control something on the character screen with keyboard. Write
the following program and run it:
10 COLOR 7, 4
20 CLS
30 REM DO
40 NAP 10
50 INKEY K
60 IF K = 27 END
70 IF K = -1 GOTO 30
80 LOCATE I, J
90 COLOR 7, 4
100 PRINT " ";
110 IF (K = 258) * (I < 24) I = I + 1
120 IF (K = 259) * (I > 0) I = I - 1
130 IF (K = 260) * (J > 0) J = J - 1
140 IF (K = 261) * (J < 65) J = J + 1
150 LOCATE I, J
160 COLOR 7, 6
170 PRINT "Hello World!";
180 GOTO 30
190 REM LOOP
First you see nothing, but when you press arrow keys, you can move
the text "Hello World!" around the screen, Escape key exits the
program. Press Escape twice because the interpreter waits for one
more key. As you can see, most of the program consists of an endless
loop. This loop is similar to the loop in the previous example where
characters were inputted to array. When the key is the Escape key, the
program exits. What follows is a continue statement with the condition
that no key was pressed. Then an empty text is printed to the location I,
J with the background color, this deletes the previous text.
Then the indexes of row and column, I and J, are changed if the arrow
keys were pressed. Notice that the boundaries are checked, so that the
text cannot be moved outside the screen. Always remember to check the
boundaries also when you process text or other data in array. After I and
J are calculated, the location is changed to I, J, and the text "Hello
World!" is printed to the new location with the text background color.
Now you know how to write any kind of screen-oriented
programs. Graphics is in many ways similar, so if you know how to write
screen-oriented programs, you also know several things necessary for
writing graphics programs.
Executing external commands
---------------------------
There is a whole world out there, there are files, there is Internet,
and you likely want to communicate with all that. It is not what the
programming language for beginners should provide, but it was a request
by users to provide such feature, and developers serve the users.
Yet the users should use that feature at their own risk, as it is very
powerful. It even enables to use Tiny BASIC for Curses for scripting,
another question is whether it is the best for that purpose. You cannot
go over the array boundaries, but you may accidentally overwrite that
which you already have in the array.
The statement for that is SYSTEM expr1, expr2 . The first expression
is the beginning of the external command in the array, and the second
is the beginning of the text in the array, both have to be followed by
zero. You have written commands in the terminal or console, such as ls,
dir, etc, and executing programs from the command line. External command
there is the text of such command line. The input of the command is
taken from the text in the array, and the output of the command shall
be written to the array, ending with zero and replacing the previous
text. This method is called filtering though external command.
You can do with external commands a lot which the operating system
enables to do, but there are some restrictions. This is because a separate
shell shall be created when executing an external command. For example
if you change the directory with the SYSTEM statement, this only changes
the directory in that new shell, and not in the shell where your program
runs. Thus you are still in the same directory when you run the next
SYSTEM statement.
Because the interpreter is expected to run on multiple platforms,
the implementation of executing external commands is the most simple,
and such that it can work with different shells. For example many shells
allow to enclose the command line in parentheses, you may have to do
that to make sure that the input is directed to the first command in
the chain of commands connected with pipes.
There is a large number of shell utilities in Linux and not many in
Windows, install GnuWin32 in Windows to get them all. The shell utilities
tee and cat are also included in tinybc. The command tee takes the
standard input and writes it to file, and cat does the opposite, reads
a file and writes it to the standard output. Consider the following code:
10 C = 100
20 @(0) = "tee myfile.txt", 0
30 @(C) = "copy", 10, "del", 10, "dir", 10, "time", 0
40 SYSTEM 0, C
50 @(0) = "cat myfile.txt", 0
60 SYSTEM 0, C
This code writes the text in the array starting at C, to the file
myfile.txt, and then reads the file myfile.txt and writes it to the
array, also starting at C. So the text in the array remains the same,
and shall also be written to the file myfile.txt. The list of Windows
commands there is separated by line feeds (the equivalents in Linux are
cp, rm, ls and date). The command "tee -a myfile.txt" adds the text to
the end of the file. Write the following program and run it:
10 C = 100
20 @(0) = "date", 0
30 SYSTEM 0, C
40 GOSUB 1000
50 END
1000 REM SUBROUTINE
1010 REM DO
1020 IF @(C) = 0 GOTO 1060
1030 OUT @(C)
1040 C = C + 1
1050 GOTO 1010
1060 REM LOOP
1070 RETURN
As you can see, the subroutine for printing is almost the same as in
previous examples. This program prints the current date. But that date
is the output of the external command named date, which you can also
write in the terminal or console after the command prompt.
Loading, saving and renumbering programs
----------------------------------------
Finally more about what you can do at the command prompt. By now you
only wrote test programs and then deleted them again. Well, you could
also paste the code to tinybc prompt by right clicking the mouse on the
terminal. But you certainly want to store some of your programs somewhere,
so that you can later load them again.
For storing files you should exit tinybc, and in the terminal go to
the directory where you want to store your files (current directory),
using the command cd directory_name. In Linux terminal you only have to
write the first letters of the directory name and press TAB, this fills
in the rest if the directory exists. In Windows Explorer, holding down
shift key when right clicking on the directory, enables to open console
with that directory as current. Then start tinybc and enter your program.
Programs are stored in files, which usually have the .bas extension to
distinguish them from other files. The commands SAVE and LOAD are for
saving and loading. To save your program, type S filename and press
Enter. Filename is the name of your program. You can also save your
programs to other directory than current, and also load them from there,
if you write path as the file name, such as tests/myprogram.bas . By
using absolute path which starts with / (\ in Windows) you can also
save to or load from the directories other than these below the current
directory. L filename loads the program, remember that this deletes your
current program.
It is also possible to run programs directly from file when you are
in terminal, tinybc filename does that. This means that you can also
edit your program in file. It is the best to edit programs with gvim
in Linux and with Wordpad in Windows, do not use a word processor such
as Word or AbiWord for that. You can also start tinybc and load your
program at once, tinybc -i filename does that.
And finally something which you most likely want to know, tinybc
-number filename renumbers your program. For example tinybc -100
myprogram.bas renumbers the program myprogram.bas so that the number of
the first line shall be 100. Number there is the number which you want
the first line to have, line numbers shall be incremented by 10. When
the expression is anything other than a number after GOTO, renumbering
shall not change that expression, so the expression may become wrong.
That's all folks
----------------