Subversion Repositories Krakow BASIC

Rev

Rev 36 | Rev 38 | 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 37 2024-09-05 15:59:22Z 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
 
36 nishi 258
#define agetch() oggetch(0)
4 nishi 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:
36 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
 
37 nishi 446
unsigned char basicbuffer[BUFFER_SIZE / 2];
447
unsigned char varbuffer[BUFFER_SIZE / 2];
2 nishi 448
char linebuf[LINE_BUFFER_SIZE];
449
 
8 nishi 450
int hexnum(char c) {
451
	if('0' <= c && c <= '9') {
452
		return c - '0';
453
	} else if('A' <= c && c <= 'F') {
454
		return c - 'A' + 10;
455
	} else if('a' <= c && c <= 'f') {
456
		return c - 'a' + 10;
457
	}
458
	return 0;
459
}
460
 
2 nishi 461
int pexpr(char* expr, char* buffer, int* number) {
462
	char ownbuf[128];
463
	int i;
464
	int start = 0;
465
	int br = 0;
466
	int result = 0;
467
	int stack[32];
468
	int sp = 0;
469
	char put = 0;
8 nishi 470
	char hex = 0;
36 nishi 471
	if(expr[0] == '"' && expr[strlen(expr) - 1] == '"'){
472
		for(i = 1; expr[i + 1] != 0; i++){
473
			buffer[i - 1] = expr[i];
474
		}
475
		buffer[i - 1] = 0;
476
		return 0;
477
	}
4 nishi 478
	for(i = 0; expr[i] != 0; i++) ownbuf[i] = expr[i];
479
	ownbuf[i] = 0;
2 nishi 480
	for(i = 0; i < 32; i++) stack[i] = 0;
481
	for(i = 0;; i++) {
482
		if(ownbuf[i] == 0) {
483
			break;
8 nishi 484
		} else if(ownbuf[i] == '&' && put == 0) {
2 nishi 485
			put = 1;
8 nishi 486
			hex = 1;
487
		} else if(('0' <= ownbuf[i] && ownbuf[i] <= '9') || (hex ? ('A' <= ownbuf[i] && ownbuf[i] <= 'F') : 0) || (hex ? ('a' <= ownbuf[i] && ownbuf[i] <= 'f') : 0)) {
488
			stack[sp] *= hex ? 16 : 10;
489
			if(hex == 1) {
490
				stack[sp] += hexnum(ownbuf[i]);
491
			} else {
492
				stack[sp] += ownbuf[i] - '0';
493
			}
494
			put = 1;
28 nishi 495
#ifndef NO_PEEKPOKE
8 nishi 496
		} else if(ownbuf[i] == 'R') {
497
			put = 0;
498
			hex = 0;
499
			if(sp < 1) {
500
				return -1;
501
			} else {
502
				int top = stack[--sp];
503
				stack[sp++] = (int)*(unsigned char*)top;
504
			}
505
			stack[sp] = 0;
28 nishi 506
#endif
2 nishi 507
		} else if(ownbuf[i] == '+' || ownbuf[i] == '-' || ownbuf[i] == '*' || ownbuf[i] == '/') {
508
			put = 0;
8 nishi 509
			hex = 0;
2 nishi 510
			if(sp < 2) {
511
				return -1;
512
			} else {
513
				int top = stack[--sp];
514
				int bottom = stack[--sp];
515
				int value = 0;
516
				if(ownbuf[i] == '+') {
517
					value = top + bottom;
518
				} else if(ownbuf[i] == '-') {
519
					value = bottom + top;
520
				} else if(ownbuf[i] == '*') {
521
					value = mull(top, bottom);
522
				} else if(ownbuf[i] == '/') {
523
					value = divl(bottom, top);
524
				}
525
				stack[sp++] = value;
526
			}
527
			stack[sp] = 0;
528
		} else if(ownbuf[i] == ' ' && put == 1) {
529
			stack[++sp] = 0;
530
		}
531
	}
532
	result = stack[0];
533
	*number = result;
534
	return 1;
535
}
536
 
537
/* arr gets sorted, arr2 index gets replaced */
538
void sort(int* arr, int* arr2, int size) {
539
	int i;
540
redo:
541
	for(i = 1; i < size; i++) {
542
		if(arr[i - 1] > arr[i]) {
543
			int tmp = arr[i];
544
			arr[i] = arr[i - 1];
545
			arr[i - 1] = tmp;
546
			tmp = arr2[i];
547
			arr2[i] = arr2[i - 1];
548
			arr2[i - 1] = tmp;
549
		}
550
	}
551
	for(i = 1; i < size; i++) {
552
		if(arr[i - 1] > arr[i]) {
553
			goto redo;
554
		}
555
	}
556
}
557
 
558
int run(char* cmd, int linenum, char num, int* lgoto) {
4 nishi 559
	char line[LINE_BUFFER_SIZE];
560
	char rcmd[32];
561
	int i;
562
	char* arg;
563
	int incr = 0;
2 nishi 564
#ifdef BREAKKEY
565
	if(agetch() == 1) return -1;
566
#endif
567
	if(lgoto != 0) *lgoto = 0;
568
	for(i = 0; cmd[i] != 0; i++) line[i] = cmd[i];
569
	line[i] = 0;
570
	rcmd[0] = 0;
571
	for(i = 0;; i++) {
572
		if(line[i] == ' ' || line[i] == '\t' || line[i] == 0 || line[i] == '"') {
573
			break;
574
		} else {
575
			rcmd[incr++] = line[i];
576
			if(incr == 32) {
577
				putstr("! Command too long");
578
				if(linenum != -1) {
579
					putstr(" in line ");
580
					putnum(linenum);
581
				}
582
				putstr(NEWLINE);
583
				return 1;
584
			}
585
			rcmd[incr] = 0;
586
		}
587
	}
4 nishi 588
	arg = line + 1 + strlen(rcmd);
2 nishi 589
	if(strcaseequ(rcmd, "COLOR")) {
590
		int argc = 0;
591
		char* farg = 0;
592
		char* sarg = 0;
4 nishi 593
		int fgcolor, bgcolor, ret0, ret1;
2 nishi 594
		if(arg[0] != 0) argc++;
595
		for(i = 0; arg[i] != 0; i++) {
596
			if(arg[i] == ',') {
597
				arg[i] = 0;
598
				farg = arg;
599
				sarg = arg + i + 1;
600
				for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++)
601
					;
602
				argc++;
603
			}
604
		}
605
		if(argc != 2) {
606
			putstr("! Invalid argument");
607
			if(linenum != -1) {
608
				putstr(" in line ");
609
				putnum(linenum);
610
			}
611
			putstr(NEWLINE);
612
			return 1;
613
		}
4 nishi 614
		bgcolor = 0;
615
		fgcolor = 0;
616
		ret0 = pexpr(farg, 0, &bgcolor);
617
		ret1 = pexpr(sarg, 0, &fgcolor);
2 nishi 618
		if(ret0 == 0) {
619
			putstr("! Invalid argument");
620
			if(linenum != -1) {
621
				putstr(" in line ");
622
				putnum(linenum);
623
			}
624
			putstr(NEWLINE);
625
			return 1;
626
		} else if(ret0 == -1) {
627
			putstr("! Syntax error");
628
			if(linenum != -1) {
629
				putstr(" in line ");
630
				putnum(linenum);
631
			}
632
			putstr(NEWLINE);
633
			return 1;
634
		}
635
		if(ret1 == 1) {
636
			change_color((fgcolor << 4) | bgcolor);
637
		} else if(ret1 == 0) {
638
			putstr("! Invalid argument");
639
			if(linenum != -1) {
640
				putstr(" in line ");
641
				putnum(linenum);
642
			}
643
			putstr(NEWLINE);
644
			return 1;
645
		} else if(ret1 == -1) {
646
			putstr("! Syntax error");
647
			if(linenum != -1) {
648
				putstr(" in line ");
649
				putnum(linenum);
650
			}
651
			putstr(NEWLINE);
652
			return 1;
653
		}
36 nishi 654
	} else if(strcaseequ(rcmd, "PRINT")){
655
		if(arg[0] != 0){
656
			char sc = 0;
657
			int incr = 0;
658
			for(i = 0;; i++) {
659
				if(arg[i] != 0) sc = 0;
660
				if(arg[i] == ';' || arg[i] == 0) {
661
					char oldc = arg[i];
662
					arg[i] = 0;
663
 
664
					if(strlen(arg + incr) > 0){	
665
						char buffer[128];
666
 
667
						int number;
668
						int ret = pexpr(arg + incr, buffer, &number);
669
 
670
						if(ret == 0){
671
							putstr(buffer);
672
						}else if(ret == 1){
673
							putstr(" ");
674
							putnum(number);
675
						}else if(ret == -1){
676
							putstr("! Syntax error");
677
							if(linenum != -1) {
678
								putstr(" in line ");
679
								putnum(linenum);
680
							}
681
							putstr(NEWLINE);
682
							return 1;
683
						}
684
					}
685
 
686
					incr = i + 1;
687
					if(oldc == ';') sc = 1;
688
					if(oldc == 0) break;
689
				}
690
			}
691
			if(!sc) putstr(NEWLINE);
692
		}else{
693
			putstr(NEWLINE);
694
		}
28 nishi 695
#ifndef NO_PEEKPOKE
8 nishi 696
	} else if(strcaseequ(rcmd, "POKE")) {
697
		int argc = 0;
698
		char* farg = 0;
699
		char* sarg = 0;
700
		int addr, data, ret0, ret1;
701
		if(arg[0] != 0) argc++;
702
		for(i = 0; arg[i] != 0; i++) {
703
			if(arg[i] == ',') {
704
				arg[i] = 0;
705
				farg = arg;
706
				sarg = arg + i + 1;
707
				for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++)
708
					;
709
				argc++;
710
			}
711
		}
712
		if(argc != 2) {
713
			putstr("! Invalid argument");
714
			if(linenum != -1) {
715
				putstr(" in line ");
716
				putnum(linenum);
717
			}
718
			putstr(NEWLINE);
719
			return 1;
720
		}
721
		addr = 0;
722
		data = 0;
723
		ret0 = pexpr(farg, 0, &addr);
724
		ret1 = pexpr(sarg, 0, &data);
725
		if(ret0 == 0) {
726
			putstr("! Invalid argument");
727
			if(linenum != -1) {
728
				putstr(" in line ");
729
				putnum(linenum);
730
			}
731
			putstr(NEWLINE);
732
			return 1;
733
		} else if(ret0 == -1) {
734
			putstr("! Syntax error");
735
			if(linenum != -1) {
736
				putstr(" in line ");
737
				putnum(linenum);
738
			}
739
			putstr(NEWLINE);
740
			return 1;
741
		}
742
		if(ret1 == 1) {
743
			unsigned char* a = (unsigned char*)addr;
744
			*a = data;
745
		} else if(ret1 == 0) {
746
			putstr("! Invalid argument");
747
			if(linenum != -1) {
748
				putstr(" in line ");
749
				putnum(linenum);
750
			}
751
			putstr(NEWLINE);
752
			return 1;
753
		} else if(ret1 == -1) {
754
			putstr("! Syntax error");
755
			if(linenum != -1) {
756
				putstr(" in line ");
757
				putnum(linenum);
758
			}
759
			putstr(NEWLINE);
760
			return 1;
761
		}
28 nishi 762
#endif
2 nishi 763
	} else if(num == 0 && strcaseequ(rcmd, "LIST")) {
764
		int addr = BUFFER_SIZE - 1;
765
		int saddr = 0;
766
		int lbuf[LINES];
767
		int shift[LINES];
768
		int cnt = 0;
4 nishi 769
		int i;
2 nishi 770
		while(1) {
771
			unsigned long ln = 0;
772
			for(i = 0; i < 4; i++) {
773
				ln >>= 8;
774
				ln |= (unsigned long)basicbuffer[addr--] << 24;
775
			}
776
			if(ln == 0) break;
777
			lbuf[cnt] = ln;
778
			shift[cnt++] = saddr;
779
			saddr += strlen(basicbuffer + saddr) + 1;
780
		}
781
		sort(lbuf, shift, cnt);
782
		for(i = 0; i < cnt; i++) {
783
			putnum(lbuf[i]);
784
			putstr(" ");
785
			putstr(basicbuffer + shift[i]);
786
			putstr(NEWLINE);
787
		}
788
	} else if(num == 1 && strcaseequ(rcmd, "GOTO")) {
789
		int ret = pexpr(arg, 0, lgoto);
790
		if(ret == 0) {
791
			putstr("! Invalid argument");
792
			if(linenum != -1) {
793
				putstr(" in line ");
794
				putnum(linenum);
795
			}
796
			putstr(NEWLINE);
797
			return 1;
798
		} else if(ret == -1) {
799
			putstr("! Syntax error");
800
			if(linenum != -1) {
801
				putstr(" in line ");
802
				putnum(linenum);
803
			}
804
			putstr(NEWLINE);
805
			return 1;
806
		}
807
	} else if(num == 0 && strcaseequ(rcmd, "RUN")) {
808
		int addr = BUFFER_SIZE - 1;
809
		int saddr = 0;
810
		int lbuf[LINES];
811
		int shift[LINES];
812
		int cnt = 0;
4 nishi 813
		int gt, i;
2 nishi 814
		while(1) {
815
			unsigned long ln = 0;
816
			for(i = 0; i < 4; i++) {
817
				ln >>= 8;
818
				ln |= (unsigned long)basicbuffer[addr--] << 24;
819
			}
820
			if(ln == 0) break;
821
			lbuf[cnt] = ln;
822
			shift[cnt++] = saddr;
823
			saddr += strlen(basicbuffer + saddr) + 1;
824
		}
825
		sort(lbuf, shift, cnt);
826
		for(i = 0; i < cnt; i++) {
827
			int ret = run(basicbuffer + shift[i], lbuf[i], 1, &gt);
828
			if(ret != 0) return ret;
829
			if(gt != 0) {
4 nishi 830
				char found;
2 nishi 831
				for(i = 0; i < cnt; i++) {
832
					if(lbuf[i] == gt) {
833
						found = 1;
834
						break;
835
					}
836
				}
837
				if(found) {
838
					i--;
839
				} else {
840
					putstr("! GOTO no such line");
841
					if(linenum != -1) {
842
						putstr(" in line ");
843
						putnum(linenum);
844
					}
845
					putstr(NEWLINE);
846
					return 1;
847
				}
848
			}
849
		}
850
	} else {
851
		putstr("! Unknown command");
852
		if(linenum != -1) {
853
			putstr(" in line ");
854
			putnum(linenum);
855
		}
856
		putstr(NEWLINE);
857
		return 1;
858
	}
859
	return 0;
860
}
861
 
862
int execute(int linenum, char* cmd, char num) {
863
	int i;
864
	char line[LINE_BUFFER_SIZE];
865
	int incr = 0;
866
	char dq = 0;
867
	for(i = 0; cmd[i] != 0; i++) {
868
		if(cmd[i] == ' ' || cmd[i] == '\t') {
869
			if(!dq) {
870
				for(; cmd[i] != 0 && (cmd[i] == ' ' || cmd[i] == '\t'); i++)
871
					;
872
				i--;
873
			}
874
			line[incr++] = cmd[i];
875
		} else if(cmd[i] == '"') {
876
			line[incr++] = '"';
877
			dq = dq == 0 ? 1 : 0;
878
		} else {
879
			line[incr++] = dq == 0 ? toupper(cmd[i]) : cmd[i];
880
		}
881
	}
882
	line[incr] = 0;
883
	if(num == 0) {
884
		int ret = run(line, -1, 0, 0);
6 nishi 885
		putstr("Ready");
886
		putstr(NEWLINE);
2 nishi 887
		return ret;
888
	} else {
889
		int addr = BUFFER_SIZE - 1;
890
		int i;
891
		int shf = 0;
892
		int cnt = 0;
4 nishi 893
		int len;
2 nishi 894
		while(1) {
895
			unsigned long ln = 0;
896
			for(i = 0; i < 4; i++) {
897
				ln >>= 8;
898
				ln |= (unsigned long)basicbuffer[addr--] << 24;
899
			}
900
			cnt++;
901
			if(ln == linenum) shf = cnt;
902
			if(shf != 0) {
903
				addr += 4;
904
				for(i = 0; i < 4; i++) {
905
					basicbuffer[addr] = basicbuffer[addr - 4 * shf];
906
					addr--;
907
				}
908
				addr += 4;
909
				ln = 0;
910
				for(i = 0; i < 4; i++) {
911
					ln >>= 8;
912
					ln |= (unsigned long)basicbuffer[addr--] << 24;
913
				}
914
			}
915
			if(ln == 0) break;
916
		}
917
		if(line[0] != 0) {
918
			addr += 4;
919
			for(i = 0; i < 4; i++) {
920
				basicbuffer[addr--] = linenum & 0xff;
921
				linenum >>= 8;
922
			}
923
		}
4 nishi 924
		len = 0;
2 nishi 925
		cnt = 0;
926
		while(1) {
927
			int slen = strlen(basicbuffer + len);
928
			if(slen == 0) break;
929
			len += slen + 1;
930
			cnt++;
931
		}
932
		if(line[0] != 0) {
933
			for(i = 0; line[i] != 0; i++) {
934
				basicbuffer[len + i] = line[i];
935
			}
936
			basicbuffer[len + i] = 0;
937
			basicbuffer[len + i + 1] = 0;
938
		}
939
		if(shf != 0) {
940
			cnt = 0;
941
			len = 0;
942
			while(1) {
943
				int slen = strlen(basicbuffer + len);
944
				if(slen == 0) break;
945
 
946
				len += slen + 1;
947
				cnt++;
948
 
949
				if(cnt == shf) {
950
					int i;
951
					int nc = 0;
4 nishi 952
					len -= slen + 1;
2 nishi 953
					for(i = len;; i++) {
954
						basicbuffer[i] = basicbuffer[i + slen + 1];
955
						if(basicbuffer[i] == 0) {
956
							nc++;
957
							if(nc == 2) break;
958
						} else {
959
							nc = 0;
960
						}
961
					}
962
					break;
963
				}
964
			}
965
		}
966
		return 0;
967
	}
968
}
969
 
970
void basic(void) {
971
	int i;
4 nishi 972
	int lineind;
2 nishi 973
	clear();
974
 
975
#ifdef SMALL
976
	putstr("Krakow BASIC  Ver. ");
977
	putstr(VERSION);
978
	putstr(NEWLINE);
979
	putstr(NEWLINE);
980
#else
981
	putstr(PLATFORM);
982
	putstr("   Krakow BASIC V");
983
	putstr(VERSION);
6 nishi 984
	putstr(NEWLINE);
985
	putstr("Copyright 2024 by: Nishi.");
986
	putstr(NEWLINE);
2 nishi 987
	putstr("                   penguin2233.");
988
	putstr(NEWLINE);
989
	putstr(NEWLINE);
990
	putstr(" Max ");
991
	putnum(LINE_BUFFER_SIZE);
992
	putstr(" characters per line");
993
	putstr(NEWLINE);
994
	putstr(" Max ");
995
	putnum(LINES);
996
	putstr(" lines");
997
	putstr(NEWLINE);
998
	putstr(" ");
37 nishi 999
	putstr("Variable buffer ");
1000
	putnum(BUFFER_SIZE / 2);
1001
	putstr(" bytes");
1002
	putstr(NEWLINE);
1003
	putstr(" ");
2 nishi 1004
#endif
37 nishi 1005
	putnum(BUFFER_SIZE / 2);
2 nishi 1006
	putstr(" bytes free");
1007
	putstr(NEWLINE);
1008
	putstr(NEWLINE);
1009
 
37 nishi 1010
	for(i = 0; i < BUFFER_SIZE / 2; i++) {
2 nishi 1011
		basicbuffer[i] = 0;
1012
	}
1013
	putstr("Ready");
1014
	putstr(NEWLINE);
1015
 
1016
	cursor();
1017
	linebuf[0] = 0;
4 nishi 1018
	lineind = 0;
2 nishi 1019
	while(1) {
4 nishi 1020
		char c;
29 nishi 1021
#if defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET) || defined(PLATFORM_MSX)
4 nishi 1022
		c = oggetch(1);
1023
#else
1024
		c = agetch();
1025
#endif
8 nishi 1026
		if(c != 0) {
1027
			killcursor();
1028
		}
2 nishi 1029
		if(c == 1) {
1030
			putstr("Break");
1031
			putstr(NEWLINE);
1032
			lineind = 0;
1033
		} else if(c == '\n') {
4 nishi 1034
			int i;
1035
			char num = 1;
1036
			char* cmd = linebuf;
1037
 
2 nishi 1038
			linebuf[lineind] = 0;
1039
			putstr(NEWLINE);
1040
			if(lineind == 0) goto skip;
1041
 
1042
			for(i = 0; linebuf[i] != 0; i++) {
1043
				if(linebuf[i] == ' ') {
1044
					linebuf[i] = 0;
1045
					cmd = linebuf + i + 1;
1046
					break;
1047
				} else if(!('0' <= linebuf[i] && linebuf[i] <= '9')) {
1048
					num = 0;
1049
					break;
1050
				}
1051
			}
1052
 
1053
			if(num == 1 && strnum(linebuf) == 0) {
1054
				putstr("! Line number 0 is illegal");
1055
				putstr(NEWLINE);
1056
			} else {
1057
				int ret = execute(num == 1 ? strnum(linebuf) : -1, (num == 1 && cmd == linebuf) ? "" : cmd, num);
1058
				if(ret == -1) {
1059
					putstr("! Break");
1060
					putstr(NEWLINE);
1061
				}
1062
			}
1063
 
1064
		skip:
1065
			lineind = 0;
1066
		} else if(c == 0x8 || c == 0x7f) {
1067
			if(lineind > 0) {
6 nishi 1068
#if defined(PLATFORM_A800XL)
1069
				putstr("\x7e \x7e");
1070
#else
2 nishi 1071
				putstr("\x08 \x08");
6 nishi 1072
#endif
2 nishi 1073
				linebuf[--lineind] = 0;
1074
			}
1075
		} else if(c == -1) {
1076
			break;
1077
		} else if(c != 0) {
1078
			putchar(c);
1079
			linebuf[lineind++] = c;
1080
		}
1081
		cursor();
1082
	}
1083
}