Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
|
start [2025/12/06 17:52] jango |
start [2025/12/10 10:09] (aktuell) jango |
||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | < | ||
| - | // German (DE) layout, scancode set 1 | ||
| - | static const char kbd_de[128] = { | ||
| - | 0, 27, ' | ||
| - | ' | ||
| - | ' | ||
| - | ' | ||
| - | /* rest 0 */ | ||
| - | }; | ||
| - | |||
| - | static const char kbd_de_shift[128] = { | ||
| - | 0, 27, ' | ||
| - | ' | ||
| - | ' | ||
| - | ' | ||
| - | /* rest 0 */ | ||
| - | }; | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | Füge global dazu: | ||
| - | |||
| - | static uint8 g_shift = 0; | ||
| - | static uint8 g_caps | ||
| - | |||
| - | |||
| - | 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/ | ||
| - | |||
| - | static const char kbd_us[128] = { | ||
| - | 0, 27,' | ||
| - | ' | ||
| - | ' | ||
| - | ' | ||
| - | /* rest 0 */ | ||
| - | }; | ||
| - | |||
| - | static const char kbd_us_shift[128] = { | ||
| - | 0, 27,' | ||
| - | ' | ||
| - | ' | ||
| - | ' | ||
| - | }; | ||
| - | |||
| - | 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 >= ' | ||
| - | if (g_caps ^ g_shift) c = (char)(c - ' | ||
| - | } else if (c >= ' | ||
| - | if (g_caps ^ g_shift) c = (char)(c - ' | ||
| - | } | ||
| - | |||
| - | return c; | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | // erlaubte Zeichen für Mini-BASIC | ||
| - | static int is_allowed_basic_char(char c) { | ||
| - | if (c == ' ' || c == ' | ||
| - | c == ' | ||
| - | c == ',' | ||
| - | |||
| - | if (c >= ' | ||
| - | if (c >= ' | ||
| - | return 0; | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | // ===================== MINI BASIC (int-only) ===================== | ||
| - | |||
| - | #define BASIC_MAX_LINES 64 | ||
| - | #define BASIC_LINE_LEN | ||
| - | |||
| - | typedef struct { | ||
| - | uint16 line_no; | ||
| - | uint8 used; | ||
| - | char | ||
| - | } 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; | ||
| - | 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 == ' | ||
| - | |||
| - | static char up(char c) { | ||
| - | if (c >= ' | ||
| - | return c; | ||
| - | } | ||
| - | |||
| - | static void skip_spaces(const char **p) { | ||
| - | while (**p && is_space(**p)) (*p)++; | ||
| - | } | ||
| - | |||
| - | static int is_digit(char c) { return (c >= ' | ||
| - | static int is_alpha(char c) { return (c >= ' | ||
| - | |||
| - | static int starts_with_kw(const char *s, const char *kw) { | ||
| - | // case-insensitive, | ||
| - | 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 - ' | ||
| - | (*p)++; | ||
| - | } | ||
| - | return v; | ||
| - | } | ||
| - | |||
| - | static int parse_int(const char **p) { | ||
| - | skip_spaces(p); | ||
| - | int sign = 1; | ||
| - | if (**p == ' | ||
| - | else if (**p == ' | ||
| - | |||
| - | int v = 0; | ||
| - | while (is_digit(**p)) { | ||
| - | v = v * 10 + (**p - ' | ||
| - | (*p)++; | ||
| - | } | ||
| - | return v * sign; | ||
| - | } | ||
| - | |||
| - | static int find_line_index(uint16 line_no) { | ||
| - | for (int i = 0; i < BASIC_MAX_LINES; | ||
| - | 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; | ||
| - | 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; | ||
| - | 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(& | ||
| - | |||
| - | 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(" | ||
| - | 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, | ||
| - | 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(" | ||
| - | 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 == ' | ||
| - | if (**p == ' | ||
| - | |||
| - | if (**p == ' | ||
| - | (*p)++; | ||
| - | int v = parse_expr(p); | ||
| - | skip_spaces(p); | ||
| - | if (**p == ' | ||
| - | else basic_error(" | ||
| - | return v; | ||
| - | } | ||
| - | |||
| - | // variable | ||
| - | if (is_alpha(**p)) { | ||
| - | char c = up(**p); | ||
| - | (*p)++; | ||
| - | if (c >= ' | ||
| - | return 0; | ||
| - | } | ||
| - | |||
| - | // number | ||
| - | if (is_digit(**p)) { | ||
| - | return parse_int(p); | ||
| - | } | ||
| - | |||
| - | basic_error(" | ||
| - | return 0; | ||
| - | } | ||
| - | |||
| - | static int parse_term(const char **p) { | ||
| - | int v = parse_factor(p); | ||
| - | for (;;) { | ||
| - | skip_spaces(p); | ||
| - | if (**p == ' | ||
| - | else if (**p == '/' | ||
| - | (*p)++; | ||
| - | int d = parse_factor(p); | ||
| - | if (d == 0) { basic_error(" | ||
| - | 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 == ' | ||
| - | else if (**p == ' | ||
| - | else break; | ||
| - | } | ||
| - | return v; | ||
| - | } | ||
| - | |||
| - | static int parse_relop(const char **p, const char **out_op) { | ||
| - | skip_spaces(p); | ||
| - | // supported: =, <, >, <=, >=, <> | ||
| - | if (**p == ' | ||
| - | if (**p == '<' | ||
| - | (*p)++; | ||
| - | if (**p == ' | ||
| - | if (**p == '>' | ||
| - | *out_op = "<"; | ||
| - | } | ||
| - | if (**p == '>' | ||
| - | (*p)++; | ||
| - | if (**p == ' | ||
| - | *out_op = ">"; | ||
| - | } | ||
| - | return 0; | ||
| - | } | ||
| - | |||
| - | static int eval_relation(int a, int b, const char *op) { | ||
| - | if (op[0] == ' | ||
| - | if (op[0] == '<' | ||
| - | if (op[0] == '>' | ||
| - | if (op[0] == '<' | ||
| - | if (op[0] == '>' | ||
| - | if (op[0] == '<' | ||
| - | 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(& | ||
| - | |||
| - | if (*p == 0) return 1; | ||
| - | |||
| - | // REM | ||
| - | if (starts_with_kw(p, | ||
| - | |||
| - | // END | ||
| - | if (starts_with_kw(p, | ||
| - | |||
| - | |||
| - | if (starts_with_kw(p, | ||
| - | p += 5; | ||
| - | skip_spaces(& | ||
| - | |||
| - | // PRINT " | ||
| - | if (*p == '"' | ||
| - | p++; | ||
| - | print_new_line(); | ||
| - | while (*p && *p != '"' | ||
| - | print_char(*p++); | ||
| - | } | ||
| - | if (*p == '"' | ||
| - | return 1; | ||
| - | } | ||
| - | |||
| - | // PRINT expr | ||
| - | int v = parse_expr(& | ||
| - | print_new_line(); | ||
| - | print_int(v); | ||
| - | return 1; | ||
| - | } | ||
| - | |||
| - | // LET (optional) | ||
| - | if (starts_with_kw(p, | ||
| - | p += 3; | ||
| - | skip_spaces(& | ||
| - | } | ||
| - | |||
| - | // IF expr rel expr THEN line | ||
| - | if (starts_with_kw(p, | ||
| - | p += 2; | ||
| - | int left = parse_expr(& | ||
| - | |||
| - | const char *op = 0; | ||
| - | if (!parse_relop(& | ||
| - | |||
| - | int right = parse_expr(& | ||
| - | |||
| - | skip_spaces(& | ||
| - | if (!starts_with_kw(p, | ||
| - | p += 4; | ||
| - | |||
| - | uint16 target = parse_u16(& | ||
| - | if (target == 0) { basic_error(" | ||
| - | |||
| - | if (eval_relation(left, | ||
| - | *pc_line = (uint16)(target - 1); // Trick: RUN loop nimmt "next > pc_line" | ||
| - | } | ||
| - | return 1; | ||
| - | } | ||
| - | |||
| - | // GOTO line | ||
| - | if (starts_with_kw(p, | ||
| - | p += 4; | ||
| - | uint16 target = parse_u16(& | ||
| - | if (target == 0) { basic_error(" | ||
| - | *pc_line = (uint16)(target - 1); | ||
| - | return 1; | ||
| - | } | ||
| - | |||
| - | // Assignment: A = expr | ||
| - | if (is_alpha(*p)) { | ||
| - | char vname = up(*p++); | ||
| - | if (vname < ' | ||
| - | skip_spaces(& | ||
| - | if (*p != ' | ||
| - | p++; | ||
| - | int value = parse_expr(& | ||
| - | g_vars[vname - ' | ||
| - | return 1; | ||
| - | } | ||
| - | |||
| - | basic_error(" | ||
| - | return 0; | ||
| - | } | ||
| - | |||
| - | static void basic_run(void) { | ||
| - | uint16 pc = 0; // last executed line_no (for sorted iteration) | ||
| - | int stop = 0; | ||
| - | |||
| - | // Start at " | ||
| - | pc = 0; | ||
| - | |||
| - | while (!stop) { | ||
| - | uint16 ln; | ||
| - | int idx; | ||
| - | if (!find_next_line_sorted(pc, | ||
| - | |||
| - | // execute | ||
| - | uint16 pc_before = ln; | ||
| - | uint16 pc_line = ln; | ||
| - | basic_exec_stmt(g_prog[idx].text, | ||
| - | |||
| - | // 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(& | ||
| - | if (*p == 0) return; | ||
| - | |||
| - | // line starts with number? -> program line | ||
| - | if (is_digit(*p)) { | ||
| - | uint16 ln = parse_u16(& | ||
| - | basic_store_line(ln, | ||
| - | return; | ||
| - | } | ||
| - | |||
| - | // Immediate commands | ||
| - | if (starts_with_kw(p, | ||
| - | if (starts_with_kw(p, | ||
| - | if (starts_with_kw(p, | ||
| - | |||
| - | // keep your old shell commands too: | ||
| - | if (starts_with_kw(p, | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | print_new_line(); | ||
| - | print_string(" | ||
| - | return; | ||
| - | } | ||
| - | |||
| - | if (starts_with_kw(p, | ||
| - | |||
| - | // Otherwise: treat as immediate BASIC statement (PRINT/ | ||
| - | uint16 dummy = 0; | ||
| - | int stop = 0; | ||
| - | basic_exec_stmt(p, | ||
| - | } | ||
| - | </ | ||
| Hallo Besucher! Willkommen in diesem kleinen Wiki rund um IT. Vieles ist noch **unvollständig, | Hallo Besucher! Willkommen in diesem kleinen Wiki rund um IT. Vieles ist noch **unvollständig, | ||