diff --git a/SLS_C/build.py b/SLS_C/build.py index 39d3472..24d8c67 100644 --- a/SLS_C/build.py +++ b/SLS_C/build.py @@ -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) diff --git a/SLS_C/include/sls/builtin.h b/SLS_C/include/sls/builtin.h index 04ac9e8..df7d8f6 100644 --- a/SLS_C/include/sls/builtin.h +++ b/SLS_C/include/sls/builtin.h @@ -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 diff --git a/SLS_C/include/sls/lexer.h b/SLS_C/include/sls/lexer.h index e5812b7..1dd94bc 100644 --- a/SLS_C/include/sls/lexer.h +++ b/SLS_C/include/sls/lexer.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 { diff --git a/SLS_C/src/builtin.c b/SLS_C/src/builtin.c index 21eb41a..8948430 100644 --- a/SLS_C/src/builtin.c +++ b/SLS_C/src/builtin.c @@ -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, }); } diff --git a/SLS_C/src/lexer.c b/SLS_C/src/lexer.c index fdf5999..4f9fe40 100644 --- a/SLS_C/src/lexer.c +++ b/SLS_C/src/lexer.c @@ -35,21 +35,21 @@ const char *TOKEN_TYPES_NAMES[] = { const size_t TOKEN_TYPE_COUNT = sizeof(TOKEN_TYPES_NAMES) / sizeof(*TOKEN_TYPES_NAMES); const char *ARRAY_TYPES_NAMES[] = { - "Identifier", - "i64", - "i32", - "i16", - "i8", - "u64", - "u32", - "u16", - "u8", - "Float", - "Double", - "Character", - "String", - "Boolean", - "Inline Struct", + "Identifier", + "i64", + "i32", + "i16", + "i8", + "u64", + "u32", + "u16", + "u8", + "Float", + "Double", + "Character", + "String", + "Boolean", + "Inline Struct", }; const size_t ARRAY_TYPE_COUNT = sizeof(ARRAY_TYPES_NAMES) / sizeof(*ARRAY_TYPES_NAMES); @@ -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}}; diff --git a/SLS_C/src/pico_main.c b/SLS_C/src/pico_main.c new file mode 100644 index 0000000..dcc85f5 --- /dev/null +++ b/SLS_C/src/pico_main.c @@ -0,0 +1,205 @@ +// Kyler Olsen +// YREA SLS +// Pico Main File +// December 2025 + +#include +#include +#include + +#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(""); + +void print_top_of_stack(InterpreterState *interpreter_state) { + if (interpreter_state->stack == NULL) { + printf("#0: \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: \n"); + break; + case STACK_CALLABLE: + printf("#0: \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(); +}