Subversion Repositories Krakow BASIC

Rev

Rev 28 | Rev 36 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 nishi 1
/* $Id: basic.c 29 2024-09-05 04:27:28Z nishi $ */
2
 
3
/* Krakow BASIC - Multi-platform simple BASIC */
4
 
5
#if defined(PLATFORM_SHIROI)
6
 
7
#include "dri/text.h"
8
#include "dri/video.h"
9
#include "dri/math.h"
10
 
11
#include "mem.h"
12
#include "char.h"
13
#define PLATFORM "Shiroi"
14
#define NEWLINE "\r\n"
15
#define BREAKKEY
16
 
29 nishi 17
#elif defined(PLATFORM_MSX)
18
 
19
#define PLATFORM "MSX"
20
#define NEWLINE "\r\n"
21
#define BREAKKEY
22
 
23
#define mull(x, y) ((x) * (y))
24
#define divl(x, y) ((x) / (y))
25
 
26
#include <ctype.h>
27
#include <string.h>
28
#include <stdlib.h>
29
 
30
#define agetch(x) oggetch(0)
31
 
32
void basic(void);
33
 
34
void main(void){
35
	basic();
36
}
37
 
38
char _wgetch(char wait) __naked {
39
	__asm
40
		ld hl, #2
41
		add hl, sp
42
 
43
		ld a, (hl)
44
 
45
		cp #1
46
		jp z, wait
47
 
48
		call 0x9c
49
		jp nz, wait
50
		ld l, a
51
		ld h, #0
52
		ret
53
 
54
wait:
55
		call 0x9f
56
		ld l, a
57
		ld h, #0
58
		ret
59
	__endasm;
60
}
61
 
62
char oggetch(char wait){
63
	char c = _wgetch(wait);
64
	if(c == '\r') return '\n';
65
	if(c == 3) return 1;
66
	return c;
67
}
68
 
69
void putchar(char c) __naked {
70
	__asm
71
		ld hl, #2
72
		add hl, sp
73
		ld a, (hl)
74
		call 0xa2
75
		ret
76
	__endasm;
77
}
78
 
79
void putstr(const char* str){
80
	int i;
81
	for(i = 0; str[i] != 0; i++) putchar(str[i]);
82
}
83
 
84
void putnum(int a){
85
	char numbuf[64];
86
	int incr = 63;
87
	numbuf[incr--] = 0;
88
	int i;
89
	while(1){
90
		numbuf[incr--] = (a % 10) + '0';
91
		a /= 10;
92
		if(a == 0) break;
93
	}
94
	putstr(numbuf + incr + 1);
95
}
96
 
97
char strcaseequ(const char* a, const char* b){
98
	int i;
99
	if(strlen(a) != strlen(b)) return 0;
100
	for(i = 0; a[i] != 0; i++){
101
		if(toupper(a[i]) != toupper(b[i])) return 0;
102
	}
103
	return 1;
104
}
105
 
106
void change_color(unsigned char c) __naked {
107
	__asm
108
		ld hl, #2
109
		add hl, sp
110
 
111
		ld a, (hl)
112
		and a, #0xf
113
		ld (0xf3ea), a
114
 
115
		ld a, (hl)
116
		and a, #0xf0
117
		sra a
118
		sra a
119
		sra a
120
		sra a
121
		ld (0xf3e9), a
122
 
123
		ld a, #1
124
		call 0x62
125
 
126
		ret
127
	__endasm;
128
}
129
 
130
#define strnum atoi
131
 
132
void clear(void) __naked {
133
	__asm
134
		call 0x6f
135
		ld a, #15
136
		ld (0xf3e9), a
137
		ld a, #1
138
		ld (0xf3ea), a
139
		ld a, #1
140
		call 0x62
141
		ret
142
	__endasm;
143
}
144
 
145
#define killcursor(x)
146
#define cursor(x)
147
 
9 nishi 148
#elif defined(PLATFORM_UNIX) || defined(PLATFORM_WINDOWS) || defined(PLATFORM_ARDUINO) || defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
2 nishi 149
 
150
#if defined(PLATFORM_WINDOWS)
151
#define PLATFORM "Windows"
28 nishi 152
#define NO_PEEKPOKE
2 nishi 153
#elif defined(PLATFORM_UNIX)
154
#define PLATFORM "Unix"
28 nishi 155
#define NO_PEEKPOKE
2 nishi 156
#elif defined(PLATFORM_ARDUINO)
157
#define PLATFORM "Arduino"
158
#define NEWLINE "\r\n"
159
#define BREAKKEY
4 nishi 160
#elif defined(PLATFORM_C64)
161
#define PLATFORM "Commodore-64"
162
#define NEWLINE "\r\n"
163
#define BREAKKEY
164
#include <conio.h>
9 nishi 165
#elif defined(PLATFORM_PET)
166
#define PLATFORM "Commodore-PET"
167
#define NEWLINE "\r\n"
168
#define BREAKKEY
169
#include <conio.h>
170
#include <peekpoke.h>
6 nishi 171
#elif defined(PLATFORM_A800XL)
172
#define PLATFORM "Atari-800XL"
173
#define NEWLINE "\n"
174
#define BREAKKEY
175
#include <conio.h>
7 nishi 176
#elif defined(PLATFORM_APPLE2)
177
#define PLATFORM "Apple2"
178
#define NEWLINE "\n"
179
#define BREAKKEY
180
#include <conio.h>
2 nishi 181
#endif
182
 
4 nishi 183
#define mull(x, y) ((x) * (y))
184
#define divl(x, y) ((x) / (y))
185
#define killcursor(x)
186
#define cursor(x)
187
#define strnum atoi
188
 
2 nishi 189
#ifndef NEWLINE
190
#define NEWLINE "\n"
191
#endif
192
 
193
#include <stdio.h>
194
#include <stdlib.h>
195
#include <string.h>
196
#include <ctype.h>
197
#include <stdbool.h>
198
 
199
#if defined(__MINGW32__)
200
#include <conio.h>
201
#include <windows.h>
202
#elif defined(PLATFORM_ARDUINO)
203
#define BAUD 9600
204
#include <avr/io.h>
205
#include <util/delay.h>
206
#include <util/setbaud.h>
207
#define BUFFER_SIZE (1024)
208
#define LINE_BUFFER_SIZE (128)
209
#define LINES (32)
210
#undef putchar
211
#define putchar uart_putchar
212
#elif defined(PLATFORM_UNIX)
213
#include <termios.h>
9 nishi 214
#elif defined(PLATFORM_PET)
215
#define BUFFER_SIZE (4 * 1024)
216
#undef killcursor
217
#undef cursor
218
#define killcursor(x) cursor(0)
219
#define cursor(x) cursor(1)
4 nishi 220
#elif defined(PLATFORM_C64)
221
#define BUFFER_SIZE (16 * 1024)
222
#undef killcursor
223
#undef cursor
224
#define killcursor(x) cursor(0)
225
#define cursor(x) cursor(1)
6 nishi 226
#elif defined(PLATFORM_A800XL)
227
#define BUFFER_SIZE (16 * 1024)
228
#undef killcursor
229
#undef cursor
230
#define killcursor(x) cursor(0)
231
#define cursor(x) cursor(1)
7 nishi 232
#elif defined(PLATFORM_APPLE2)
233
#define BUFFER_SIZE (8 * 1024)
234
#undef killcursor
235
#undef cursor
236
#define killcursor(x) cursor(0)
237
#define cursor(x) cursor(1)
2 nishi 238
#endif
239
 
240
#if defined(PLATFORM_ARDUINO)
241
int uart_putchar(char c) {
242
	while(!(UCSR0A & _BV(UDRE0)))
243
		;
244
	UDR0 = c;
245
	return 0;
246
}
247
 
248
void uart_init(void) {
249
	UBRR0H = UBRRH_VALUE;
250
	UBRR0L = UBRRL_VALUE;
251
 
252
	UCSR0B |= _BV(TXEN0) | _BV(RXEN0);
253
 
254
	UCSR0C |= _BV(UCSZ00) | _BV(UCSZ01);
255
}
256
#endif
257
 
4 nishi 258
#define agetch(x) oggetch(0)
259
char oggetch(char wait) {
260
	int c;
2 nishi 261
#if defined(PLATFORM_WINDOWS)
262
rescan:
263
	c = _getch();
264
	if(c == '\r') return '\n';
265
	if(c == '\n') goto rescan;
266
#elif defined(PLATFORM_UNIX)
4 nishi 267
	c = getchar();
2 nishi 268
	if(c == EOF) return -1;
269
	if(c == '\r') return '\n';
270
#elif defined(PLATFORM_ARDUINO)
271
rescan:
7 nishi 272
	if(wait) {
4 nishi 273
		if(!(UCSR0A & _BV(RXC0))) return 0;
7 nishi 274
	} else {
275
		while(!(UCSR0A & _BV(RXC0)))
276
			;
4 nishi 277
	}
2 nishi 278
	c = UDR0;
279
	if(c == '\r') return '\n';
280
	if(c == '\n') goto rescan;
281
	if(c == 3) return 1;
9 nishi 282
#elif defined(PLATFORM_C64) || defined(PLATFORM_PET)
7 nishi 283
	if(!wait) {
4 nishi 284
		if(!kbhit()) return 0;
285
	}
286
	c = cgetc();
287
	if(c == EOF) return -1;
288
	if(c == '\r') return '\n';
289
	if(c == 20) return 8;
290
	if(c == 3) return 1;
6 nishi 291
#elif defined(PLATFORM_A800XL)
7 nishi 292
	if(!wait) {
6 nishi 293
		if(!kbhit()) return 0;
294
	}
295
	c = cgetc();
296
	if(c == EOF) return -1;
297
	if(c == '\r') return '\n';
298
	if(c == 126) return 8;
299
	if(c == 3) return 1;
7 nishi 300
#elif defined(PLATFORM_APPLE2)
301
	if(!wait) {
302
		if(!kbhit()) return 0;
303
	}
304
	c = cgetc();
305
	if(c == EOF) return -1;
306
	if(c == '\r') return '\n';
307
	if(c == 3) return 1;
2 nishi 308
#endif
309
	return c;
310
}
311
 
312
bool strcaseequ(const char* a, const char* b) { return strcasecmp(a, b) == 0; }
313
 
314
#if defined(PLATFORM_ARDUINO)
315
void putstr(const char* n) {
316
	int i;
317
	for(i = 0; n[i] != 0; i++) {
318
		uart_putchar(n[i]);
319
	}
320
}
321
 
322
void putnum(int n) {
323
	char buf[64];
324
	int incr = 63;
325
	buf[incr--] = 0;
326
	while(1) {
327
		buf[incr--] = (n % 10) + '0';
328
		n /= 10;
329
		if(n == 0) break;
330
	}
331
	putstr(buf + incr + 1);
332
}
333
#else
334
void putnum(int n) {
335
	printf("%d", n);
336
	fflush(stdout);
337
}
338
 
339
void putstr(const char* n) {
340
	printf("%s", n);
341
	fflush(stdout);
342
}
343
#endif
344
 
345
void change_color(int a) {
4 nishi 346
#if defined(PLATFORM_ARDUINO) || defined(PLATFORM_UNIX)
2 nishi 347
	int fg = (a >> 4) & 0xf;
348
	int bg = (a & 0xf);
4 nishi 349
	char color[2];
2 nishi 350
	if(!(0 <= fg && fg <= 15)) return;
351
	if(!(0 <= bg && bg <= 15)) return;
352
	color[1] = 0;
3 nishi 353
	if(bg < 8) {
2 nishi 354
		color[0] = bg + '0';
355
		putstr("\x1b[4");
3 nishi 356
	} else {
2 nishi 357
		color[0] = (bg - 8) + '0';
358
		putstr("\x1b[10");
359
	}
360
	putstr(color);
361
	putstr("m");
3 nishi 362
	if(fg < 8) {
2 nishi 363
		color[0] = fg + '0';
364
		putstr("\x1b[3");
3 nishi 365
	} else {
2 nishi 366
		color[0] = (fg - 8) + '0';
367
		putstr("\x1b[9");
368
	}
369
	putstr(color);
370
	putstr("m");
371
	putstr("\x1b[2J\x1b[1;1H");
9 nishi 372
#elif defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 373
	int fg = (a >> 4) & 0xf;
374
	int bg = (a & 0xf);
375
	bgcolor(bg);
376
	textcolor(fg);
377
#endif
2 nishi 378
}
379
 
380
void clear(void) {
381
#if defined(PLATFORM_WINDOWS)
382
	system("cls");
383
#elif defined(PLATFORM_UNIX) || defined(PLATFORM_ARDUINO)
384
	putstr("\x1b[0m\x1b[2J\x1b[1;1H");
9 nishi 385
#elif defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 386
	clrscr();
2 nishi 387
#endif
388
}
389
 
390
void basic(void);
391
 
392
int main() {
9 nishi 393
#if defined(PLATFORM_PET)
394
	if(PEEK(0x9000) == POKE(0x9000, PEEK(0x9000) + 1)) {
395
		_heapadd((void*)0x9000, 0x2000);
396
	}
397
#endif
2 nishi 398
#if defined(PLATFORM_WINDOWS)
399
	HANDLE winstdout = GetStdHandle(STD_OUTPUT_HANDLE);
400
	DWORD mode = 0;
401
	GetConsoleMode(winstdout, &mode);
402
	const DWORD origmode = mode;
403
	mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
404
	SetConsoleMode(winstdout, mode);
405
#elif defined(PLATFORM_UNIX)
406
	struct termios old, new;
407
	tcgetattr(0, &old);
408
	new = old;
409
	new.c_lflag &= ~(ECHO | ICANON);
410
	tcsetattr(0, TCSANOW, &new);
411
#elif defined(PLATFORM_ARDUINO)
412
	uart_init();
413
	DDRB |= _BV(DDB5);
414
	PORTB |= _BV(PORT5);
415
#endif
9 nishi 416
#if defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 417
	change_color((1 << 4) | 0);
9 nishi 418
	bordercolor(0);
4 nishi 419
#endif
2 nishi 420
	basic();
421
#if defined(PLATFORM_WINDOWS)
422
	SetConsoleMode(winstdout, origmode);
423
#elif defined(PLATFORM_UNIX)
424
	tcsetattr(0, TCSANOW, &old);
425
#endif
426
}
427
 
428
#else
429
#error "Define PLATFORM_*"
430
#endif
431
 
432
#define VERSION "0.0"
433
 
434
#ifndef LINE_BUFFER_SIZE
435
#define LINE_BUFFER_SIZE (512)
436
#endif
437
 
438
#ifndef BUFFER_SIZE
439
#define BUFFER_SIZE (1024 * 24)
440
#endif
441
 
442
#ifndef LINES
443
#define LINES (1024)
444
#endif
445
 
446
unsigned char basicbuffer[BUFFER_SIZE];
447
char linebuf[LINE_BUFFER_SIZE];
448
 
8 nishi 449
int hexnum(char c) {
450
	if('0' <= c && c <= '9') {
451
		return c - '0';
452
	} else if('A' <= c && c <= 'F') {
453
		return c - 'A' + 10;
454
	} else if('a' <= c && c <= 'f') {
455
		return c - 'a' + 10;
456
	}
457
	return 0;
458
}
459
 
2 nishi 460
int pexpr(char* expr, char* buffer, int* number) {
461
	char ownbuf[128];
462
	int i;
463
	int start = 0;
464
	int br = 0;
465
	int result = 0;
466
	int stack[32];
467
	int sp = 0;
468
	char put = 0;
8 nishi 469
	char hex = 0;
4 nishi 470
	for(i = 0; expr[i] != 0; i++) ownbuf[i] = expr[i];
471
	ownbuf[i] = 0;
2 nishi 472
	for(i = 0; i < 32; i++) stack[i] = 0;
473
	for(i = 0;; i++) {
474
		if(ownbuf[i] == 0) {
475
			break;
8 nishi 476
		} else if(ownbuf[i] == '&' && put == 0) {
2 nishi 477
			put = 1;
8 nishi 478
			hex = 1;
479
		} else if(('0' <= ownbuf[i] && ownbuf[i] <= '9') || (hex ? ('A' <= ownbuf[i] && ownbuf[i] <= 'F') : 0) || (hex ? ('a' <= ownbuf[i] && ownbuf[i] <= 'f') : 0)) {
480
			stack[sp] *= hex ? 16 : 10;
481
			if(hex == 1) {
482
				stack[sp] += hexnum(ownbuf[i]);
483
			} else {
484
				stack[sp] += ownbuf[i] - '0';
485
			}
486
			put = 1;
28 nishi 487
#ifndef NO_PEEKPOKE
8 nishi 488
		} else if(ownbuf[i] == 'R') {
489
			put = 0;
490
			hex = 0;
491
			if(sp < 1) {
492
				return -1;
493
			} else {
494
				int top = stack[--sp];
495
				stack[sp++] = (int)*(unsigned char*)top;
496
			}
497
			stack[sp] = 0;
28 nishi 498
#endif
2 nishi 499
		} else if(ownbuf[i] == '+' || ownbuf[i] == '-' || ownbuf[i] == '*' || ownbuf[i] == '/') {
500
			put = 0;
8 nishi 501
			hex = 0;
2 nishi 502
			if(sp < 2) {
503
				return -1;
504
			} else {
505
				int top = stack[--sp];
506
				int bottom = stack[--sp];
507
				int value = 0;
508
				if(ownbuf[i] == '+') {
509
					value = top + bottom;
510
				} else if(ownbuf[i] == '-') {
511
					value = bottom + top;
512
				} else if(ownbuf[i] == '*') {
513
					value = mull(top, bottom);
514
				} else if(ownbuf[i] == '/') {
515
					value = divl(bottom, top);
516
				}
517
				stack[sp++] = value;
518
			}
519
			stack[sp] = 0;
520
		} else if(ownbuf[i] == ' ' && put == 1) {
521
			stack[++sp] = 0;
522
		}
523
	}
524
	result = stack[0];
525
	*number = result;
526
	return 1;
527
}
528
 
529
/* arr gets sorted, arr2 index gets replaced */
530
void sort(int* arr, int* arr2, int size) {
531
	int i;
532
redo:
533
	for(i = 1; i < size; i++) {
534
		if(arr[i - 1] > arr[i]) {
535
			int tmp = arr[i];
536
			arr[i] = arr[i - 1];
537
			arr[i - 1] = tmp;
538
			tmp = arr2[i];
539
			arr2[i] = arr2[i - 1];
540
			arr2[i - 1] = tmp;
541
		}
542
	}
543
	for(i = 1; i < size; i++) {
544
		if(arr[i - 1] > arr[i]) {
545
			goto redo;
546
		}
547
	}
548
}
549
 
550
int run(char* cmd, int linenum, char num, int* lgoto) {
4 nishi 551
	char line[LINE_BUFFER_SIZE];
552
	char rcmd[32];
553
	int i;
554
	char* arg;
555
	int incr = 0;
2 nishi 556
#ifdef BREAKKEY
557
	if(agetch() == 1) return -1;
558
#endif
559
	if(lgoto != 0) *lgoto = 0;
560
	for(i = 0; cmd[i] != 0; i++) line[i] = cmd[i];
561
	line[i] = 0;
562
	rcmd[0] = 0;
563
	for(i = 0;; i++) {
564
		if(line[i] == ' ' || line[i] == '\t' || line[i] == 0 || line[i] == '"') {
565
			break;
566
		} else {
567
			rcmd[incr++] = line[i];
568
			if(incr == 32) {
569
				putstr("! Command too long");
570
				if(linenum != -1) {
571
					putstr(" in line ");
572
					putnum(linenum);
573
				}
574
				putstr(NEWLINE);
575
				return 1;
576
			}
577
			rcmd[incr] = 0;
578
		}
579
	}
4 nishi 580
	arg = line + 1 + strlen(rcmd);
2 nishi 581
	if(strcaseequ(rcmd, "COLOR")) {
582
		int argc = 0;
583
		char* farg = 0;
584
		char* sarg = 0;
4 nishi 585
		int fgcolor, bgcolor, ret0, ret1;
2 nishi 586
		if(arg[0] != 0) argc++;
587
		for(i = 0; arg[i] != 0; i++) {
588
			if(arg[i] == ',') {
589
				arg[i] = 0;
590
				farg = arg;
591
				sarg = arg + i + 1;
592
				for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++)
593
					;
594
				argc++;
595
			}
596
		}
597
		if(argc != 2) {
598
			putstr("! Invalid argument");
599
			if(linenum != -1) {
600
				putstr(" in line ");
601
				putnum(linenum);
602
			}
603
			putstr(NEWLINE);
604
			return 1;
605
		}
4 nishi 606
		bgcolor = 0;
607
		fgcolor = 0;
608
		ret0 = pexpr(farg, 0, &bgcolor);
609
		ret1 = pexpr(sarg, 0, &fgcolor);
2 nishi 610
		if(ret0 == 0) {
611
			putstr("! Invalid argument");
612
			if(linenum != -1) {
613
				putstr(" in line ");
614
				putnum(linenum);
615
			}
616
			putstr(NEWLINE);
617
			return 1;
618
		} else if(ret0 == -1) {
619
			putstr("! Syntax error");
620
			if(linenum != -1) {
621
				putstr(" in line ");
622
				putnum(linenum);
623
			}
624
			putstr(NEWLINE);
625
			return 1;
626
		}
627
		if(ret1 == 1) {
628
			change_color((fgcolor << 4) | bgcolor);
629
		} else if(ret1 == 0) {
630
			putstr("! Invalid argument");
631
			if(linenum != -1) {
632
				putstr(" in line ");
633
				putnum(linenum);
634
			}
635
			putstr(NEWLINE);
636
			return 1;
637
		} else if(ret1 == -1) {
638
			putstr("! Syntax error");
639
			if(linenum != -1) {
640
				putstr(" in line ");
641
				putnum(linenum);
642
			}
643
			putstr(NEWLINE);
644
			return 1;
645
		}
28 nishi 646
#ifndef NO_PEEKPOKE
8 nishi 647
	} else if(strcaseequ(rcmd, "POKE")) {
648
		int argc = 0;
649
		char* farg = 0;
650
		char* sarg = 0;
651
		int addr, data, ret0, ret1;
652
		if(arg[0] != 0) argc++;
653
		for(i = 0; arg[i] != 0; i++) {
654
			if(arg[i] == ',') {
655
				arg[i] = 0;
656
				farg = arg;
657
				sarg = arg + i + 1;
658
				for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++)
659
					;
660
				argc++;
661
			}
662
		}
663
		if(argc != 2) {
664
			putstr("! Invalid argument");
665
			if(linenum != -1) {
666
				putstr(" in line ");
667
				putnum(linenum);
668
			}
669
			putstr(NEWLINE);
670
			return 1;
671
		}
672
		addr = 0;
673
		data = 0;
674
		ret0 = pexpr(farg, 0, &addr);
675
		ret1 = pexpr(sarg, 0, &data);
676
		if(ret0 == 0) {
677
			putstr("! Invalid argument");
678
			if(linenum != -1) {
679
				putstr(" in line ");
680
				putnum(linenum);
681
			}
682
			putstr(NEWLINE);
683
			return 1;
684
		} else if(ret0 == -1) {
685
			putstr("! Syntax error");
686
			if(linenum != -1) {
687
				putstr(" in line ");
688
				putnum(linenum);
689
			}
690
			putstr(NEWLINE);
691
			return 1;
692
		}
693
		if(ret1 == 1) {
694
			unsigned char* a = (unsigned char*)addr;
695
			*a = data;
696
		} else if(ret1 == 0) {
697
			putstr("! Invalid argument");
698
			if(linenum != -1) {
699
				putstr(" in line ");
700
				putnum(linenum);
701
			}
702
			putstr(NEWLINE);
703
			return 1;
704
		} else if(ret1 == -1) {
705
			putstr("! Syntax error");
706
			if(linenum != -1) {
707
				putstr(" in line ");
708
				putnum(linenum);
709
			}
710
			putstr(NEWLINE);
711
			return 1;
712
		}
28 nishi 713
#endif
2 nishi 714
	} else if(num == 0 && strcaseequ(rcmd, "LIST")) {
715
		int addr = BUFFER_SIZE - 1;
716
		int saddr = 0;
717
		int lbuf[LINES];
718
		int shift[LINES];
719
		int cnt = 0;
4 nishi 720
		int i;
2 nishi 721
		while(1) {
722
			unsigned long ln = 0;
723
			for(i = 0; i < 4; i++) {
724
				ln >>= 8;
725
				ln |= (unsigned long)basicbuffer[addr--] << 24;
726
			}
727
			if(ln == 0) break;
728
			lbuf[cnt] = ln;
729
			shift[cnt++] = saddr;
730
			saddr += strlen(basicbuffer + saddr) + 1;
731
		}
732
		sort(lbuf, shift, cnt);
733
		for(i = 0; i < cnt; i++) {
734
			putnum(lbuf[i]);
735
			putstr(" ");
736
			putstr(basicbuffer + shift[i]);
737
			putstr(NEWLINE);
738
		}
739
	} else if(num == 1 && strcaseequ(rcmd, "GOTO")) {
740
		int ret = pexpr(arg, 0, lgoto);
741
		if(ret == 0) {
742
			putstr("! Invalid argument");
743
			if(linenum != -1) {
744
				putstr(" in line ");
745
				putnum(linenum);
746
			}
747
			putstr(NEWLINE);
748
			return 1;
749
		} else if(ret == -1) {
750
			putstr("! Syntax error");
751
			if(linenum != -1) {
752
				putstr(" in line ");
753
				putnum(linenum);
754
			}
755
			putstr(NEWLINE);
756
			return 1;
757
		}
758
	} else if(num == 0 && strcaseequ(rcmd, "RUN")) {
759
		int addr = BUFFER_SIZE - 1;
760
		int saddr = 0;
761
		int lbuf[LINES];
762
		int shift[LINES];
763
		int cnt = 0;
4 nishi 764
		int gt, i;
2 nishi 765
		while(1) {
766
			unsigned long ln = 0;
767
			for(i = 0; i < 4; i++) {
768
				ln >>= 8;
769
				ln |= (unsigned long)basicbuffer[addr--] << 24;
770
			}
771
			if(ln == 0) break;
772
			lbuf[cnt] = ln;
773
			shift[cnt++] = saddr;
774
			saddr += strlen(basicbuffer + saddr) + 1;
775
		}
776
		sort(lbuf, shift, cnt);
777
		for(i = 0; i < cnt; i++) {
778
			int ret = run(basicbuffer + shift[i], lbuf[i], 1, &gt);
779
			if(ret != 0) return ret;
780
			if(gt != 0) {
4 nishi 781
				char found;
2 nishi 782
				for(i = 0; i < cnt; i++) {
783
					if(lbuf[i] == gt) {
784
						found = 1;
785
						break;
786
					}
787
				}
788
				if(found) {
789
					i--;
790
				} else {
791
					putstr("! GOTO no such line");
792
					if(linenum != -1) {
793
						putstr(" in line ");
794
						putnum(linenum);
795
					}
796
					putstr(NEWLINE);
797
					return 1;
798
				}
799
			}
800
		}
801
	} else {
802
		putstr("! Unknown command");
803
		if(linenum != -1) {
804
			putstr(" in line ");
805
			putnum(linenum);
806
		}
807
		putstr(NEWLINE);
808
		return 1;
809
	}
810
	return 0;
811
}
812
 
813
int execute(int linenum, char* cmd, char num) {
814
	int i;
815
	char line[LINE_BUFFER_SIZE];
816
	int incr = 0;
817
	char dq = 0;
818
	for(i = 0; cmd[i] != 0; i++) {
819
		if(cmd[i] == ' ' || cmd[i] == '\t') {
820
			if(!dq) {
821
				for(; cmd[i] != 0 && (cmd[i] == ' ' || cmd[i] == '\t'); i++)
822
					;
823
				i--;
824
			}
825
			line[incr++] = cmd[i];
826
		} else if(cmd[i] == '"') {
827
			line[incr++] = '"';
828
			dq = dq == 0 ? 1 : 0;
829
		} else {
830
			line[incr++] = dq == 0 ? toupper(cmd[i]) : cmd[i];
831
		}
832
	}
833
	line[incr] = 0;
834
	if(num == 0) {
835
		int ret = run(line, -1, 0, 0);
6 nishi 836
		putstr("Ready");
837
		putstr(NEWLINE);
2 nishi 838
		return ret;
839
	} else {
840
		int addr = BUFFER_SIZE - 1;
841
		int i;
842
		int shf = 0;
843
		int cnt = 0;
4 nishi 844
		int len;
2 nishi 845
		while(1) {
846
			unsigned long ln = 0;
847
			for(i = 0; i < 4; i++) {
848
				ln >>= 8;
849
				ln |= (unsigned long)basicbuffer[addr--] << 24;
850
			}
851
			cnt++;
852
			if(ln == linenum) shf = cnt;
853
			if(shf != 0) {
854
				addr += 4;
855
				for(i = 0; i < 4; i++) {
856
					basicbuffer[addr] = basicbuffer[addr - 4 * shf];
857
					addr--;
858
				}
859
				addr += 4;
860
				ln = 0;
861
				for(i = 0; i < 4; i++) {
862
					ln >>= 8;
863
					ln |= (unsigned long)basicbuffer[addr--] << 24;
864
				}
865
			}
866
			if(ln == 0) break;
867
		}
868
		if(line[0] != 0) {
869
			addr += 4;
870
			for(i = 0; i < 4; i++) {
871
				basicbuffer[addr--] = linenum & 0xff;
872
				linenum >>= 8;
873
			}
874
		}
4 nishi 875
		len = 0;
2 nishi 876
		cnt = 0;
877
		while(1) {
878
			int slen = strlen(basicbuffer + len);
879
			if(slen == 0) break;
880
			len += slen + 1;
881
			cnt++;
882
		}
883
		if(line[0] != 0) {
884
			for(i = 0; line[i] != 0; i++) {
885
				basicbuffer[len + i] = line[i];
886
			}
887
			basicbuffer[len + i] = 0;
888
			basicbuffer[len + i + 1] = 0;
889
		}
890
		if(shf != 0) {
891
			cnt = 0;
892
			len = 0;
893
			while(1) {
894
				int slen = strlen(basicbuffer + len);
895
				if(slen == 0) break;
896
 
897
				len += slen + 1;
898
				cnt++;
899
 
900
				if(cnt == shf) {
901
					int i;
902
					int nc = 0;
4 nishi 903
					len -= slen + 1;
2 nishi 904
					for(i = len;; i++) {
905
						basicbuffer[i] = basicbuffer[i + slen + 1];
906
						if(basicbuffer[i] == 0) {
907
							nc++;
908
							if(nc == 2) break;
909
						} else {
910
							nc = 0;
911
						}
912
					}
913
					break;
914
				}
915
			}
916
		}
917
		return 0;
918
	}
919
}
920
 
921
void basic(void) {
922
	int i;
4 nishi 923
	int lineind;
2 nishi 924
	clear();
925
 
926
#ifdef SMALL
927
	putstr("Krakow BASIC  Ver. ");
928
	putstr(VERSION);
929
	putstr(NEWLINE);
930
	putstr(NEWLINE);
931
#else
932
	putstr(PLATFORM);
933
	putstr("   Krakow BASIC V");
934
	putstr(VERSION);
6 nishi 935
	putstr(NEWLINE);
936
	putstr("Copyright 2024 by: Nishi.");
937
	putstr(NEWLINE);
2 nishi 938
	putstr("                   penguin2233.");
939
	putstr(NEWLINE);
940
	putstr(NEWLINE);
941
	putstr(" Max ");
942
	putnum(LINE_BUFFER_SIZE);
943
	putstr(" characters per line");
944
	putstr(NEWLINE);
945
	putstr(" Max ");
946
	putnum(LINES);
947
	putstr(" lines");
948
	putstr(NEWLINE);
949
	putstr(" ");
950
#endif
951
	putnum(BUFFER_SIZE);
952
	putstr(" bytes free");
953
	putstr(NEWLINE);
954
	putstr(NEWLINE);
955
 
956
	for(i = 0; i < BUFFER_SIZE; i++) {
957
		basicbuffer[i] = 0;
958
	}
959
	putstr("Ready");
960
	putstr(NEWLINE);
961
 
962
	cursor();
963
	linebuf[0] = 0;
4 nishi 964
	lineind = 0;
2 nishi 965
	while(1) {
4 nishi 966
		char c;
29 nishi 967
#if defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET) || defined(PLATFORM_MSX)
4 nishi 968
		c = oggetch(1);
969
#else
970
		c = agetch();
971
#endif
8 nishi 972
		if(c != 0) {
973
			killcursor();
974
		}
2 nishi 975
		if(c == 1) {
976
			putstr("Break");
977
			putstr(NEWLINE);
978
			lineind = 0;
979
		} else if(c == '\n') {
4 nishi 980
			int i;
981
			char num = 1;
982
			char* cmd = linebuf;
983
 
2 nishi 984
			linebuf[lineind] = 0;
985
			putstr(NEWLINE);
986
			if(lineind == 0) goto skip;
987
 
988
			for(i = 0; linebuf[i] != 0; i++) {
989
				if(linebuf[i] == ' ') {
990
					linebuf[i] = 0;
991
					cmd = linebuf + i + 1;
992
					break;
993
				} else if(!('0' <= linebuf[i] && linebuf[i] <= '9')) {
994
					num = 0;
995
					break;
996
				}
997
			}
998
 
999
			if(num == 1 && strnum(linebuf) == 0) {
1000
				putstr("! Line number 0 is illegal");
1001
				putstr(NEWLINE);
1002
			} else {
1003
				int ret = execute(num == 1 ? strnum(linebuf) : -1, (num == 1 && cmd == linebuf) ? "" : cmd, num);
1004
				if(ret == -1) {
1005
					putstr("! Break");
1006
					putstr(NEWLINE);
1007
				}
1008
			}
1009
 
1010
		skip:
1011
			lineind = 0;
1012
		} else if(c == 0x8 || c == 0x7f) {
1013
			if(lineind > 0) {
6 nishi 1014
#if defined(PLATFORM_A800XL)
1015
				putstr("\x7e \x7e");
1016
#else
2 nishi 1017
				putstr("\x08 \x08");
6 nishi 1018
#endif
2 nishi 1019
				linebuf[--lineind] = 0;
1020
			}
1021
		} else if(c == -1) {
1022
			break;
1023
		} else if(c != 0) {
1024
			putchar(c);
1025
			linebuf[lineind++] = c;
1026
		}
1027
		cursor();
1028
	}
1029
}