Subversion Repositories Krakow BASIC

Rev

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