Subversion Repositories Shiroi

Rev

Rev 33 | Blame | Last modification | View Log | Download | RSS feed

/* $Id: basic.c 35 2024-09-01 15:14:41Z nishi $ */

#include "dri/text.h"
#include "dri/video.h"
#include "dri/math.h"

#include "mem.h"
#include "char.h"

#define VERSION "0.0"
#define LINE_BUFFER_SIZE 512
#define BUFFER_SIZE (1024 * 24)

unsigned char basicbuffer[BUFFER_SIZE];
char linebuf[LINE_BUFFER_SIZE];

int pexpr(char* expr, char* buffer, int* number){
        char ownbuf[128];
        int i;
        for(i = 0; expr[i] != 0; i++) ownbuf[i] = expr[i];
        ownbuf[i] = 0;
        int start = 0;
        int br = 0;
        int result = 0;
        int stack[128];
        int sp = 0;
        char put = 0;
        for(i = 0; i < 128; i++) stack[i] = 0;
        for(i = 0;; i++){
                if(ownbuf[i] == 0){
                        break;
                }else if('0' <= ownbuf[i] && ownbuf[i] <= '9'){
                        stack[sp] *= 10;
                        stack[sp] += ownbuf[i] - '0';
                        put = 1;
                }else if(ownbuf[i] == '+' || ownbuf[i] == '-' || ownbuf[i] == '*' || ownbuf[i] == '/'){
                        put = 0;
                        if(sp < 2){
                                return -1;
                        }else{
                                int top = stack[--sp];
                                int bottom = stack[--sp];
                                int value = 0;
                                if(ownbuf[i] == '+'){
                                        value = top + bottom;
                                }else if(ownbuf[i] == '-'){
                                        value = bottom + top;
                                }else if(ownbuf[i] == '*'){
                                        value = mull(top, bottom);
                                }else if(ownbuf[i] == '/'){
                                        value = divl(bottom, top);
                                }
                                stack[sp++] = value;
                        }
                        stack[sp] = 0;
                }else if(ownbuf[i] == ' ' && put == 1){
                        stack[++sp] = 0;
                }
        }
        result = stack[0];
        *number = result;
        return 1;
}

/* arr gets sorted, arr2 index gets replaced */
void sort(int* arr, int* arr2, int size){
        int i;
redo:
        for(i = 1; i < size; i++){
                if(arr[i - 1] > arr[i]){
                        int tmp = arr[i];
                        arr[i] = arr[i - 1];
                        arr[i - 1] = tmp;
                        tmp = arr2[i];
                        arr2[i] = arr2[i - 1];
                        arr2[i - 1] = tmp;
                }
        }
        for(i = 1; i < size; i++){
                if(arr[i - 1] > arr[i]){
                        goto redo;
                }
        }
}

int run(char* cmd, int linenum, char num, int* lgoto){
        if(agetch() == 1) return -1;
        char line[LINE_BUFFER_SIZE];
        char rcmd[32];
        int i;
        if(lgoto != 0) *lgoto = 0;
        for(i = 0; cmd[i] != 0; i++) line[i] = cmd[i];
        line[i] = 0;
        rcmd[0] = 0;
        int incr = 0;
        for(i = 0;; i++){
                if(line[i] == ' ' || line[i] == '\t' || line[i] == 0 || line[i] == '"'){
                        break;
                }else{
                        rcmd[incr++] = line[i];
                        if(incr == 32){
                                putstr("! Command too long");
                                if(linenum != -1){
                                        putstr(" in line ");
                                        putnum(linenum);
                                }
                                putstr("\r\n");
                                return 1;
                        }
                        rcmd[incr] = 0;
                }
        }
        char* arg = line + 1 + strlen(rcmd);
        if(strcaseequ(rcmd, "COLOR")){
                int argc = 0;
                char* farg = 0;
                char* sarg = 0;
                if(arg[0] != 0) argc++;
                for(i = 0; arg[i] != 0; i++){
                        if(arg[i] == ','){
                                arg[i] = 0;
                                farg = arg;
                                sarg = arg + i + 1;
                                for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++);
                                argc++;
                        }
                }
                if(argc != 2){
                        putstr("! Invalid argument");
                        if(linenum != -1){
                                putstr(" in line ");
                                putnum(linenum);
                        }
                        putstr("\r\n");
                        return 1;
                }
                int bgcolor = 0;
                int fgcolor = 0;
                int ret0 = pexpr(farg, 0, &bgcolor);
                int ret1 = pexpr(sarg, 0, &fgcolor);
                if(ret0 == 0){
                        putstr("! Invalid argument");
                        if(linenum != -1){
                                putstr(" in line ");
                                putnum(linenum);
                        }
                        putstr("\r\n");
                        return 1;
                }else if(ret0 == -1){
                        putstr("! Syntax error");
                        if(linenum != -1){
                                putstr(" in line ");
                                putnum(linenum);
                        }
                        putstr("\r\n");
                        return 1;
                }
                if(ret1 == 1){
                        change_color((fgcolor << 4) | bgcolor);
                }else if(ret1 == 0){
                        putstr("! Invalid argument");
                        if(linenum != -1){
                                putstr(" in line ");
                                putnum(linenum);
                        }
                        putstr("\r\n");
                        return 1;
                }else if(ret1 == -1){
                        putstr("! Syntax error");
                        if(linenum != -1){
                                putstr(" in line ");
                                putnum(linenum);
                        }
                        putstr("\r\n");
                        return 1;
                }
        }else if(num == 0 && strcaseequ(rcmd, "LIST")){
                int addr = BUFFER_SIZE - 1;
                int saddr = 0;
                int lbuf[1024];
                int shift[1024];
                int cnt = 0;
                while(1){
                        unsigned long ln = 0;
                        for(i = 0; i < 4; i++){
                                ln >>= 8;
                                ln |= (unsigned long)basicbuffer[addr--] << 24;
                        }
                        if(ln == 0) break;
                        lbuf[cnt] = ln;
                        shift[cnt++] = saddr;
                        saddr += strlen(basicbuffer + saddr) + 1;
                }
                sort(lbuf, shift, cnt);
                int i;
                for(i = 0; i < cnt; i++){
                        putnum(lbuf[i]);
                        putstr(" ");
                        putstr(basicbuffer + shift[i]);
                        putstr("\r\n");
                }
        }else if(num == 1 && strcaseequ(rcmd, "GOTO")){
                int ret = pexpr(arg, 0, lgoto);
                if(ret == 0){
                        putstr("! Invalid argument");
                        if(linenum != -1){
                                putstr(" in line ");
                                putnum(linenum);
                        }
                        putstr("\r\n");
                        return 1;
                }else if(ret == -1){
                        putstr("! Syntax error");
                        if(linenum != -1){
                                putstr(" in line ");
                                putnum(linenum);
                        }
                        putstr("\r\n");
                        return 1;
                }
        }else if(num == 0 && strcaseequ(rcmd, "RUN")){
                int addr = BUFFER_SIZE - 1;
                int saddr = 0;
                int lbuf[1024];
                int shift[1024];
                int cnt = 0;
                int gt;
                while(1){
                        unsigned long ln = 0;
                        for(i = 0; i < 4; i++){
                                ln >>= 8;
                                ln |= (unsigned long)basicbuffer[addr--] << 24;
                        }
                        if(ln == 0) break;
                        lbuf[cnt] = ln;
                        shift[cnt++] = saddr;
                        saddr += strlen(basicbuffer + saddr) + 1;
                }
                sort(lbuf, shift, cnt);
                int i;
                for(i = 0; i < cnt; i++){
                        int ret = run(basicbuffer + shift[i], lbuf[i], 1, &gt);
                        if(ret != 0) return ret;
                        if(gt != 0){
                                char found = 0;
                                for(i = 0; i < cnt; i++){
                                        if(lbuf[i] == gt){
                                                found = 1;
                                                break;
                                        }
                                }
                                if(found){
                                        i--;
                                }else{
                                        putstr("! GOTO no such line");
                                        if(linenum != -1){
                                                putstr(" in line ");
                                                putnum(linenum);
                                        }
                                        putstr("\r\n");
                                        return 1;
                                }
                        }
                }
        }else{
                putstr("! Unknown command");
                if(linenum != -1){
                        putstr(" in line ");
                        putnum(linenum);
                }
                putstr("\r\n");
                return 1;
        }
        return 0;
}

int execute(int linenum, char* cmd, char num){
        int i;
        char line[LINE_BUFFER_SIZE];
        int incr = 0;
        char dq = 0;
        for(i = 0; cmd[i] != 0; i++){
                if(cmd[i] == ' ' || cmd[i] == '\t'){
                        if(!dq){
                                for(; cmd[i] != 0 && (cmd[i] == ' ' || cmd[i] == '\t'); i++);
                                i--;
                        }
                        line[incr++] = cmd[i];
                }else if(cmd[i] == '"'){
                        line[incr++] = '"';
                        dq = dq == 0 ? 1 : 0;
                }else{
                        line[incr++] = dq == 0 ? toupper(cmd[i]) : cmd[i];
                }
        }
        line[incr] = 0;
        if(num == 0){
                int ret = run(line, -1, 0, 0);
                putstr("Ready\r\n");
                return ret;
        }else{
                int addr = BUFFER_SIZE - 1;
                int i;
                int shf = 0;
                int cnt = 0;
                while(1){
                        unsigned long ln = 0;
                        for(i = 0; i < 4; i++){
                                ln >>= 8;
                                ln |= (unsigned long)basicbuffer[addr--] << 24;
                        }
                        cnt++;
                        if(ln == linenum) shf = cnt;
                        if(shf != 0){
                                addr += 4;
                                for(i = 0; i < 4; i++){
                                        basicbuffer[addr] = basicbuffer[addr - 4 * shf];
                                        addr--;
                                }
                                addr += 4;
                                ln = 0;
                                for(i = 0; i < 4; i++){
                                        ln >>= 8;
                                        ln |= (unsigned long)basicbuffer[addr--] << 24;
                                }
                        }
                        if(ln == 0) break;
                }
                if(line[0] != 0){
                        addr += 4;
                        for(i = 0; i < 4; i++){
                                basicbuffer[addr--] = linenum & 0xff;
                                linenum >>= 8;
                        }
                }
                int len = 0;
                cnt = 0;
                while(1){
                        int slen = strlen(basicbuffer + len);
                        if(slen == 0) break;
                        len += slen + 1;
                        cnt++;
                }
                if(line[0] != 0){
                        for(i = 0; line[i] != 0; i++){
                                basicbuffer[len + i] = line[i];
                        }
                        basicbuffer[len + i] = 0;
                        basicbuffer[len + i + 1] = 0;
                }
                if(shf != 0){
                        cnt = 0;
                        len = 0;
                        while(1){
                                int slen = strlen(basicbuffer + len);
                                if(slen == 0) break;

                                len += slen + 1;
                                cnt++;

                                if(cnt == shf){
                                        len -= slen + 1;
                                        int i;
                                        int nc = 0;
                                        for(i = len;; i++){
                                                basicbuffer[i] = basicbuffer[i + slen + 1];
                                                if(basicbuffer[i] == 0){
                                                        nc++;
                                                        if(nc == 2) break;
                                                }else{
                                                        nc = 0;
                                                }
                                        }
                                        break;
                                }
                        }
                }
                return 0;
        }
}

void basic(void){
        int i;
        clear();

        putstr(PLATFORM);
        putstr("   Krakow BASIC V");
        putstr(VERSION);
        putstr("\r\n");
        putstr("Copyright 2024 by: Nishi.\r\n");
        putstr("                   penguin2233.\r\n\r\n ");
        putnum(BUFFER_SIZE);
        putstr(" bytes free\r\n");
        putstr("\r\n");

        for(i = 0; i < BUFFER_SIZE; i++){
                basicbuffer[i] = 0;
        }
        putstr("Ready\r\n");

        cursor();
        linebuf[0] = 0;
        int lineind = 0;
        while(1){
                char c = agetch();
                if(c != 0) killcursor();
                if(c == 1){
                        putstr("Break\r\n");
                        lineind = 0;
                }else if(c == '\n'){
                        linebuf[lineind] = 0;
                        putstr("\r\n");
                        if(lineind == 0) goto skip;

                        int i;
                        char num = 1;

                        char* cmd = linebuf;

                        for(i = 0; linebuf[i] != 0; i++){
                                if(linebuf[i] == ' '){
                                        linebuf[i] = 0;
                                        cmd = linebuf + i + 1;
                                        break;
                                }else if(!('0' <= linebuf[i] && linebuf[i] <= '9')){
                                        num = 0;
                                        break;
                                }
                        }

                        if(num == 1 && strnum(linebuf) == 0){
                                putstr("! Line number 0 is illegal\r\n");
                        }else{
                                int ret = execute(num == 1 ? strnum(linebuf) : -1, (num == 1 && cmd == linebuf) ? "" : cmd, num);
                                if(ret == -1){
                                        putstr("! Break\r\n");
                                }
                        }

skip:
                        lineind = 0;
                }else if(c == 0x8){
                        if(lineind > 0){
                                putstr("\x08 \x08");
                                lineind--;
                        }
                }else if(c != 0){
                        putchar(c);
                        linebuf[lineind++] = c;
                }
                cursor();
        }
}