206 lines
5.6 KiB
C
206 lines
5.6 KiB
C
// Kyler Olsen
|
|
// YREA SLS
|
|
// Pico Main File
|
|
// December 2025
|
|
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include "pico/stdlib.h"
|
|
#include "pico/stdio_usb.h"
|
|
#include "hardware/uart.h"
|
|
#include "hardware/gpio.h"
|
|
|
|
#include "sls/meta.h"
|
|
#include "sls/bool.h"
|
|
#include "sls/string.h"
|
|
#include "sls/errors.h"
|
|
#include "sls/lexer.h"
|
|
#include "sls/interpreter.h"
|
|
|
|
// Pico onboard LED
|
|
#define LED_PIN 25
|
|
|
|
static const SlsStr PICO_REPL_NAME = SLS_STR_CONST("<PICO-REPL>");
|
|
|
|
void print_top_of_stack(InterpreterState *interpreter_state) {
|
|
if (interpreter_state->stack == NULL) {
|
|
printf("#0: <STACK IS EMPTY>\n");
|
|
return;
|
|
}
|
|
switch (interpreter_state->stack->type) {
|
|
case STACK_IDENTIFIER:
|
|
printf("#0: ::%s\n", interpreter_state->stack->identifier.name.str);
|
|
break;
|
|
case STACK_I64:
|
|
printf("#0: %lld:i64\n", interpreter_state->stack->i64);
|
|
break;
|
|
case STACK_I32:
|
|
printf("#0: %ld\n", interpreter_state->stack->i32);
|
|
break;
|
|
case STACK_I16:
|
|
printf("#0: %d:i16\n", interpreter_state->stack->i16);
|
|
break;
|
|
case STACK_I8:
|
|
printf("#0: %d:i8\n", interpreter_state->stack->i8);
|
|
break;
|
|
case STACK_U64:
|
|
printf("#0: %llu:u64\n", interpreter_state->stack->u64);
|
|
break;
|
|
case STACK_U32:
|
|
printf("#0: %lu:u32\n", interpreter_state->stack->u32);
|
|
break;
|
|
case STACK_U16:
|
|
printf("#0: %u:u16\n", interpreter_state->stack->u16);
|
|
break;
|
|
case STACK_U8:
|
|
printf("#0: %u:u8\n", interpreter_state->stack->u8);
|
|
break;
|
|
case STACK_FLOAT:
|
|
printf("#0: %f:f32\n", interpreter_state->stack->f32);
|
|
break;
|
|
case STACK_DOUBLE:
|
|
printf("#0: %f\n", interpreter_state->stack->f64);
|
|
break;
|
|
case STACK_CHARACTER:
|
|
printf("#0: %c\n", interpreter_state->stack->character);
|
|
break;
|
|
case STACK_BOOLEAN:
|
|
if (interpreter_state->stack->boolean) printf("#0: TRUE\n");
|
|
else printf("#0: FALSE\n");
|
|
break;
|
|
case STACK_TOKEN_STRING:
|
|
printf("#0: <TOKEN STRING>\n");
|
|
break;
|
|
case STACK_CALLABLE:
|
|
printf("#0: <CALLABLE>\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void led_blink(int count) {
|
|
for (int i = 0; i < count; i++) {
|
|
gpio_put(LED_PIN, 1);
|
|
sleep_ms(100);
|
|
gpio_put(LED_PIN, 0);
|
|
sleep_ms(100);
|
|
}
|
|
}
|
|
|
|
int pico_repl() {
|
|
// Initialize LED
|
|
gpio_init(LED_PIN);
|
|
gpio_set_dir(LED_PIN, GPIO_OUT);
|
|
|
|
// Blink to show we're ready
|
|
led_blink(3);
|
|
|
|
// Wait for a key press to start the repl
|
|
while (true) {
|
|
int c = getchar_timeout_us(100000);
|
|
if (c == PICO_ERROR_TIMEOUT) {
|
|
continue;
|
|
} else if (c == '\r' || c == '\n' || c == 8 || (c >= 32 && c < 128)) {
|
|
printf("\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
led_blink(1);
|
|
|
|
print_version();
|
|
printf("===== YREA SLS PICO REPL =====\n");
|
|
printf("Type `#exit` to exit.\n");
|
|
fflush(stdout);
|
|
|
|
LexerInfo lexer_info;
|
|
InterpreterState *interpreter_state = interpreter_create();
|
|
if (interpreter_state == NULL) {
|
|
printf("ERROR: Failed to create interpreter!\n");
|
|
return 1;
|
|
}
|
|
|
|
char buf[256];
|
|
int buf_pos = 0;
|
|
|
|
while (true) {
|
|
// Read character by character for better embedded behavior
|
|
int c = getchar_timeout_us(100000); // 100ms timeout
|
|
|
|
if (c == PICO_ERROR_TIMEOUT) {
|
|
continue;
|
|
}
|
|
|
|
if (c == '\r' || c == '\n') {
|
|
if (buf_pos == 0) continue; // Empty line
|
|
|
|
buf[buf_pos] = '\0';
|
|
printf("\n"); // Echo newline
|
|
|
|
if (strncmp(buf, "#exit", 5) == 0) {
|
|
printf("Exiting REPL...\n");
|
|
interpreter_delete(interpreter_state);
|
|
led_blink(2);
|
|
return 0;
|
|
}
|
|
|
|
SlsStr code = sls_str_malloc(buf, buf_pos);
|
|
init_lexer(&lexer_info, PICO_REPL_NAME, code);
|
|
LexerResult result = lexical_analysis(&lexer_info);
|
|
|
|
if (result.type == SLS_ERROR) {
|
|
printf("%s\n", result.error.message.str);
|
|
sls_str_free(&result.error.message);
|
|
} else {
|
|
LexerTokenResult *head = result.result;
|
|
while (head) {
|
|
if (head->type == SLS_ERROR) {
|
|
printf("%s\n", head->error.message.str);
|
|
break;
|
|
} else if (!execute(interpreter_state, head)) {
|
|
printf("A runtime error occurred!\n");
|
|
break;
|
|
}
|
|
head = head->next;
|
|
}
|
|
clean_token_result(result.result);
|
|
print_top_of_stack(interpreter_state);
|
|
}
|
|
sls_str_free(&code);
|
|
|
|
buf_pos = 0;
|
|
|
|
} else if (c == 127 || c == 8) {
|
|
// Backspace or DEL
|
|
if (buf_pos > 0) {
|
|
buf_pos--;
|
|
printf("\b \b"); // Erase character from terminal
|
|
fflush(stdout);
|
|
}
|
|
} else if (c >= 32 && c < 127 && buf_pos < 255) {
|
|
// Printable character
|
|
buf[buf_pos++] = (char)c;
|
|
putchar(c); // Echo character
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
interpreter_delete(interpreter_state);
|
|
return 1;
|
|
}
|
|
|
|
int main() {
|
|
// Initialize USB/UART stdio
|
|
stdio_init_all();
|
|
// Wait a bit for USB to enumerate
|
|
sleep_ms(5000);
|
|
|
|
printf("\n\n=============================\n");
|
|
printf("YREA SLS on Raspberry Pi Pico\n");
|
|
printf("=============================\n\n");
|
|
printf("Press any key to begin...\n");
|
|
|
|
return pico_repl();
|
|
}
|