Subversion Repositories Krakow BASIC

Rev

Rev 39 | Details | Compare with Previous | Last modification | View Log | RSS feed

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