Subversion Repositories Krakow BASIC

Rev

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