Added pico support

This commit is contained in:
Kyler Olsen 2025-12-04 01:09:30 -07:00
parent 642c277388
commit 2ac3c1ac26
6 changed files with 280 additions and 30 deletions

View File

@ -303,8 +303,20 @@ def generate_pico_toolchain():
def generate_pico_cmake(project_name="sls"): def generate_pico_cmake(project_name="sls"):
"""Generate CMakeLists.txt for RP2040 build""" """Generate CMakeLists.txt for RP2040 build"""
sources = list(SRC_DIR.glob("*.c")) sources = list(SRC_DIR.glob("*.c"))
# Exclude test runner if present # Exclude main.c, repl.c, file.c and test files for Pico build
sources = [s for s in sources if "test" not in s.stem.lower()] # pico_main.c will provide its own REPL implementation
sources = [s for s in sources
if s.name not in ["main.c", "repl.c", "file.c"]
and "test" not in s.stem.lower()]
# Check for pico_main.c
pico_main = SRC_DIR / "pico_main.c"
if not pico_main.exists():
print(f"WARNING: {pico_main} not found! Please create it.")
print("The Pico build requires a pico_main.c file.")
return False
sources.append(pico_main)
source_files = "\n".join(f" {s}" for s in sources) source_files = "\n".join(f" {s}" for s in sources)
@ -320,6 +332,7 @@ def generate_pico_cmake(project_name="sls"):
f.write(cmake_content) f.write(cmake_content)
print(f"Generated {cmake_file}") print(f"Generated {cmake_file}")
return True
def build_rp2040(): def build_rp2040():
@ -333,7 +346,8 @@ def build_rp2040():
generate_pico_toolchain() generate_pico_toolchain()
# Generate CMakeLists.txt # Generate CMakeLists.txt
generate_pico_cmake() if not generate_pico_cmake():
return False
# Create build directory # Create build directory
mkdir(PICO_BUILD_DIR) mkdir(PICO_BUILD_DIR)

View File

@ -9,6 +9,23 @@
#include "sls/bool.h" #include "sls/bool.h"
#include "sls/interpreter.h" #include "sls/interpreter.h"
#if __SIZEOF_POINTER__ == 4
// 32-bit system
#define SLS_INTEGER_BUILTIN_DEFAULT INTEGER_I32
#define SLS_UNSIGNED_INTEGER_BUILTIN_DEFAULT INTEGER_U32
#define SLS_FLOAT_BUILTIN_DEFAULT TOKEN_FLOAT
#elif __SIZEOF_POINTER__ == 8
// 64-bit system
#define SLS_INTEGER_BUILTIN_DEFAULT INTEGER_I64
#define SLS_UNSIGNED_INTEGER_BUILTIN_DEFAULT INTEGER_U64
#define SLS_FLOAT_BUILTIN_DEFAULT TOKEN_DOUBLE
#else
// Fallback
#define SLS_INTEGER_BUILTIN_DEFAULT INTEGER_I16
#define SLS_UNSIGNED_INTEGER_BUILTIN_DEFAULT INTEGER_U16
#define SLS_FLOAT_BUILTIN_DEFAULT TOKEN_FLOAT
#endif
Boolean load_builtins(InterpreterState *interpreter_state); Boolean load_builtins(InterpreterState *interpreter_state);
#endif // SLS_BUILTIN_FUNCTIONS_H #endif // SLS_BUILTIN_FUNCTIONS_H

View File

@ -11,6 +11,20 @@
#include "sls/bool.h" #include "sls/bool.h"
#include "sls/errors.h" #include "sls/errors.h"
#if __SIZEOF_POINTER__ == 4
// 32-bit system
#define SLS_INTEGER_TYPE_DEFAULT INTEGER_I32
#define SLS_FLOAT_TYPE_DEFAULT NUMERIC_F32
#elif __SIZEOF_POINTER__ == 8
// 64-bit system
#define SLS_INTEGER_TYPE_DEFAULT INTEGER_I64
#define SLS_FLOAT_TYPE_DEFAULT NUMERIC_F64
#else
// Fallback
#define SLS_INTEGER_TYPE_DEFAULT INTEGER_I16
#define SLS_FLOAT_TYPE_DEFAULT NUMERIC_F32
#endif
extern const size_t TYPE_NAMES_SAFE_LENGTH; extern const size_t TYPE_NAMES_SAFE_LENGTH;
typedef struct { typedef struct {

View File

@ -687,7 +687,7 @@ Boolean load_builtins(InterpreterState *interpreter_state) {
clean_stack(node); \ clean_stack(node); \
\ \
return push_token(interpreter_state, (Token){ \ return push_token(interpreter_state, (Token){ \
.type = TOKEN_DOUBLE, \ .type = SLS_FLOAT_BUILTIN_DEFAULT, \
.double_literal = func(af), \ .double_literal = func(af), \
}); \ }); \
@ -897,7 +897,7 @@ Boolean builtin_division(InterpreterState *interpreter_state) {
clean_stack(node); clean_stack(node);
return push_token(interpreter_state, (Token){ return push_token(interpreter_state, (Token){
.type = TOKEN_DOUBLE, .type = SLS_FLOAT_BUILTIN_DEFAULT,
.double_literal = bf / af, .double_literal = bf / af,
}); });
} }
@ -997,7 +997,7 @@ Boolean builtin_exponential(InterpreterState *interpreter_state) {
clean_stack(node); clean_stack(node);
return push_token(interpreter_state, (Token){ return push_token(interpreter_state, (Token){
.type = TOKEN_DOUBLE, .type = SLS_FLOAT_BUILTIN_DEFAULT,
.double_literal = pow(bf, af), .double_literal = pow(bf, af),
}); });
} }
@ -1210,7 +1210,7 @@ Boolean builtin_atan2(InterpreterState *interpreter_state) {
clean_stack(node); clean_stack(node);
return push_token(interpreter_state, (Token){ return push_token(interpreter_state, (Token){
.type = TOKEN_DOUBLE, .type = SLS_FLOAT_BUILTIN_DEFAULT,
.double_literal = atan2(bf, af), .double_literal = atan2(bf, af),
}); });
} }
@ -1573,7 +1573,7 @@ Boolean builtin_depth(InterpreterState *interpreter_state) {
return push_token(interpreter_state, (Token){ return push_token(interpreter_state, (Token){
.type = TOKEN_INTEGER, .type = TOKEN_INTEGER,
.integer_literal = (IntegerLiteral){ .integer_literal = (IntegerLiteral){
.type = INTEGER_U64, .type = SLS_UNSIGNED_INTEGER_BUILTIN_DEFAULT,
.value = (uint64_t)depth, .value = (uint64_t)depth,
}, },
}); });
@ -1695,7 +1695,7 @@ Boolean builtin_for(InterpreterState *interpreter_state) {
return_value = push_token(interpreter_state, (Token){ return_value = push_token(interpreter_state, (Token){
.type = TOKEN_INTEGER, .type = TOKEN_INTEGER,
.integer_literal = (IntegerLiteral){ .integer_literal = (IntegerLiteral){
.type = INTEGER_I64, .type = SLS_INTEGER_BUILTIN_DEFAULT,
.value = (uint64_t)i, .value = (uint64_t)i,
}, },
}); });
@ -1893,7 +1893,7 @@ Boolean builtin_pick(InterpreterState *interpreter_state) {
Boolean builtin_rand(InterpreterState *interpreter_state) { Boolean builtin_rand(InterpreterState *interpreter_state) {
return push_token(interpreter_state, (Token){ return push_token(interpreter_state, (Token){
.type = TOKEN_DOUBLE, .type = SLS_FLOAT_BUILTIN_DEFAULT,
.double_literal = rand() / RAND_MAX, .double_literal = rand() / RAND_MAX,
}); });
} }

View File

@ -521,7 +521,7 @@ static LexerResult parse_binary_integer(LexerInfo *lexer_info, char c, size_t st
if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_BINARY); if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_BINARY);
if (isspace(c) || c == '/' || c == '\0') { if (isspace(c) || c == '/' || c == '\0') {
uint64_t value = create_binary_integer(lexer_info, start); uint64_t value = create_binary_integer(lexer_info, start);
return create_integer_token(lexer_info, INTEGER_I64, value, start, start_line); return create_integer_token(lexer_info, SLS_INTEGER_TYPE_DEFAULT, value, start, start_line);
} }
SlsStr error_msg = sls_format(SLS_STR("Invalid binary literal: unexpected '%c' in binary integer."), c); SlsStr error_msg = sls_format(SLS_STR("Invalid binary literal: unexpected '%c' in binary integer."), c);
if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}}; if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}};
@ -533,7 +533,7 @@ static LexerResult parse_octal_integer(LexerInfo *lexer_info, char c, size_t sta
if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_OCTAL); if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_OCTAL);
if (isspace(c) || c == '/' || c == '\0') { if (isspace(c) || c == '/' || c == '\0') {
uint64_t value = create_octal_integer(lexer_info, start); uint64_t value = create_octal_integer(lexer_info, start);
return create_integer_token(lexer_info, INTEGER_I64, value, start, start_line); return create_integer_token(lexer_info, SLS_INTEGER_TYPE_DEFAULT, value, start, start_line);
} }
SlsStr error_msg = sls_format(SLS_STR("Invalid octal literal: unexpected '%c' in octal integer."), c); SlsStr error_msg = sls_format(SLS_STR("Invalid octal literal: unexpected '%c' in octal integer."), c);
if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}}; if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}};
@ -550,7 +550,7 @@ static LexerResult parse_float(LexerInfo *lexer_info, char c, size_t start, size
if (c == 'e' || c == 'E') return parse_exponential(lexer_info, c, start, start_line); if (c == 'e' || c == 'E') return parse_exponential(lexer_info, c, start, start_line);
if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_FLOAT); if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_FLOAT);
if (isspace(c) || c == '/' || c == '\0') if (isspace(c) || c == '/' || c == '\0')
return create_float_token(lexer_info, NUMERIC_F64, start, start_line); return create_float_token(lexer_info, SLS_FLOAT_TYPE_DEFAULT, start, start_line);
SlsStr error_msg = sls_format(SLS_STR("Invalid float literal: unexpected '%c' in float."), c); SlsStr error_msg = sls_format(SLS_STR("Invalid float literal: unexpected '%c' in float."), c);
if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}}; if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}};
return lexer_error(lexer_info, error_msg, start, start_line); return lexer_error(lexer_info, error_msg, start, start_line);
@ -565,7 +565,7 @@ static LexerResult parse_decimal_integer(LexerInfo *lexer_info, char c, size_t s
if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_DECIMAL); if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_DECIMAL);
if (isspace(c) || c == '/' || c == '\0') { if (isspace(c) || c == '/' || c == '\0') {
uint64_t value = create_decimal_integer(lexer_info, start); uint64_t value = create_decimal_integer(lexer_info, start);
return create_integer_token(lexer_info, INTEGER_I64, value, start, start_line); return create_integer_token(lexer_info, SLS_INTEGER_TYPE_DEFAULT, value, start, start_line);
} }
SlsStr error_msg = sls_format(SLS_STR("Invalid decimal literal: unexpected '%c' in decimal integer."), c); SlsStr error_msg = sls_format(SLS_STR("Invalid decimal literal: unexpected '%c' in decimal integer."), c);
if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}}; if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}};
@ -577,7 +577,7 @@ static LexerResult parse_hexadecimal_integer(LexerInfo *lexer_info, char c, size
if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_HEXADECIMAL); if (c == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_HEXADECIMAL);
if (isspace(c) || c == '/' || c == '\0') { if (isspace(c) || c == '/' || c == '\0') {
uint64_t value = create_hexadecimal_integer(lexer_info, start); uint64_t value = create_hexadecimal_integer(lexer_info, start);
return create_integer_token(lexer_info, INTEGER_I64, value, start, start_line); return create_integer_token(lexer_info, SLS_INTEGER_TYPE_DEFAULT, value, start, start_line);
} }
SlsStr error_msg = sls_format(SLS_STR("Invalid hexadecimal literal: unexpected '%c' in hexadecimal integer."), c); SlsStr error_msg = sls_format(SLS_STR("Invalid hexadecimal literal: unexpected '%c' in hexadecimal integer."), c);
if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}}; if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}};

205
SLS_C/src/pico_main.c Normal file
View File

@ -0,0 +1,205 @@
// 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: %ld:i64\n", interpreter_state->stack->i64);
break;
case STACK_I32:
printf("#0: %d\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: %lu:u64\n", interpreter_state->stack->u64);
break;
case STACK_U32:
printf("#0: %u: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();
}