-
Notifications
You must be signed in to change notification settings - Fork 0
/
basic.c
3068 lines (2580 loc) · 73.6 KB
/
basic.c
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
/* basic.c - a BASIC interpreter for the Arduino Due
and posix (linux) systems.
(C) 2020 Kurt Theis under the GPL 3.0 license
There is no warrantee that this software will
work for any purpose. Please see the license document
included with this work.
----------------------------------------------------------
----------------------------------------------------------
This is a Tiny BASIC language interpreter written
for both posix systems and the Arduino Due. It should
work on anything with a command line and a c compiler.
First uncomment the define for the platform on ~line 310.
for Arduino Due:
#define arduino
for posix/linux:
#define posix
And comment the opposite. Then compile:
For posix systems (linux etc):
compile with: cc -o basic basic.c -Wall
For Arduino Due:
rename basic.c to basic.ino
Use the Arduino IDE to compile and
upload this program.
------------------------------
To run on a posix (linux) machine::
basic [filename] where filename is an optional basic
source file. After loading, the program will run until a
STOP, END or EXIT statement.
If a filename is not given on the command line, basic
will start with an Ok> prompt and place you in the editor
mode with an empty file.
----------------
On an Arduino Due:
load the program using the IDE and plug in a usb
cable to the usb port closest to the power jack. Terminal
defaults to 9600/8/N/1 and vt100/vt102. Putty, minicom,
etc should work.
The Arduino Due requires an SD card for the file commands
to work. I use the Adafruit SD card using SPI. The chip
select #define is on about line 310 of this file. It must
be set to the pin number you use on your board setup.
-----------------------------------------------------------------
-----------------------------------------------------------------
NOTE: Although statements, expressions and functions appear
in UPPER CASE, the basic lines entered are converted to lower
case when typed. You can use either UPPER or lower case in
your statements. Characters between double quotes ("") or
parens () are NOT converted.
-----------------------------------------------------------------
These are the statements that this version of basic recognizes:
LET [a-z/@(a-z/0-9)$]=[expr] (see below for expr defines)
INPUT ["",;$][a-z]
PRINT [expr][a-z][0-9]@(a-z/0-9)[; , ""$]
FILEREAD [a-z][,]
FILEWRITE [a-z][,;""][@(a-z)]
GOTO [0-9]
GOSUB [0-9]
RETURN
REM
IF [a-z][logical][a-z/0-9] [THEN/GOTO/GOSUB] [line number]
IF [a-z][logical][a-z/0-9] [RETURN/STOP]
STOP
END
EXIT
SLEEP [0-9] (integer seconds) (NOTE:posix only)
DELAY [0-9/a-z] (value is in msec)
FOR [a-z]=[a-z/0-9/expr] TO [a-z/0-9/expr] STEP [+-][0-9/a-z/expr]
NEXT [a-z]
CLEAR
DIM (0-9/a-z/[expr]) NOTE: Array NOT cleared at start
FILEOPEN [a-z/0-9][Rr/Ww]
FILECLOSE
--- Arduino Specific Statements ---
PINSET [0-9/a-z]
PINCLR [0-9/a-z]
expr is a simple assignment (5, a+20, c-5, x) used for LET, PRINT
and FOR. expr returns a numeric integer value.
expr recognized the following operands:
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulo
& Logical and
| Logical or
^ Logical xor
~ Compliment (bits inside a variable or value)
E Exponent (ie 2E3 = 2*2*2)
For the Arduino, expr also includes:
PINREAD(n) w/n = pin# [0-9/a-z] digital
PINREAD(n) w/n = A0-A11 analog
Logical comparisons (logical):
The following symbols are used in the IF statement to compare 2 values:
= lvalue is equal to rvalue
# lvalue is not equal to rvalue
< lvalue is less than rvalue
> lvalue is greater than rvalue
& lvalue logical and with rvalue
| lvalue logical or with rvalue
^ lvalue logical xor with rvalue
Functions:
ABS(x) w/x = [a-z] absolute value of variable a-z
RANDOM() random number between 0 and 2^32/2 -1
Functions return a numeric integer value
------------------------------------------------------------------------
Line numbers MUST be used, and be in the range of 1 thru 32767.
Lines may be blank (newline terminated). However, the basic
editor does not save blank lines to memory. If you want them,
create the file with an external editor and load the program
either from the command line or with the 'load' command
(or use the co-resident editor).
Numeric variables are 32-bit integer (a-z). There is a single
integer array called @(). The dim nn statement sets up the
array. nn is the decimal size of the array, maximum size is
ARRAYMAX integers. On the Arduino, that's 4*ARRAYMAX
(see #define ARRAYMAX below).
Text variables are a$ - z$ and are MAXLINE characters
long (#define in line ~ 310). Text vars are used in LET,
INPUT and PRINT statements:
10 LET a$="hello world"
20 INPUT "enter name ",n$
30 PRINT a$,n$
Spaces MUST be used between line numbers and keywords, and
between multiple keywords (ie. 10 for n=1 to 20 step 2).
Variable assignments MUST NOT contain any spaces
(ie. 10 let a=5, b=a*20/3, c=a*b/2) but can use comma seperators
and spaces between commas and the next assignment.
-------------------------------------------------------------------------
*** Commands ***
run [linenumber] Start running the basic program. All variables are cleared.
If linenumber is given then no variables are cleared. The
basic program starts running from the given line.
list Display the basic program in memory.
cls Clear the display
size/mem Show free (unused) memory.
*load [filename] Load the file 'filename' into memory clearing out any
prior code.
*save [filename] Save the program in memory to 'filename'.
*dir [dirname] Show a directory of files in the given directory. Default
directory is /. ex: dir /basic/
*flist List a file on the drive, no change to local memory.
**slist List the program in memory to Serial Port #1 (printer etc).
*delete Delete a file
new Delete the program currently in memory.
exit Exit the basic interpreter.
trace Toggle program tracing ON/OFF.
dump Show a hex memory dump of the basic file.
edit Jump to co-resident line editor. 'exit' to return to basic,
'help' to show edit commands while in editor.
* only work if an SD card is connected to the SPI
port of the Arduino due. On a posix (linux) machine,
these commands access the current directory you are in.
** This only works on the Arduino due.
--------------------------------------------------
--------------------------------------------------
*** BASIC Line Editor Usage ***
At the OK> prompt in BASIC you can enter lines of BASIC
code preceeded by a line number:
10 REM
20 FOR n=1 to 10
30 PRINT n, n*n
40 NEXT n
To delete an existing BASIC line, enter the line number and
press enter. To edit a BASIC line, just re-enter the line number
followed by the BASIC code.
---------------------------------------------------
---------------------------------------------------
*** Edit Line Editor Commands ***
A seperate line editor is invoked by typing 'edit' at
the OK> prompt of the BASIC interpreter. This is an
Arduino-only editor (posix has a lot more and better
editors).
The BASIC line editor and this line editor share the
same memory space. The BASIC editor is better for writing
BASIC code, this line editor is better for writing straight
text lines.
(NOTE: The basic.ino and edit.ino files are actually part
of a bigger package for the arduino due.)
When started, you will see a > prompt. There are 3 modes
to the editor: command mode, append mode and insert mode,
and the prompts show which mode you are in:
> command mode
a> append mode
i> insert mode
In command mode, the following commands are accepted:
exit, cls, list, new, mem, dir, save [filename],
load [filename], a, i #, d #, f [string], help.
help shows a command summary.
exit exits the editor and returns to BASIC
cls clears the screen
list shows the buffer contents preceeded by a line number.
new clears the buffer
mem shows available memory
dir shows files in the directory
save [filename] saves the buffer to filename
load [filename] loads a file to the buffer
a enters the append mode. All characters typed
will be stored at the end of the buffer. To exit
append mode type .q and enter on an otherwise
empty line. You will return to the command mode.
i [line number] starts inserting text BEFORE line number.
Pressing .q and enter on an otherwise empty line exits
insert mode and returns to the command mode.
d [line number] deletes the line referenced by line number.
f [string] finds every occurance of [string] in the buffer
preceeded by it's line number.
TODO:
nested for/next loops
virtual memory for buffer space and arrays
larger gosub/return stack
pwm output routines
posix gpio routines
ctrl-c for posix (arduino already has it)
goto/gosub to a variable
arduino 'tone' function
***** *****
***** Version Information *****
***** *****
ver 0.56 minor mod to list(), added 8080 emulator (command i80)
ver 0.55 DELAY(msec) works for posix now too
ver 0.54 added an editor, string variables
ver 0.53 allow user to select directory in dir command
ver 0.52 change size of basic ram for arduino,
remove \n from run at start, added cls command
ver 0.51 2E5 and 2e5 equiv (linetolower() caused issue)
ver 0.50 moved from alpha to beta, released to the wild
*/
/* !!!!!!!!!! NOTE NOTE NOTE NOTE NOTE !!!!!!!!!!! */
/* how are we coding this? (choose posix/arduino) */
//#define posix // build for posix/linux
#define arduino // build for arduino
#define MAXLINE 80 // max chars in a line
#define SDCARDCS 53 // chip select for the SD card
/* !!!!!!!!!! NOTE NOTE NOTE NOTE NOTE !!!!!!!!!!! */
// No #define's below this point need to be touched.
//#define dueMini // you won't need this for basic or edit
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifdef posix
#include <unistd.h> // for posix sleep()
#endif
#ifdef arduino
#include <malloc.h> // for memory size determination
#include <SPI.h>
#include <SD.h>
#endif
// this is not part of basic, but included since it's how my stuff is wired
#ifdef dueMini
#include "Adafruit_FRAM_SPI.h"
uint8_t FRAM_CS = 52; // chip select for SPI fram chip
Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_CS); // use hardware SPI
uint32_t fram_addr = 0;
uint8_t fram_data = 0;
#endif
/* general system defines */
#define PROMPT "Ok> "
#ifdef posix
#define BUFSIZE 65536 // ram buffer memory for bigger computers
#define ARRAYMAX 65536 // max size of @() array (4 bytes/element)
// NOTE: on a posix machine, these are really unlimited due to VM
#endif
#ifdef arduino
#define BUFSIZE 32768 // ram buffer memory (arduino) for basic statements (appx 23 bytes/line)
#define ARRAYMAX 12032 // max size of @() array (4 bytes/element)
// NOTE: If you need more program size, adjust array size down so that you have 1024 bytes on top
// 16384 + (12032 * 4) + 1024 = 65536 (every byte of buffer = 4 bytes of array)
#define MAXRAND 2147483647 // 2^31-1
#endif
#define MAXLINENUMBER 32767 // increase if you need to
#define MAXRETURNSTACKPOS 10 // basic: max stack depth
#define HEADER "\r\nTiny+ Basic (C) 2020 Kurt Theis"
/* define routine return values */
#define NORMAL_RETURN -1 // basic returned OK
#define ERROR_RETURN -2 // basic returned an error
#define END_RETURN -3 // basic encountered END
#define STOP_RETURN -4 // basic encountered STOP
/* define error messages */
#define ERR1 "syntax error\r\n"
#define ERR2 "syntax error in line "
#define ERR3 "bad char in line "
#define ERR4 "out of memory"
#define ERR5 "buffer is empty\n\r"
#define ERR6 "line number is out of range "
#define ERR7 "bad char in line number "
#define ERR8 "line not found in "
#define ERR9 "line not recognized in"
#define ERR10 "usage: load filename\r\n"
#define ERR11 "usage: save filename\r\n"
#define ERR12 "error creating file in "
#define ERR13 "error reading file\r\n"
#define ERR14 "usage: flist filename\r\n"
#define ERR15 "usage: delete filename\r\n"
#define ERR16 "file not found\r\n"
#define ERR17 "unexpected error in line "
#define ERR18 "end at line "
#define ERR19 "stop at line "
#define ERR20 "array re-dimension in line "
#define ERR21 "array size error in line "
#define ERR22 "dim: no action taken in line "
#define ERR23 "array too big in line "
#define ERR24 "out of memory in line "
#define ERR25 "stack full in line "
#define ERR26 "return without gosub in line "
#define ERR27 "bad format in line "
#define ERR28 "bad expression in line "
#define ERR29 "bad array in line "
#define ERR30 "array index too large in line "
#define ERR31 "unknown variable in line "
#define ERR32 "next without for in line "
#define ERR33 "unexpected next error in line "
#define ERR34 "usage: fileopen filename Rr/Ww in line "
#define ERR35 "file already open in line "
#define ERR36 "bad mode in fileopen in line "
#define ERR37 "file not open in line "
#define ERR38 "no file open for write in line "
#define ERR39 "unterminated string in line "
#define ERR40 "no file open for read in line "
#define ERR41 "unterminated quotes in line "
#define ERR42 "expression empty in line "
#define ERR43 "bad pin number in line "
#define ERR44 "missing closing ) in line "
#define ERR45 "array bounds error in line "
#define ERR46 "divide by zero error in line "
#define ERR47 "unknown operand error in line "
#define ERR48 "index to array must be a variable in line "
#define ERR49 "logical eval error in line "
#define ERR50 "directory error "
/* ******************** */
/* pre-define functions */
/* ******************** */
/* external (non-basic) routines */
extern void run80(void);
/* editor routines */
void list(char[]);
int getmaxlinenum(void);
int isline(int);
void fileload(char *);
void filesave(char *);
void flist(char *);
void dir(char*);
int run(char *);
void tokenize(char[]);
void linetolower(char *);
void filedelete(char *);
void showmem();
/* basic subroutines */
int parse(char *);
int setlinenumber(char[],int);
int parse_print(char[]);
int parse_input(char[]);
int eval(char *);
int parse_let(char[]);
int evallogic(char *);
int parse_if(char[]);
int parse_for(char[]);
int parse_next(char[]);
int isoperand(char);
int domath(int,char,int);
int dueanalog(int);
int fileopen(char[],char[]);
int fileclose(void);
int fileread(char[]);
int filewrite(char[]);
/* **************** */
/* global variables */
/* **************** */
#ifdef posix
FILE *diskfile; // used for fileopen/close etc
#endif
#ifdef arduino
File root; // used in dir
File sdFile; // used in save, load
// used in showmem()
extern char _end;
char *ramstart=(char *)0x20070000;
char *ramend=(char *)0x20088000;
extern "C" char *sbrk(int i);
/* // used for virtual mem
using namespace virtmem;
SDVAlloc valloc;
SdFat sd;
*/
#endif
unsigned char *buffer;
unsigned int position;
unsigned int maxline;
int error=0; // when a routine fails, error gets set
int DEBUG = 0; // enables trace in parse()
char printmessage[MAXLINE+(MAXLINE/2)]; // universal print routine
int arraymax = 0; // max size of array, assigned in DIM
unsigned int foraddr=0; // loop address for/next
unsigned char forvar; // hold var name for/next
int tovar=0; // final number for/next
int forstep=0; // hold step size
/* define storage for return stack for gosubs */
int return_stack[MAXRETURNSTACKPOS]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; // 10 deep
int return_stack_position = 0;
/* define storage for integer variables a-z */
int intvar[26]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* define array for DIM and @(n) */
int* intarray = (int*)NULL;
/* define text variables (this uses 2K ram - could be done better) */
char textvar[26][80] = {};
/* showmem - routine to read arduino due registers and report memory usage */
/* saw this on stackoverflow.com, and many other places, and don't know who to attribute to */
void showmem() {
#ifdef arduino
/* due mem usage */
char *heapend=sbrk(0);
register char * stack_ptr asm("sp");
struct mallinfo mi=mallinfo();
Serial.print(F("\rDynamic RAM used "));
Serial.println(mi.uordblks);
Serial.print(F("\rProg Static Ram used "));
Serial.println(&_end - ramstart);
Serial.print(F("\rStack Ram used "));
Serial.println(ramend - stack_ptr);
Serial.print(F("\rFree Mem "));
Serial.println(stack_ptr - heapend + mi.fordblks);
#endif
return;
}
#ifdef arduino
/* serial fgets : replacement for fgets */
void sgets(char *line) {
unsigned int cnt=0;
char ch;
memset(line,0,MAXLINE);
while (1) {
if (Serial.available() > 0) {
ch = Serial.read();
if (ch == 0x08) { // backspace
if (cnt > 0) {
Serial.print(F("\b"));
Serial.print(F(" "));
Serial.print(F("\b"));
line[cnt] = '\0';
cnt--;
} else {
continue;
}
continue;
}
if (ch == '\r') ch = '\n';
if (cnt+1 >= MAXLINE-2) { // MAXLINE reached
Serial.write(0x07); // ctrl-G bell
continue; // don't save anything
}
Serial.print(ch); // save to buffer
line[cnt++] = ch;
if (ch == '\n') {
Serial.print('\r');
return;
}
}
}
}
#endif
/* ***** */
/* SETUP */
/* ***** */
#ifdef arduino
Sd2Card card;
SdVolume volume;
void setup() {
Serial.begin(9600); // console I/O port 0
Serial1.begin(9600); // printer I/O port 1
analogReadResolution(16);
/* set up SD card */
if (!SD.begin(SDCARDCS)) { // SD chip select in #define above
Serial.println(F("SD card init failed!"));
Serial.println(F("Power down, fix and restart"));
while (1);
}
/* test spi fram */
#ifdef dueMini
fram_addr = 0;
fram_data = 128;
if (fram.begin(3)) {
fram.writeEnable(true);
fram.write(fram_addr, &fram_data, sizeof(int32_t));
fram.writeEnable(false);
fram.read(fram_addr,&fram_data, sizeof(int32_t));
if (fram_data != 128)
Serial.println(F("fram test: bad data returned"));
} else
Serial.println(F("Cannot access FRAM memory"));
#endif
/* initialize virtual mem */
//valloc.start();
}
#endif
/* ***** */
/* PROUT */
/* ***** */
/* printout - send string to stdout/serialout */
void prout(char message[MAXLINE+(MAXLINE/2)]) {
#ifdef posix
printf("%s",message);
#endif
#ifdef arduino
Serial.print(message);
#endif
return;
}
/* **************** */
/* main/loop */
/* **************** */
#ifdef posix
int main(int argc, char **argv) {
#endif
#ifdef arduino
void loop() {
#endif
int pos=0;
int n;
char line[MAXLINE]={}, linenum[32]={};
char *p;
basicLoop: // when external programs exit, jump back here to restart things
/* basic program is stored in ram */
buffer = (unsigned char *)malloc(BUFSIZE);
if (buffer == NULL) {
prout("out of memory");
#ifdef posix
return 1;
#endif
#ifdef arduino
while(1); // wait for reset
#endif
}
// clear the buffer before start
memset(buffer,0,BUFSIZE);
position = 0; // set start position
maxline = 0; // highest line number
sprintf(printmessage,"%s\r\n",HEADER);
prout(printmessage);
sprintf(printmessage,"%d Bytes Free\r\n",BUFSIZE-position);
prout(printmessage);
#ifdef posix
/* test command line: if argv[1] = program name, load & run it */
if (argc == 2) {
char temp[strlen(argv[1])+5];
strcpy(temp,"load ");
strcat(temp,argv[1]);
fileload(temp); // format of the load command requires 'load' before filename
/* run it */
run("x"); // x is dummy, not used
} // at end jump to editor
#endif
/***********************************/
/* Main Command Loop */
/***********************************/
while (1) {
/* show prompt, get a line or command */
memset(line,0,MAXLINE);
maxline = getmaxlinenum();
prout(PROMPT);
#ifdef posix
fgets(line,MAXLINE,stdin);
#endif
#ifdef arduino
sgets(line);
#endif
if (line[0] == '\n') continue;
line[strlen(line)] = '\0';
#ifdef posix
/* exit - exit out of this program */
if (strncmp(line,"exit",4)==0) {
if (intarray != NULL)
free(intarray); // free up the array ram
free(buffer); // and program memory
return 0;
}
#endif
/* trace - trace program flow */
if (strncmp(line,"trace",4)==0) {
DEBUG = abs(DEBUG-1);
if (DEBUG) {
sprintf(printmessage,"Trace ON\r\n");
prout(printmessage);
}
else {
sprintf(printmessage,"Trace OFF\r\n");
prout(printmessage);
}
continue;
}
/* clear the display */
if (strncmp(line,"cls",3)==0) {
#ifdef arduino
Serial.println(F("\e[H\e[J"));
#endif
continue;
}
#ifdef arduino
/* jump to line editor */
if (strncmp(line,"edit",4)==0) {
ledit();
continue;
}
#endif
/* list - display basic listing in buffer */
if (strncmp(line,"list",4)==0) {
list(line);
continue;
}
/* slist - send listing to serial 1 (if arduino) */
#ifdef arduino
if (strncmp(line,"slist",5)==0) {
list(line);
continue;
}
#endif
/* new - clear the buffers, reset pointers */
if (strncmp(line,"new",3)==0) {
position=0;
memset(buffer,0,BUFSIZE);
if (intarray != NULL)
free(intarray); // clear DIM memory
for (int i=0; i<26; i++)
intvar[i]=0; // clear vars a-z
intarray=(int*)NULL;
arraymax=0;
maxline=0;
continue;
}
/* dump - hex dump of program listing (used in debugging the editor) */
if (strncmp(line,"dump",4)==0) {
int addr = 0;
while (addr < position) {
sprintf(printmessage,"%04X ",addr);
prout(printmessage);
for (n=0; n<16; n++) {
sprintf(printmessage,"%02X ",buffer[addr+n]);
prout(printmessage);
}
prout(" ");
for (n=0; n<16; n++) {
sprintf(printmessage,"%c",isprint(buffer[addr+n])?buffer[addr+n]:'.');
prout(printmessage);
}
prout("\r\n");
addr += 16;
}
prout("\r\n");
continue;
}
/* mem/size - show free memory */
if ((strncmp(line,"mem",3)==0) || (strncmp(line,"size",4)==0)) {
sprintf(printmessage,"Basic Program Storage: %d bytes free\r\n",BUFSIZE-position);
prout(printmessage);
showmem();
continue;
}
/* load - load file to buffer */
if (strncmp(line,"load",4)==0) {
fileload(line);
continue;
}
/* save - save buffer to file */
if (strncmp(line,"save",4)==0) {
filesave(line);
continue;
}
/* flist - display file contents */
if (strncmp(line,"flist",5)==0) {
flist(line);
continue;
}
/* dir - show directory */
if (strncmp(line,"dir",3)==0) {
prout("\r\n");
dir(line);
continue;
}
/* delete - delete a file from the file system */
if (strncmp(line,"delete",6)==0) {
filedelete(line);
continue;
}
/* run - run the basic program */
if (strncmp(line,"run",3)==0) {
if (position==0) {
prout(ERR5); // empty buffer
continue;
}
run(line);
memset(line,0,MAXLINE);
#ifdef arduino
/* clear any chars in buffer caused by ctrl-c */
if (Serial.available())
while(Serial.available());
#endif
prout("\r\n"); // in case print terminated with ;
continue;
}
#ifdef dueMini
if (strncmp(line,"i80",3)==0) { // 8080 emulator
// free up used memory
free(buffer);
position = 0;
i80(); // jump to 8080 emulator
// restore memory, reset pointers
goto basicLoop;
}
#endif
/* if the 1st character of a line isn't a number, show an error */
if (!(isdigit(line[0]))) {
prout(ERR1); // syntax
continue;
}
/* ********************** */
/* end of command testing */
/* ********************** */
/* first char IS a line number - save in memory */
/* test line number count */
sscanf(line,"%s ",linenum);
if (atoi(linenum) < 1 || atoi(linenum) > MAXLINENUMBER) {
prout(ERR6); // line # out of range
continue;
}
/* look for bad trailing chars in line number */
if (!(isdigit(linenum[strlen(linenum)-1]))) {
prout(ERR3); // bad char in line #
continue;
}
/*
* Memory savings when converting to tokens is only 18%,
* hardly worth the added code. With 16K ram you get about
* 744 lines of basic code. Quite a lot for a controller.
*/
//tokenize(line);
linetolower(line); // all but quoted and inside () lower case
/* room to add the line? */
if (strlen(line) + position > BUFSIZE-1) {
prout(ERR4); // out of memory
continue;
}
/* *********************************************** */
/* if line number > maxline, append line to buffer */
/* *********************************************** */
if (atoi(linenum) > maxline) {
/* test if line is blank (don't insert blank lines) */
int FLAG=0;
for (int n=strlen(linenum); n<strlen(line); n++)
if (!(isspace(line[n]))) FLAG=1;
if (!FLAG) continue;
p=line;
while (*p != '\0') {
buffer[position++] = *p++;
}
if (position >= BUFSIZE-1) {
prout(ERR4); // out of memory
}
maxline = getmaxlinenum();
continue;
}
/* ********************************************************* */
/* if line number == existing line number, delete or replace */
/* ********************************************************* */
if ((pos = isline(atoi(linenum))) != -1) {
int FLAG=0;
/* pos points to start of line to replace */
unsigned char *start, *end;
end = start = buffer+pos; // start of line
while (*end++ != '\n'); // look for \n - end = end of line
/* delete line */
while (end-buffer <= position)
*start++ = *end++;
position -= (end-start); // line is deleted
/* clear the old code above old position */
for (n=position+1; n<BUFSIZE; n++) buffer[n]='\0';
/* test if entered line is empty (delete) */
if (strlen(line)-strlen(linenum) == 1) {
maxline = getmaxlinenum();
continue; // line was empty - we're done
}
/* test if line is blank (don't insert blank lines) */
for (n=strlen(linenum); n<strlen(line); n++)
if (!(isspace(line[n]))) FLAG=1;
if (!FLAG) continue;
/* else shift buffer up by strlen(line) */
memmove(&buffer[pos+strlen(line)],&buffer[pos],position-pos);
position += strlen(line);
/* insert line at pos */
for (int i=pos, n=0; i<=pos+(strlen(line)-1); i++)
buffer[i] = line[n++];
maxline = getmaxlinenum();
continue;
}
/* ***************************************** */
/* line# < maxline - insert line into buffer */
/* ***************************************** */
if (atoi(linenum) < maxline) {
int n, i, start=0, end=1;
char temp[MAXLINE]={};
char LINEN[6]; // hold line number from temp
/* test if line is blank (don't insert blank lines) */