Added pico support
This commit is contained in:
parent
642c277388
commit
2ac3c1ac26
|
|
@ -303,8 +303,20 @@ def generate_pico_toolchain():
|
|||
def generate_pico_cmake(project_name="sls"):
|
||||
"""Generate CMakeLists.txt for RP2040 build"""
|
||||
sources = list(SRC_DIR.glob("*.c"))
|
||||
# Exclude test runner if present
|
||||
sources = [s for s in sources if "test" not in s.stem.lower()]
|
||||
# Exclude main.c, repl.c, file.c and test files for Pico build
|
||||
# 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)
|
||||
|
||||
|
|
@ -320,6 +332,7 @@ def generate_pico_cmake(project_name="sls"):
|
|||
f.write(cmake_content)
|
||||
|
||||
print(f"Generated {cmake_file}")
|
||||
return True
|
||||
|
||||
|
||||
def build_rp2040():
|
||||
|
|
@ -333,7 +346,8 @@ def build_rp2040():
|
|||
generate_pico_toolchain()
|
||||
|
||||
# Generate CMakeLists.txt
|
||||
generate_pico_cmake()
|
||||
if not generate_pico_cmake():
|
||||
return False
|
||||
|
||||
# Create build directory
|
||||
mkdir(PICO_BUILD_DIR)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,23 @@
|
|||
#include "sls/bool.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);
|
||||
|
||||
#endif // SLS_BUILTIN_FUNCTIONS_H
|
||||
|
|
|
|||
|
|
@ -11,6 +11,20 @@
|
|||
#include "sls/bool.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;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
|
|
@ -687,7 +687,7 @@ Boolean load_builtins(InterpreterState *interpreter_state) {
|
|||
clean_stack(node); \
|
||||
\
|
||||
return push_token(interpreter_state, (Token){ \
|
||||
.type = TOKEN_DOUBLE, \
|
||||
.type = SLS_FLOAT_BUILTIN_DEFAULT, \
|
||||
.double_literal = func(af), \
|
||||
}); \
|
||||
|
||||
|
|
@ -897,7 +897,7 @@ Boolean builtin_division(InterpreterState *interpreter_state) {
|
|||
clean_stack(node);
|
||||
|
||||
return push_token(interpreter_state, (Token){
|
||||
.type = TOKEN_DOUBLE,
|
||||
.type = SLS_FLOAT_BUILTIN_DEFAULT,
|
||||
.double_literal = bf / af,
|
||||
});
|
||||
}
|
||||
|
|
@ -997,7 +997,7 @@ Boolean builtin_exponential(InterpreterState *interpreter_state) {
|
|||
clean_stack(node);
|
||||
|
||||
return push_token(interpreter_state, (Token){
|
||||
.type = TOKEN_DOUBLE,
|
||||
.type = SLS_FLOAT_BUILTIN_DEFAULT,
|
||||
.double_literal = pow(bf, af),
|
||||
});
|
||||
}
|
||||
|
|
@ -1210,7 +1210,7 @@ Boolean builtin_atan2(InterpreterState *interpreter_state) {
|
|||
clean_stack(node);
|
||||
|
||||
return push_token(interpreter_state, (Token){
|
||||
.type = TOKEN_DOUBLE,
|
||||
.type = SLS_FLOAT_BUILTIN_DEFAULT,
|
||||
.double_literal = atan2(bf, af),
|
||||
});
|
||||
}
|
||||
|
|
@ -1573,7 +1573,7 @@ Boolean builtin_depth(InterpreterState *interpreter_state) {
|
|||
return push_token(interpreter_state, (Token){
|
||||
.type = TOKEN_INTEGER,
|
||||
.integer_literal = (IntegerLiteral){
|
||||
.type = INTEGER_U64,
|
||||
.type = SLS_UNSIGNED_INTEGER_BUILTIN_DEFAULT,
|
||||
.value = (uint64_t)depth,
|
||||
},
|
||||
});
|
||||
|
|
@ -1695,7 +1695,7 @@ Boolean builtin_for(InterpreterState *interpreter_state) {
|
|||
return_value = push_token(interpreter_state, (Token){
|
||||
.type = TOKEN_INTEGER,
|
||||
.integer_literal = (IntegerLiteral){
|
||||
.type = INTEGER_I64,
|
||||
.type = SLS_INTEGER_BUILTIN_DEFAULT,
|
||||
.value = (uint64_t)i,
|
||||
},
|
||||
});
|
||||
|
|
@ -1893,7 +1893,7 @@ Boolean builtin_pick(InterpreterState *interpreter_state) {
|
|||
|
||||
Boolean builtin_rand(InterpreterState *interpreter_state) {
|
||||
return push_token(interpreter_state, (Token){
|
||||
.type = TOKEN_DOUBLE,
|
||||
.type = SLS_FLOAT_BUILTIN_DEFAULT,
|
||||
.double_literal = rand() / RAND_MAX,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (isspace(c) || c == '/' || c == '\0') {
|
||||
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);
|
||||
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 (isspace(c) || c == '/' || c == '\0') {
|
||||
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);
|
||||
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 == ':') return parse_numeric_type(lexer_info, c, start, start_line, NUMERIC_FLOAT);
|
||||
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);
|
||||
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);
|
||||
|
|
@ -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 (isspace(c) || c == '/' || c == '\0') {
|
||||
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);
|
||||
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 (isspace(c) || c == '/' || c == '\0') {
|
||||
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);
|
||||
if (error_msg.str == NULL) return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Out Of Memory Error."), 1}};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
Loading…
Reference in New Issue