Subversion Repositories Krakow BASIC

Rev

Rev 37 | Rev 39 | 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 38 2024-09-05 16:02:53Z 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>
38 nishi 214
#include <sys/ioctl.h>
9 nishi 215
#elif defined(PLATFORM_PET)
216
#define BUFFER_SIZE (4 * 1024)
217
#undef killcursor
218
#undef cursor
219
#define killcursor(x) cursor(0)
220
#define cursor(x) cursor(1)
4 nishi 221
#elif defined(PLATFORM_C64)
222
#define BUFFER_SIZE (16 * 1024)
223
#undef killcursor
224
#undef cursor
225
#define killcursor(x) cursor(0)
226
#define cursor(x) cursor(1)
6 nishi 227
#elif defined(PLATFORM_A800XL)
228
#define BUFFER_SIZE (16 * 1024)
229
#undef killcursor
230
#undef cursor
231
#define killcursor(x) cursor(0)
232
#define cursor(x) cursor(1)
7 nishi 233
#elif defined(PLATFORM_APPLE2)
234
#define BUFFER_SIZE (8 * 1024)
235
#undef killcursor
236
#undef cursor
237
#define killcursor(x) cursor(0)
238
#define cursor(x) cursor(1)
2 nishi 239
#endif
240
 
241
#if defined(PLATFORM_ARDUINO)
242
int uart_putchar(char c) {
243
	while(!(UCSR0A & _BV(UDRE0)))
244
		;
245
	UDR0 = c;
246
	return 0;
247
}
248
 
249
void uart_init(void) {
250
	UBRR0H = UBRRH_VALUE;
251
	UBRR0L = UBRRL_VALUE;
252
 
253
	UCSR0B |= _BV(TXEN0) | _BV(RXEN0);
254
 
255
	UCSR0C |= _BV(UCSZ00) | _BV(UCSZ01);
256
}
257
#endif
258
 
36 nishi 259
#define agetch() oggetch(0)
4 nishi 260
char oggetch(char wait) {
261
	int c;
2 nishi 262
#if defined(PLATFORM_WINDOWS)
263
rescan:
38 nishi 264
	if(!wait){
265
		if(!_kbhit()) return 0;
266
	}
2 nishi 267
	c = _getch();
268
	if(c == '\r') return '\n';
269
	if(c == '\n') goto rescan;
270
#elif defined(PLATFORM_UNIX)
38 nishi 271
	if(!wait){
272
		int b;
273
		ioctl(0, FIONREAD, &b);
274
		if(b == 0) return 0;
275
	}
4 nishi 276
	c = getchar();
2 nishi 277
	if(c == EOF) return -1;
278
	if(c == '\r') return '\n';
279
#elif defined(PLATFORM_ARDUINO)
280
rescan:
36 nishi 281
	if(!wait) {
4 nishi 282
		if(!(UCSR0A & _BV(RXC0))) return 0;
7 nishi 283
	} else {
284
		while(!(UCSR0A & _BV(RXC0)))
285
			;
4 nishi 286
	}
2 nishi 287
	c = UDR0;
288
	if(c == '\r') return '\n';
289
	if(c == '\n') goto rescan;
290
	if(c == 3) return 1;
9 nishi 291
#elif defined(PLATFORM_C64) || defined(PLATFORM_PET)
7 nishi 292
	if(!wait) {
4 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 == 20) return 8;
299
	if(c == 3) return 1;
6 nishi 300
#elif defined(PLATFORM_A800XL)
7 nishi 301
	if(!wait) {
6 nishi 302
		if(!kbhit()) return 0;
303
	}
304
	c = cgetc();
305
	if(c == EOF) return -1;
306
	if(c == '\r') return '\n';
307
	if(c == 126) return 8;
308
	if(c == 3) return 1;
7 nishi 309
#elif defined(PLATFORM_APPLE2)
310
	if(!wait) {
311
		if(!kbhit()) return 0;
312
	}
313
	c = cgetc();
314
	if(c == EOF) return -1;
315
	if(c == '\r') return '\n';
316
	if(c == 3) return 1;
2 nishi 317
#endif
318
	return c;
319
}
320
 
321
bool strcaseequ(const char* a, const char* b) { return strcasecmp(a, b) == 0; }
322
 
323
#if defined(PLATFORM_ARDUINO)
324
void putstr(const char* n) {
325
	int i;
326
	for(i = 0; n[i] != 0; i++) {
327
		uart_putchar(n[i]);
328
	}
329
}
330
 
331
void putnum(int n) {
332
	char buf[64];
333
	int incr = 63;
334
	buf[incr--] = 0;
335
	while(1) {
336
		buf[incr--] = (n % 10) + '0';
337
		n /= 10;
338
		if(n == 0) break;
339
	}
340
	putstr(buf + incr + 1);
341
}
342
#else
343
void putnum(int n) {
344
	printf("%d", n);
345
	fflush(stdout);
346
}
347
 
348
void putstr(const char* n) {
349
	printf("%s", n);
350
	fflush(stdout);
351
}
352
#endif
353
 
354
void change_color(int a) {
4 nishi 355
#if defined(PLATFORM_ARDUINO) || defined(PLATFORM_UNIX)
2 nishi 356
	int fg = (a >> 4) & 0xf;
357
	int bg = (a & 0xf);
4 nishi 358
	char color[2];
2 nishi 359
	if(!(0 <= fg && fg <= 15)) return;
360
	if(!(0 <= bg && bg <= 15)) return;
361
	color[1] = 0;
3 nishi 362
	if(bg < 8) {
2 nishi 363
		color[0] = bg + '0';
364
		putstr("\x1b[4");
3 nishi 365
	} else {
2 nishi 366
		color[0] = (bg - 8) + '0';
367
		putstr("\x1b[10");
368
	}
369
	putstr(color);
370
	putstr("m");
3 nishi 371
	if(fg < 8) {
2 nishi 372
		color[0] = fg + '0';
373
		putstr("\x1b[3");
3 nishi 374
	} else {
2 nishi 375
		color[0] = (fg - 8) + '0';
376
		putstr("\x1b[9");
377
	}
378
	putstr(color);
379
	putstr("m");
380
	putstr("\x1b[2J\x1b[1;1H");
9 nishi 381
#elif defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 382
	int fg = (a >> 4) & 0xf;
383
	int bg = (a & 0xf);
384
	bgcolor(bg);
385
	textcolor(fg);
386
#endif
2 nishi 387
}
388
 
389
void clear(void) {
390
#if defined(PLATFORM_WINDOWS)
391
	system("cls");
392
#elif defined(PLATFORM_UNIX) || defined(PLATFORM_ARDUINO)
393
	putstr("\x1b[0m\x1b[2J\x1b[1;1H");
9 nishi 394
#elif defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 395
	clrscr();
2 nishi 396
#endif
397
}
398
 
399
void basic(void);
400
 
401
int main() {
9 nishi 402
#if defined(PLATFORM_PET)
403
	if(PEEK(0x9000) == POKE(0x9000, PEEK(0x9000) + 1)) {
404
		_heapadd((void*)0x9000, 0x2000);
405
	}
406
#endif
2 nishi 407
#if defined(PLATFORM_WINDOWS)
408
	HANDLE winstdout = GetStdHandle(STD_OUTPUT_HANDLE);
409
	DWORD mode = 0;
410
	GetConsoleMode(winstdout, &mode);
411
	const DWORD origmode = mode;
412
	mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
413
	SetConsoleMode(winstdout, mode);
414
#elif defined(PLATFORM_UNIX)
415
	struct termios old, new;
416
	tcgetattr(0, &old);
417
	new = old;
418
	new.c_lflag &= ~(ECHO | ICANON);
419
	tcsetattr(0, TCSANOW, &new);
420
#elif defined(PLATFORM_ARDUINO)
421
	uart_init();
422
	DDRB |= _BV(DDB5);
423
	PORTB |= _BV(PORT5);
424
#endif
9 nishi 425
#if defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 426
	change_color((1 << 4) | 0);
9 nishi 427
	bordercolor(0);
4 nishi 428
#endif
2 nishi 429
	basic();
430
#if defined(PLATFORM_WINDOWS)
431
	SetConsoleMode(winstdout, origmode);
432
#elif defined(PLATFORM_UNIX)
433
	tcsetattr(0, TCSANOW, &old);
434
#endif
435
}
436
 
437
#else
438
#error "Define PLATFORM_*"
439
#endif
440
 
441
#define VERSION "0.0"
442
 
443
#ifndef LINE_BUFFER_SIZE
444
#define LINE_BUFFER_SIZE (512)
445
#endif
446
 
447
#ifndef BUFFER_SIZE
448
#define BUFFER_SIZE (1024 * 24)
449
#endif
450
 
451
#ifndef LINES
452
#define LINES (1024)
453
#endif
454
 
37 nishi 455
unsigned char basicbuffer[BUFFER_SIZE / 2];
456
unsigned char varbuffer[BUFFER_SIZE / 2];
2 nishi 457
char linebuf[LINE_BUFFER_SIZE];
458
 
8 nishi 459
int hexnum(char c) {
460
	if('0' <= c && c <= '9') {
461
		return c - '0';
462
	} else if('A' <= c && c <= 'F') {
463
		return c - 'A' + 10;
464
	} else if('a' <= c && c <= 'f') {
465
		return c - 'a' + 10;
466
	}
467
	return 0;
468
}
469
 
2 nishi 470
int pexpr(char* expr, char* buffer, int* number) {
471
	char ownbuf[128];
472
	int i;
473
	int start = 0;
474
	int br = 0;
475
	int result = 0;
476
	int stack[32];
477
	int sp = 0;
478
	char put = 0;
8 nishi 479
	char hex = 0;
36 nishi 480
	if(expr[0] == '"' && expr[strlen(expr) - 1] == '"'){
481
		for(i = 1; expr[i + 1] != 0; i++){
482
			buffer[i - 1] = expr[i];
483
		}
484
		buffer[i - 1] = 0;
485
		return 0;
486
	}
4 nishi 487
	for(i = 0; expr[i] != 0; i++) ownbuf[i] = expr[i];
488
	ownbuf[i] = 0;
2 nishi 489
	for(i = 0; i < 32; i++) stack[i] = 0;
490
	for(i = 0;; i++) {
491
		if(ownbuf[i] == 0) {
492
			break;
8 nishi 493
		} else if(ownbuf[i] == '&' && put == 0) {
2 nishi 494
			put = 1;
8 nishi 495
			hex = 1;
496
		} else if(('0' <= ownbuf[i] && ownbuf[i] <= '9') || (hex ? ('A' <= ownbuf[i] && ownbuf[i] <= 'F') : 0) || (hex ? ('a' <= ownbuf[i] && ownbuf[i] <= 'f') : 0)) {
497
			stack[sp] *= hex ? 16 : 10;
498
			if(hex == 1) {
499
				stack[sp] += hexnum(ownbuf[i]);
500
			} else {
501
				stack[sp] += ownbuf[i] - '0';
502
			}
503
			put = 1;
28 nishi 504
#ifndef NO_PEEKPOKE
8 nishi 505
		} else if(ownbuf[i] == 'R') {
506
			put = 0;
507
			hex = 0;
508
			if(sp < 1) {
509
				return -1;
510
			} else {
511
				int top = stack[--sp];
512
				stack[sp++] = (int)*(unsigned char*)top;
513
			}
514
			stack[sp] = 0;
28 nishi 515
#endif
2 nishi 516
		} else if(ownbuf[i] == '+' || ownbuf[i] == '-' || ownbuf[i] == '*' || ownbuf[i] == '/') {
517
			put = 0;
8 nishi 518
			hex = 0;
2 nishi 519
			if(sp < 2) {
520
				return -1;
521
			} else {
522
				int top = stack[--sp];
523
				int bottom = stack[--sp];
524
				int value = 0;
525
				if(ownbuf[i] == '+') {
526
					value = top + bottom;
527
				} else if(ownbuf[i] == '-') {
528
					value = bottom + top;
529
				} else if(ownbuf[i] == '*') {
530
					value = mull(top, bottom);
531
				} else if(ownbuf[i] == '/') {
532
					value = divl(bottom, top);
533
				}
534
				stack[sp++] = value;
535
			}
536
			stack[sp] = 0;
537
		} else if(ownbuf[i] == ' ' && put == 1) {
538
			stack[++sp] = 0;
539
		}
540
	}
541
	result = stack[0];
542
	*number = result;
543
	return 1;
544
}
545
 
546
/* arr gets sorted, arr2 index gets replaced */
547
void sort(int* arr, int* arr2, int size) {
548
	int i;
549
redo:
550
	for(i = 1; i < size; i++) {
551
		if(arr[i - 1] > arr[i]) {
552
			int tmp = arr[i];
553
			arr[i] = arr[i - 1];
554
			arr[i - 1] = tmp;
555
			tmp = arr2[i];
556
			arr2[i] = arr2[i - 1];
557
			arr2[i - 1] = tmp;
558
		}
559
	}
560
	for(i = 1; i < size; i++) {
561
		if(arr[i - 1] > arr[i]) {
562
			goto redo;
563
		}
564
	}
565
}
566
 
567
int run(char* cmd, int linenum, char num, int* lgoto) {
4 nishi 568
	char line[LINE_BUFFER_SIZE];
569
	char rcmd[32];
570
	int i;
571
	char* arg;
572
	int incr = 0;
2 nishi 573
#ifdef BREAKKEY
574
	if(agetch() == 1) return -1;
575
#endif
576
	if(lgoto != 0) *lgoto = 0;
577
	for(i = 0; cmd[i] != 0; i++) line[i] = cmd[i];
578
	line[i] = 0;
579
	rcmd[0] = 0;
580
	for(i = 0;; i++) {
581
		if(line[i] == ' ' || line[i] == '\t' || line[i] == 0 || line[i] == '"') {
582
			break;
583
		} else {
584
			rcmd[incr++] = line[i];
585
			if(incr == 32) {
586
				putstr("! Command too long");
587
				if(linenum != -1) {
588
					putstr(" in line ");
589
					putnum(linenum);
590
				}
591
				putstr(NEWLINE);
592
				return 1;
593
			}
594
			rcmd[incr] = 0;
595
		}
596
	}
4 nishi 597
	arg = line + 1 + strlen(rcmd);
2 nishi 598
	if(strcaseequ(rcmd, "COLOR")) {
599
		int argc = 0;
600
		char* farg = 0;
601
		char* sarg = 0;
4 nishi 602
		int fgcolor, bgcolor, ret0, ret1;
2 nishi 603
		if(arg[0] != 0) argc++;
604
		for(i = 0; arg[i] != 0; i++) {
605
			if(arg[i] == ',') {
606
				arg[i] = 0;
607
				farg = arg;
608
				sarg = arg + i + 1;
609
				for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++)
610
					;
611
				argc++;
612
			}
613
		}
614
		if(argc != 2) {
615
			putstr("! Invalid argument");
616
			if(linenum != -1) {
617
				putstr(" in line ");
618
				putnum(linenum);
619
			}
620
			putstr(NEWLINE);
621
			return 1;
622
		}
4 nishi 623
		bgcolor = 0;
624
		fgcolor = 0;
625
		ret0 = pexpr(farg, 0, &bgcolor);
626
		ret1 = pexpr(sarg, 0, &fgcolor);
2 nishi 627
		if(ret0 == 0) {
628
			putstr("! Invalid argument");
629
			if(linenum != -1) {
630
				putstr(" in line ");
631
				putnum(linenum);
632
			}
633
			putstr(NEWLINE);
634
			return 1;
635
		} else if(ret0 == -1) {
636
			putstr("! Syntax error");
637
			if(linenum != -1) {
638
				putstr(" in line ");
639
				putnum(linenum);
640
			}
641
			putstr(NEWLINE);
642
			return 1;
643
		}
644
		if(ret1 == 1) {
645
			change_color((fgcolor << 4) | bgcolor);
646
		} else if(ret1 == 0) {
647
			putstr("! Invalid argument");
648
			if(linenum != -1) {
649
				putstr(" in line ");
650
				putnum(linenum);
651
			}
652
			putstr(NEWLINE);
653
			return 1;
654
		} else if(ret1 == -1) {
655
			putstr("! Syntax error");
656
			if(linenum != -1) {
657
				putstr(" in line ");
658
				putnum(linenum);
659
			}
660
			putstr(NEWLINE);
661
			return 1;
662
		}
36 nishi 663
	} else if(strcaseequ(rcmd, "PRINT")){
664
		if(arg[0] != 0){
665
			char sc = 0;
666
			int incr = 0;
667
			for(i = 0;; i++) {
668
				if(arg[i] != 0) sc = 0;
669
				if(arg[i] == ';' || arg[i] == 0) {
670
					char oldc = arg[i];
671
					arg[i] = 0;
672
 
673
					if(strlen(arg + incr) > 0){	
674
						char buffer[128];
675
 
676
						int number;
677
						int ret = pexpr(arg + incr, buffer, &number);
678
 
679
						if(ret == 0){
680
							putstr(buffer);
681
						}else if(ret == 1){
682
							putstr(" ");
683
							putnum(number);
684
						}else if(ret == -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
					}
694
 
695
					incr = i + 1;
696
					if(oldc == ';') sc = 1;
697
					if(oldc == 0) break;
698
				}
699
			}
700
			if(!sc) putstr(NEWLINE);
701
		}else{
702
			putstr(NEWLINE);
703
		}
28 nishi 704
#ifndef NO_PEEKPOKE
8 nishi 705
	} else if(strcaseequ(rcmd, "POKE")) {
706
		int argc = 0;
707
		char* farg = 0;
708
		char* sarg = 0;
709
		int addr, data, ret0, ret1;
710
		if(arg[0] != 0) argc++;
711
		for(i = 0; arg[i] != 0; i++) {
712
			if(arg[i] == ',') {
713
				arg[i] = 0;
714
				farg = arg;
715
				sarg = arg + i + 1;
716
				for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++)
717
					;
718
				argc++;
719
			}
720
		}
721
		if(argc != 2) {
722
			putstr("! Invalid argument");
723
			if(linenum != -1) {
724
				putstr(" in line ");
725
				putnum(linenum);
726
			}
727
			putstr(NEWLINE);
728
			return 1;
729
		}
730
		addr = 0;
731
		data = 0;
732
		ret0 = pexpr(farg, 0, &addr);
733
		ret1 = pexpr(sarg, 0, &data);
734
		if(ret0 == 0) {
735
			putstr("! Invalid argument");
736
			if(linenum != -1) {
737
				putstr(" in line ");
738
				putnum(linenum);
739
			}
740
			putstr(NEWLINE);
741
			return 1;
742
		} else if(ret0 == -1) {
743
			putstr("! Syntax error");
744
			if(linenum != -1) {
745
				putstr(" in line ");
746
				putnum(linenum);
747
			}
748
			putstr(NEWLINE);
749
			return 1;
750
		}
751
		if(ret1 == 1) {
752
			unsigned char* a = (unsigned char*)addr;
753
			*a = data;
754
		} else if(ret1 == 0) {
755
			putstr("! Invalid argument");
756
			if(linenum != -1) {
757
				putstr(" in line ");
758
				putnum(linenum);
759
			}
760
			putstr(NEWLINE);
761
			return 1;
762
		} else if(ret1 == -1) {
763
			putstr("! Syntax error");
764
			if(linenum != -1) {
765
				putstr(" in line ");
766
				putnum(linenum);
767
			}
768
			putstr(NEWLINE);
769
			return 1;
770
		}
28 nishi 771
#endif
2 nishi 772
	} else if(num == 0 && strcaseequ(rcmd, "LIST")) {
773
		int addr = BUFFER_SIZE - 1;
774
		int saddr = 0;
775
		int lbuf[LINES];
776
		int shift[LINES];
777
		int cnt = 0;
4 nishi 778
		int i;
2 nishi 779
		while(1) {
780
			unsigned long ln = 0;
781
			for(i = 0; i < 4; i++) {
782
				ln >>= 8;
783
				ln |= (unsigned long)basicbuffer[addr--] << 24;
784
			}
785
			if(ln == 0) break;
786
			lbuf[cnt] = ln;
787
			shift[cnt++] = saddr;
788
			saddr += strlen(basicbuffer + saddr) + 1;
789
		}
790
		sort(lbuf, shift, cnt);
791
		for(i = 0; i < cnt; i++) {
792
			putnum(lbuf[i]);
793
			putstr(" ");
794
			putstr(basicbuffer + shift[i]);
795
			putstr(NEWLINE);
796
		}
797
	} else if(num == 1 && strcaseequ(rcmd, "GOTO")) {
798
		int ret = pexpr(arg, 0, lgoto);
799
		if(ret == 0) {
800
			putstr("! Invalid argument");
801
			if(linenum != -1) {
802
				putstr(" in line ");
803
				putnum(linenum);
804
			}
805
			putstr(NEWLINE);
806
			return 1;
807
		} else if(ret == -1) {
808
			putstr("! Syntax error");
809
			if(linenum != -1) {
810
				putstr(" in line ");
811
				putnum(linenum);
812
			}
813
			putstr(NEWLINE);
814
			return 1;
815
		}
816
	} else if(num == 0 && strcaseequ(rcmd, "RUN")) {
817
		int addr = BUFFER_SIZE - 1;
818
		int saddr = 0;
819
		int lbuf[LINES];
820
		int shift[LINES];
821
		int cnt = 0;
4 nishi 822
		int gt, i;
2 nishi 823
		while(1) {
824
			unsigned long ln = 0;
825
			for(i = 0; i < 4; i++) {
826
				ln >>= 8;
827
				ln |= (unsigned long)basicbuffer[addr--] << 24;
828
			}
829
			if(ln == 0) break;
830
			lbuf[cnt] = ln;
831
			shift[cnt++] = saddr;
832
			saddr += strlen(basicbuffer + saddr) + 1;
833
		}
834
		sort(lbuf, shift, cnt);
835
		for(i = 0; i < cnt; i++) {
836
			int ret = run(basicbuffer + shift[i], lbuf[i], 1, &gt);
837
			if(ret != 0) return ret;
838
			if(gt != 0) {
4 nishi 839
				char found;
2 nishi 840
				for(i = 0; i < cnt; i++) {
841
					if(lbuf[i] == gt) {
842
						found = 1;
843
						break;
844
					}
845
				}
846
				if(found) {
847
					i--;
848
				} else {
849
					putstr("! GOTO no such line");
850
					if(linenum != -1) {
851
						putstr(" in line ");
852
						putnum(linenum);
853
					}
854
					putstr(NEWLINE);
855
					return 1;
856
				}
857
			}
858
		}
859
	} else {
860
		putstr("! Unknown command");
861
		if(linenum != -1) {
862
			putstr(" in line ");
863
			putnum(linenum);
864
		}
865
		putstr(NEWLINE);
866
		return 1;
867
	}
868
	return 0;
869
}
870
 
871
int execute(int linenum, char* cmd, char num) {
872
	int i;
873
	char line[LINE_BUFFER_SIZE];
874
	int incr = 0;
875
	char dq = 0;
876
	for(i = 0; cmd[i] != 0; i++) {
877
		if(cmd[i] == ' ' || cmd[i] == '\t') {
878
			if(!dq) {
879
				for(; cmd[i] != 0 && (cmd[i] == ' ' || cmd[i] == '\t'); i++)
880
					;
881
				i--;
882
			}
883
			line[incr++] = cmd[i];
884
		} else if(cmd[i] == '"') {
885
			line[incr++] = '"';
886
			dq = dq == 0 ? 1 : 0;
887
		} else {
888
			line[incr++] = dq == 0 ? toupper(cmd[i]) : cmd[i];
889
		}
890
	}
891
	line[incr] = 0;
892
	if(num == 0) {
893
		int ret = run(line, -1, 0, 0);
6 nishi 894
		putstr("Ready");
895
		putstr(NEWLINE);
2 nishi 896
		return ret;
897
	} else {
898
		int addr = BUFFER_SIZE - 1;
899
		int i;
900
		int shf = 0;
901
		int cnt = 0;
4 nishi 902
		int len;
2 nishi 903
		while(1) {
904
			unsigned long ln = 0;
905
			for(i = 0; i < 4; i++) {
906
				ln >>= 8;
907
				ln |= (unsigned long)basicbuffer[addr--] << 24;
908
			}
909
			cnt++;
910
			if(ln == linenum) shf = cnt;
911
			if(shf != 0) {
912
				addr += 4;
913
				for(i = 0; i < 4; i++) {
914
					basicbuffer[addr] = basicbuffer[addr - 4 * shf];
915
					addr--;
916
				}
917
				addr += 4;
918
				ln = 0;
919
				for(i = 0; i < 4; i++) {
920
					ln >>= 8;
921
					ln |= (unsigned long)basicbuffer[addr--] << 24;
922
				}
923
			}
924
			if(ln == 0) break;
925
		}
926
		if(line[0] != 0) {
927
			addr += 4;
928
			for(i = 0; i < 4; i++) {
929
				basicbuffer[addr--] = linenum & 0xff;
930
				linenum >>= 8;
931
			}
932
		}
4 nishi 933
		len = 0;
2 nishi 934
		cnt = 0;
935
		while(1) {
936
			int slen = strlen(basicbuffer + len);
937
			if(slen == 0) break;
938
			len += slen + 1;
939
			cnt++;
940
		}
941
		if(line[0] != 0) {
942
			for(i = 0; line[i] != 0; i++) {
943
				basicbuffer[len + i] = line[i];
944
			}
945
			basicbuffer[len + i] = 0;
946
			basicbuffer[len + i + 1] = 0;
947
		}
948
		if(shf != 0) {
949
			cnt = 0;
950
			len = 0;
951
			while(1) {
952
				int slen = strlen(basicbuffer + len);
953
				if(slen == 0) break;
954
 
955
				len += slen + 1;
956
				cnt++;
957
 
958
				if(cnt == shf) {
959
					int i;
960
					int nc = 0;
4 nishi 961
					len -= slen + 1;
2 nishi 962
					for(i = len;; i++) {
963
						basicbuffer[i] = basicbuffer[i + slen + 1];
964
						if(basicbuffer[i] == 0) {
965
							nc++;
966
							if(nc == 2) break;
967
						} else {
968
							nc = 0;
969
						}
970
					}
971
					break;
972
				}
973
			}
974
		}
975
		return 0;
976
	}
977
}
978
 
979
void basic(void) {
980
	int i;
4 nishi 981
	int lineind;
2 nishi 982
	clear();
983
 
984
#ifdef SMALL
985
	putstr("Krakow BASIC  Ver. ");
986
	putstr(VERSION);
987
	putstr(NEWLINE);
988
	putstr(NEWLINE);
989
#else
990
	putstr(PLATFORM);
991
	putstr("   Krakow BASIC V");
992
	putstr(VERSION);
6 nishi 993
	putstr(NEWLINE);
994
	putstr("Copyright 2024 by: Nishi.");
995
	putstr(NEWLINE);
2 nishi 996
	putstr("                   penguin2233.");
997
	putstr(NEWLINE);
998
	putstr(NEWLINE);
999
	putstr(" Max ");
1000
	putnum(LINE_BUFFER_SIZE);
1001
	putstr(" characters per line");
1002
	putstr(NEWLINE);
1003
	putstr(" Max ");
1004
	putnum(LINES);
1005
	putstr(" lines");
1006
	putstr(NEWLINE);
1007
	putstr(" ");
37 nishi 1008
	putstr("Variable buffer ");
1009
	putnum(BUFFER_SIZE / 2);
1010
	putstr(" bytes");
1011
	putstr(NEWLINE);
1012
	putstr(" ");
2 nishi 1013
#endif
37 nishi 1014
	putnum(BUFFER_SIZE / 2);
2 nishi 1015
	putstr(" bytes free");
1016
	putstr(NEWLINE);
1017
	putstr(NEWLINE);
1018
 
37 nishi 1019
	for(i = 0; i < BUFFER_SIZE / 2; i++) {
2 nishi 1020
		basicbuffer[i] = 0;
1021
	}
1022
	putstr("Ready");
1023
	putstr(NEWLINE);
1024
 
1025
	cursor();
1026
	linebuf[0] = 0;
4 nishi 1027
	lineind = 0;
2 nishi 1028
	while(1) {
4 nishi 1029
		char c;
29 nishi 1030
#if defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET) || defined(PLATFORM_MSX)
4 nishi 1031
		c = oggetch(1);
1032
#else
1033
		c = agetch();
1034
#endif
8 nishi 1035
		if(c != 0) {
1036
			killcursor();
1037
		}
2 nishi 1038
		if(c == 1) {
1039
			putstr("Break");
1040
			putstr(NEWLINE);
1041
			lineind = 0;
1042
		} else if(c == '\n') {
4 nishi 1043
			int i;
1044
			char num = 1;
1045
			char* cmd = linebuf;
1046
 
2 nishi 1047
			linebuf[lineind] = 0;
1048
			putstr(NEWLINE);
1049
			if(lineind == 0) goto skip;
1050
 
1051
			for(i = 0; linebuf[i] != 0; i++) {
1052
				if(linebuf[i] == ' ') {
1053
					linebuf[i] = 0;
1054
					cmd = linebuf + i + 1;
1055
					break;
1056
				} else if(!('0' <= linebuf[i] && linebuf[i] <= '9')) {
1057
					num = 0;
1058
					break;
1059
				}
1060
			}
1061
 
1062
			if(num == 1 && strnum(linebuf) == 0) {
1063
				putstr("! Line number 0 is illegal");
1064
				putstr(NEWLINE);
1065
			} else {
1066
				int ret = execute(num == 1 ? strnum(linebuf) : -1, (num == 1 && cmd == linebuf) ? "" : cmd, num);
1067
				if(ret == -1) {
1068
					putstr("! Break");
1069
					putstr(NEWLINE);
1070
				}
1071
			}
1072
 
1073
		skip:
1074
			lineind = 0;
1075
		} else if(c == 0x8 || c == 0x7f) {
1076
			if(lineind > 0) {
6 nishi 1077
#if defined(PLATFORM_A800XL)
1078
				putstr("\x7e \x7e");
1079
#else
2 nishi 1080
				putstr("\x08 \x08");
6 nishi 1081
#endif
2 nishi 1082
				linebuf[--lineind] = 0;
1083
			}
1084
		} else if(c == -1) {
1085
			break;
1086
		} else if(c != 0) {
1087
			putchar(c);
1088
			linebuf[lineind++] = c;
1089
		}
1090
		cursor();
1091
	}
1092
}