Benutzer-Werkzeuge

Webseiten-Werkzeuge


start

Dies ist eine alte Version des Dokuments!


Füge global dazu:

static uint8 g_shift = 0;
static uint8 g_caps  = 0;


Und passe get_keycode_once() so an, dass Modifier-Tasten den Zustand setzen und nicht als Zeichen zurückkommen:

int get_keycode_once(uint8 *out_scancode)
{
  if (!kbd_has_data()) return 0;
  uint8 sc = kbd_read_data();

  if (sc == 0xE0) { e0_prefix = 1; return 0; }

  // Break (release)
  if (sc & 0x80) {
    uint8 make = sc & 0x7F;

    // Shift released?
    if (!e0_prefix && (make == 0x2A || make == 0x36)) g_shift = 0;

    if (!e0_prefix && make < 128) key_down[make] = 0;
    e0_prefix = 0;
    return 0;
  }

  // Make (press)
  if (!e0_prefix) {
    // Shift pressed?
    if (sc == 0x2A || sc == 0x36) { g_shift = 1; return 0; }

    // CapsLock toggled?
    if (sc == 0x3A) { g_caps ^= 1; return 0; }

    // suppress repeats
    if (sc < 128) {
      if (key_down[sc]) return 0;
      key_down[sc] = 1;
    }
  }

  e0_prefix = 0;
  *out_scancode = sc;
  return 1;
}

2) ASCII-Übersetzung mit Shift (US-Map als Basis)

Ersetze/ergänze deine get_ascii_char()-Logik durch eine Funktion, die Shift/Caps berücksichtigt:

static const char kbd_us[128] = {
  0,  27,'1','2','3','4','5','6','7','8','9','0','-','=',  '\b',
  '\t','q','w','e','r','t','y','u','i','o','p','[',']','\n', 0,
  'a','s','d','f','g','h','j','k','l',';','\'','`', 0,'\\',
  'z','x','c','v','b','n','m',',','.','/', 0,  '*', 0,' ',
  /* rest 0 */ 
};

static const char kbd_us_shift[128] = {
  0,  27,'!','@','#','$','%','^','&','*','(',')','_','+',  '\b',
  '\t','Q','W','E','R','T','Y','U','I','O','P','{','}','\n', 0,
  'A','S','D','F','G','H','J','K','L',':','"','~', 0,'|',
  'Z','X','C','V','B','N','M','<','>','?', 0,  '*', 0,' ',
};

static char get_ascii_char_ex(uint8 sc)
{
  if (sc >= 128) return 0;

  char c = g_shift ? kbd_us_shift[sc] : kbd_us[sc];

  // CapsLock nur für Buchstaben (und Shift invertiert Caps)
  if (c >= 'a' && c <= 'z') {
    if (g_caps ^ g_shift) c = (char)(c - 'a' + 'A');
  } else if (c >= 'A' && c <= 'Z') {
    if (g_caps ^ g_shift) c = (char)(c - 'A' + 'a');
  }

  return c;
}
// erlaubte Zeichen für Mini-BASIC
static int is_allowed_basic_char(char c) {
    if (c == ' ' || c == '.' || c == '"' || c == '=' || c == '+' || c == '-' ||
        c == '*' || c == '/' || c == '(' || c == ')' || c == '<' || c == '>' ||
        c == ',' ) return 1;

    if (c >= 'A' && c <= 'Z') return 1;
    if (c >= '0' && c <= '9') return 1;
    return 0;
}
// ===================== MINI BASIC (int-only) =====================

#define BASIC_MAX_LINES 64
#define BASIC_LINE_LEN  96

typedef struct {
    uint16 line_no;
    uint8  used;
    char   text[BASIC_LINE_LEN];
} BasicLine;

static BasicLine g_prog[BASIC_MAX_LINES];
static int g_vars[26]; // A..Z

static void basic_reset_program(void) {
    for (int i = 0; i < BASIC_MAX_LINES; i++) {
        g_prog[i].used = 0;
        g_prog[i].line_no = 0;
        g_prog[i].text[0] = 0;
    }
}

static void basic_reset_vars(void) {
    for (int i = 0; i < 26; i++) g_vars[i] = 0;
}

static int is_space(char c) { return c == ' ' || c == '\t'; }

static char up(char c) {
    if (c >= 'a' && c <= 'z') return (char)(c - 'a' + 'A');
    return c;
}

static void skip_spaces(const char **p) {
    while (**p && is_space(**p)) (*p)++;
}

static int is_digit(char c) { return (c >= '0' && c <= '9'); }
static int is_alpha(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); }

static int starts_with_kw(const char *s, const char *kw) {
    // case-insensitive, kw muss "Wortgrenze" haben (Ende oder Space)
    int i = 0;
    while (kw[i]) {
        if (up(s[i]) != kw[i]) return 0;
        i++;
    }
    char next = s[i];
    return (next == 0 || is_space(next));
}

static uint16 parse_u16(const char **p) {
    skip_spaces(p);
    uint16 v = 0;
    while (is_digit(**p)) {
        v = (uint16)(v * 10 + (**p - '0'));
        (*p)++;
    }
    return v;
}

static int parse_int(const char **p) {
    skip_spaces(p);
    int sign = 1;
    if (**p == '+') { (*p)++; }
    else if (**p == '-') { sign = -1; (*p)++; }

    int v = 0;
    while (is_digit(**p)) {
        v = v * 10 + (**p - '0');
        (*p)++;
    }
    return v * sign;
}

static int find_line_index(uint16 line_no) {
    for (int i = 0; i < BASIC_MAX_LINES; i++) {
        if (g_prog[i].used && g_prog[i].line_no == line_no) return i;
    }
    return -1;
}

static int find_free_slot(void) {
    for (int i = 0; i < BASIC_MAX_LINES; i++) {
        if (!g_prog[i].used) return i;
    }
    return -1;
}

static int find_next_line_sorted(uint16 last_line, uint16 *out_line, int *out_idx) {
    int found = 0;
    uint16 best = 0xFFFF;
    int best_i = -1;

    for (int i = 0; i < BASIC_MAX_LINES; i++) {
        if (!g_prog[i].used) continue;
        uint16 ln = g_prog[i].line_no;
        if (ln > last_line && ln < best) {
            best = ln;
            best_i = i;
            found = 1;
        }
    }

    if (!found) return 0;
    *out_line = best;
    *out_idx = best_i;
    return 1;
}

static void basic_store_line(uint16 line_no, const char *rest) {
    // rest: nach der Zeilennummer (inkl. leading spaces)
    // Wenn rest leer -> löschen
    const char *p = rest;
    skip_spaces(&p);

    int idx = find_line_index(line_no);

    if (*p == 0) {
        if (idx >= 0) g_prog[idx].used = 0;
        return;
    }

    if (idx < 0) {
        idx = find_free_slot();
        if (idx < 0) {
            print_new_line();
            print_string("BASIC: OUT OF PROGRAM SPACE");
            return;
        }
        g_prog[idx].used = 1;
        g_prog[idx].line_no = line_no;
    }

    // copy text, uppercase keywords funktionieren trotzdem case-insensitive
    int j = 0;
    while (*p && j < BASIC_LINE_LEN - 1) {
        g_prog[idx].text[j++] = *p++;
    }
    g_prog[idx].text[j] = 0;
}

static void basic_list(void) {
    uint16 last = 0;
    uint16 ln;
    int idx;

    while (find_next_line_sorted(last, &ln, &idx)) {
        print_new_line();
        print_int((int)ln);
        print_string(" ");
        print_string(g_prog[idx].text);
        last = ln;
    }
}

static void basic_error(const char *msg) {
    print_new_line();
    print_string("BASIC ERROR: ");
    print_string((char*)msg);
}

// ---------- Expression parser (recursive descent) ----------
static int parse_expr(const char **p); // forward

static int parse_factor(const char **p) {
    skip_spaces(p);

    // unary
    if (**p == '+') { (*p)++; return parse_factor(p); }
    if (**p == '-') { (*p)++; return -parse_factor(p); }

    if (**p == '(') {
        (*p)++;
        int v = parse_expr(p);
        skip_spaces(p);
        if (**p == ')') (*p)++;
        else basic_error("MISSING )");
        return v;
    }

    // variable
    if (is_alpha(**p)) {
        char c = up(**p);
        (*p)++;
        if (c >= 'A' && c <= 'Z') return g_vars[c - 'A'];
        return 0;
    }

    // number
    if (is_digit(**p)) {
        return parse_int(p);
    }

    basic_error("BAD FACTOR");
    return 0;
}

static int parse_term(const char **p) {
    int v = parse_factor(p);
    for (;;) {
        skip_spaces(p);
        if (**p == '*') { (*p)++; v = v * parse_factor(p); }
        else if (**p == '/') {
            (*p)++;
            int d = parse_factor(p);
            if (d == 0) { basic_error("DIV BY ZERO"); return 0; }
            v = v / d;
        } else break;
    }
    return v;
}

static int parse_expr(const char **p) {
    int v = parse_term(p);
    for (;;) {
        skip_spaces(p);
        if (**p == '+') { (*p)++; v = v + parse_term(p); }
        else if (**p == '-') { (*p)++; v = v - parse_term(p); }
        else break;
    }
    return v;
}

static int parse_relop(const char **p, const char **out_op) {
    skip_spaces(p);
    // supported: =, <, >, <=, >=, <>
    if (**p == '=') { *out_op = "="; (*p)++; return 1; }
    if (**p == '<') {
        (*p)++;
        if (**p == '=') { *out_op = "<="; (*p)++; return 1; }
        if (**p == '>') { *out_op = "<>"; (*p)++; return 1; }
        *out_op = "<"; return 1;
    }
    if (**p == '>') {
        (*p)++;
        if (**p == '=') { *out_op = ">="; (*p)++; return 1; }
        *out_op = ">"; return 1;
    }
    return 0;
}

static int eval_relation(int a, int b, const char *op) {
    if (op[0] == '=' && op[1] == 0) return a == b;
    if (op[0] == '<' && op[1] == 0) return a < b;
    if (op[0] == '>' && op[1] == 0) return a > b;
    if (op[0] == '<' && op[1] == '=') return a <= b;
    if (op[0] == '>' && op[1] == '=') return a >= b;
    if (op[0] == '<' && op[1] == '>') return a != b;
    return 0;
}

// ---------- Statement execution ----------
static int basic_exec_stmt(const char *line, uint16 *pc_line /*in/out*/, int *stop /*out*/) {
    const char *p = line;
    skip_spaces(&p);

    if (*p == 0) return 1;

    // REM
    if (starts_with_kw(p, "REM")) return 1;

    // END
    if (starts_with_kw(p, "END")) { *stop = 1; return 1; }

    // PRINT
    if (starts_with_kw(p, "PRINT")) {
        p += 5;
        skip_spaces(&p);

        // PRINT "TEXT"
        if (*p == '"') {
            p++;
            print_new_line();
            while (*p && *p != '"') {
                print_char(*p++);
            }
            if (*p == '"') p++;
            return 1;
        }

        // PRINT expr
        int v = parse_expr(&p);
        print_new_line();
        print_int(v);
        return 1;
    }

    // LET (optional)
    if (starts_with_kw(p, "LET")) {
        p += 3;
        skip_spaces(&p);
    }

    // IF expr rel expr THEN line
    if (starts_with_kw(p, "IF")) {
        p += 2;
        int left = parse_expr(&p);

        const char *op = 0;
        if (!parse_relop(&p, &op)) { basic_error("IF NEEDS RELOP"); return 0; }

        int right = parse_expr(&p);

        skip_spaces(&p);
        if (!starts_with_kw(p, "THEN")) { basic_error("IF NEEDS THEN"); return 0; }
        p += 4;

        uint16 target = parse_u16(&p);
        if (target == 0) { basic_error("BAD THEN LINE"); return 0; }

        if (eval_relation(left, right, op)) {
            *pc_line = (uint16)(target - 1); // Trick: RUN loop nimmt "next > pc_line"
        }
        return 1;
    }

    // GOTO line
    if (starts_with_kw(p, "GOTO")) {
        p += 4;
        uint16 target = parse_u16(&p);
        if (target == 0) { basic_error("BAD GOTO LINE"); return 0; }
        *pc_line = (uint16)(target - 1);
        return 1;
    }

    // Assignment: A = expr
    if (is_alpha(*p)) {
        char vname = up(*p++);
        if (vname < 'A' || vname > 'Z') { basic_error("BAD VAR"); return 0; }
        skip_spaces(&p);
        if (*p != '=') { basic_error("EXPECTED ="); return 0; }
        p++;
        int value = parse_expr(&p);
        g_vars[vname - 'A'] = value;
        return 1;
    }

    basic_error("UNKNOWN STATEMENT");
    return 0;
}

static void basic_run(void) {
    uint16 pc = 0;         // last executed line_no (for sorted iteration)
    int stop = 0;

    // Start at "before" first line:
    pc = 0;

    while (!stop) {
        uint16 ln;
        int idx;
        if (!find_next_line_sorted(pc, &ln, &idx)) break;

        // execute
        uint16 pc_before = ln;
        uint16 pc_line = ln;
        basic_exec_stmt(g_prog[idx].text, &pc_line, &stop);

        // pc_line may be changed by GOTO/IF
        pc = pc_line;

        // normal case: move to next after current
        if (pc == pc_before) pc = ln;
    }
}

// ---------- REPL line handler ----------
static void basic_repl_line(const char *input) {
    const char *p = input;
    skip_spaces(&p);
    if (*p == 0) return;

    // line starts with number? -> program line
    if (is_digit(*p)) {
        uint16 ln = parse_u16(&p);
        basic_store_line(ln, p);
        return;
    }

    // Immediate commands
    if (starts_with_kw(p, "LIST")) { basic_list(); return; }
    if (starts_with_kw(p, "RUN"))  { basic_run(); return; }
    if (starts_with_kw(p, "NEW"))  { basic_reset_program(); basic_reset_vars(); print_new_line(); print_string("OK"); return; }

    // keep your old shell commands too:
    if (starts_with_kw(p, "HELP")) {
        print_new_line();
        print_string("Available commands:");
        print_new_line();
        print_string("  HELP   - Prints this help");
        print_new_line();
        print_string("  REBOOT - Reboot the system");
        print_new_line();
        print_string("  NEW    - Clear BASIC program + vars");
        print_new_line();
        print_string("  LIST   - List BASIC program");
        print_new_line();
        print_string("  RUN    - Run BASIC program");
        print_new_line();
        print_string("BASIC examples:");
        print_new_line();
        print_string("  10 A=1+2*3");
        print_new_line();
        print_string("  20 PRINT A");
        print_new_line();
        print_string("  30 IF A=7 THEN 50");
        print_new_line();
        print_string("  40 GOTO 20");
        print_new_line();
        print_string("  50 END");
        return;
    }

    if (starts_with_kw(p, "REBOOT")) { do_reboot(); return; }

    // Otherwise: treat as immediate BASIC statement (PRINT/LET/A=.../IF/GOTO/END)
    uint16 dummy = 0;
    int stop = 0;
    basic_exec_stmt(p, &dummy, &stop);
}

Hallo Besucher! Willkommen in diesem kleinen Wiki rund um IT. Vieles ist noch unvollständig, unstrukturiert oder vielleicht sogar falsch bzw. irreführend.

Du kannst Artikel gerne ergänzen oder verbessern. Gerne mit so vielen Links wie nötig. Bitte keine Werbelinks und nur selbst verfasste oder lizenzfreie Texte! Copyright beachten!

Fehlende Verlinkungen

start.1765039591.txt.gz · Zuletzt geändert: 2025/12/06 17:46 von jango