├── LICENSE ├── Makefile ├── README.md ├── tests.c ├── tokenizer.c ├── tokenizer.h ├── ubasic.c ├── ubasic.h ├── use-ubasic.c └── vartype.h /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006, Adam Dunkels 2 | All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote 12 | products derived from this software without specific prior 13 | written permission. 14 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS 15 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | tests: tests.o ubasic.o tokenizer.o 2 | use-ubasic: use-ubasic.o ubasic.o tokenizer.o 3 | clean: 4 | rm *.o tests use-ubasic 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | uBASIC: a really simple BASIC interpreter 2 | ========================================= 3 | 4 | http://dunkels.com/adam/ubasic/ 5 | 6 | Written in a couple of hours, for the fun of it. Ended up being used in a bunch of places! 7 | 8 | The (non-interactive) uBASIC interpreter supports only the most basic BASIC functionality: if/then/else, for/next, let, goto, gosub, print, and mathematical expressions. There is only support for integer variables and the variables can only have single character names. I have added an API that allows for the program that uses the uBASIC interpreter to get and set BASIC variables, so it might be possible to actually use the uBASIC code for something useful (e.g. a small scripting language for an application that has to be really small). 9 | 10 | See the file `use-ubasic.c` for an example of how to use it. 11 | -------------------------------------------------------------------------------- /tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, Adam Dunkels 3 | * Copyright (c) 2013, Danyil Bohdan 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the author nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include "ubasic.h" 36 | 37 | static const char program_let[] = 38 | "10 let a = 42\n\ 39 | 20 end\n"; 40 | 41 | static const char program_goto[] = 42 | "10 goto 50\n\ 43 | 20 goto 40\n\ 44 | 30 goto 60\n\ 45 | 40 goto 30\n\ 46 | 50 goto 20\n\ 47 | 60 let c = 108\n\ 48 | 70 end\n"; 49 | 50 | static const char program_loop[] = 51 | "10 for i = 0 to 126\n\ 52 | 20 for j = 0 to 126\n\ 53 | 30 for k = 0 to 10\n\ 54 | 40 let a = i * j * k\n\ 55 | rem 45 print a, i, j, k\n\ 56 | 50 next k\n\ 57 | 60 next j\n\ 58 | 70 next i\n\ 59 | 80 end\n"; 60 | 61 | static const char program_fibs[] = 62 | "20 let a = 1\n\ 63 | 40 let b = 1\n\ 64 | 60 for i = 0 to 8\n\ 65 | 80 let b = a + b\n\ 66 | 100 let a = b - a\n\ 67 | rem 120 print a, b\n\ 68 | 140 next i\n\ 69 | 160 end\n"; 70 | 71 | static const char program_peek_poke[] = 72 | "10 peek 100 + 20 + 3, a\n\ 73 | 20 peek 123, z\n\ 74 | 30 poke 100 - 1, 99\n\ 75 | 40 poke 0, 0\n\ 76 | 50 end\n"; 77 | 78 | /*---------------------------------------------------------------------------*/ 79 | VARIABLE_TYPE peek(VARIABLE_TYPE arg) { 80 | return arg; 81 | } 82 | 83 | /*---------------------------------------------------------------------------*/ 84 | void poke(VARIABLE_TYPE arg, VARIABLE_TYPE value) { 85 | assert(arg == value); 86 | } 87 | 88 | /*---------------------------------------------------------------------------*/ 89 | void run(const char program[]) { 90 | static int test_num = 0; 91 | test_num++; 92 | printf("Running test #%u... ", test_num); 93 | fflush(stdout); 94 | 95 | clock_t start_t, end_t; 96 | double delta_t; 97 | 98 | start_t = clock(); 99 | 100 | ubasic_init_peek_poke(program, &peek, &poke); 101 | 102 | do { 103 | ubasic_run(); 104 | } while(!ubasic_finished()); 105 | 106 | end_t = clock(); 107 | delta_t = (double)(end_t - start_t) / CLOCKS_PER_SEC; 108 | 109 | printf("done. Run time: %.3f s\n", delta_t); 110 | } 111 | 112 | /*---------------------------------------------------------------------------*/ 113 | int 114 | main(void) 115 | { 116 | run(program_let); 117 | assert(ubasic_get_variable(0) == 42); 118 | 119 | run(program_goto); 120 | assert(ubasic_get_variable(2) == 108); 121 | 122 | run(program_loop); 123 | assert(ubasic_get_variable(0) == (VARIABLE_TYPE)(126 * 126 * 10)); 124 | 125 | run(program_fibs); 126 | assert(ubasic_get_variable(1) == 89); 127 | 128 | run(program_peek_poke); 129 | assert(ubasic_get_variable(0) == 123); 130 | assert(ubasic_get_variable(25) == 123); 131 | 132 | return 0; 133 | } 134 | /*---------------------------------------------------------------------------*/ 135 | -------------------------------------------------------------------------------- /tokenizer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, Adam Dunkels 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the author nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | #define DEBUG 0 32 | 33 | #if DEBUG 34 | #define DEBUG_PRINTF(...) printf(__VA_ARGS__) 35 | #else 36 | #define DEBUG_PRINTF(...) 37 | #endif 38 | 39 | #include "tokenizer.h" 40 | #include 41 | #include 42 | #include 43 | 44 | static char const *ptr, *nextptr; 45 | 46 | #define MAX_NUMLEN 6 47 | 48 | struct keyword_token { 49 | char *keyword; 50 | int token; 51 | }; 52 | 53 | static int current_token = TOKENIZER_ERROR; 54 | 55 | static const struct keyword_token keywords[] = { 56 | {"let", TOKENIZER_LET}, 57 | {"print", TOKENIZER_PRINT}, 58 | {"if", TOKENIZER_IF}, 59 | {"then", TOKENIZER_THEN}, 60 | {"else", TOKENIZER_ELSE}, 61 | {"for", TOKENIZER_FOR}, 62 | {"to", TOKENIZER_TO}, 63 | {"next", TOKENIZER_NEXT}, 64 | {"goto", TOKENIZER_GOTO}, 65 | {"gosub", TOKENIZER_GOSUB}, 66 | {"return", TOKENIZER_RETURN}, 67 | {"call", TOKENIZER_CALL}, 68 | {"rem", TOKENIZER_REM}, 69 | {"peek", TOKENIZER_PEEK}, 70 | {"poke", TOKENIZER_POKE}, 71 | {"end", TOKENIZER_END}, 72 | {NULL, TOKENIZER_ERROR} 73 | }; 74 | 75 | /*---------------------------------------------------------------------------*/ 76 | static int 77 | singlechar(void) 78 | { 79 | if(*ptr == '\n') { 80 | return TOKENIZER_CR; 81 | } else if(*ptr == ',') { 82 | return TOKENIZER_COMMA; 83 | } else if(*ptr == ';') { 84 | return TOKENIZER_SEMICOLON; 85 | } else if(*ptr == '+') { 86 | return TOKENIZER_PLUS; 87 | } else if(*ptr == '-') { 88 | return TOKENIZER_MINUS; 89 | } else if(*ptr == '&') { 90 | return TOKENIZER_AND; 91 | } else if(*ptr == '|') { 92 | return TOKENIZER_OR; 93 | } else if(*ptr == '*') { 94 | return TOKENIZER_ASTR; 95 | } else if(*ptr == '/') { 96 | return TOKENIZER_SLASH; 97 | } else if(*ptr == '%') { 98 | return TOKENIZER_MOD; 99 | } else if(*ptr == '(') { 100 | return TOKENIZER_LEFTPAREN; 101 | } else if(*ptr == '#') { 102 | return TOKENIZER_HASH; 103 | } else if(*ptr == ')') { 104 | return TOKENIZER_RIGHTPAREN; 105 | } else if(*ptr == '<') { 106 | return TOKENIZER_LT; 107 | } else if(*ptr == '>') { 108 | return TOKENIZER_GT; 109 | } else if(*ptr == '=') { 110 | return TOKENIZER_EQ; 111 | } 112 | return 0; 113 | } 114 | /*---------------------------------------------------------------------------*/ 115 | static int 116 | get_next_token(void) 117 | { 118 | struct keyword_token const *kt; 119 | int i; 120 | 121 | DEBUG_PRINTF("get_next_token(): '%s'\n", ptr); 122 | 123 | if(*ptr == 0) { 124 | return TOKENIZER_ENDOFINPUT; 125 | } 126 | 127 | if(isdigit(*ptr)) { 128 | for(i = 0; i < MAX_NUMLEN; ++i) { 129 | if(!isdigit(ptr[i])) { 130 | if(i > 0) { 131 | nextptr = ptr + i; 132 | return TOKENIZER_NUMBER; 133 | } else { 134 | DEBUG_PRINTF("get_next_token: error due to too short number\n"); 135 | return TOKENIZER_ERROR; 136 | } 137 | } 138 | if(!isdigit(ptr[i])) { 139 | DEBUG_PRINTF("get_next_token: error due to malformed number\n"); 140 | return TOKENIZER_ERROR; 141 | } 142 | } 143 | DEBUG_PRINTF("get_next_token: error due to too long number\n"); 144 | return TOKENIZER_ERROR; 145 | } else if(singlechar()) { 146 | nextptr = ptr + 1; 147 | return singlechar(); 148 | } else if(*ptr == '"') { 149 | nextptr = ptr; 150 | do { 151 | ++nextptr; 152 | } while(*nextptr != '"'); 153 | ++nextptr; 154 | return TOKENIZER_STRING; 155 | } else { 156 | for(kt = keywords; kt->keyword != NULL; ++kt) { 157 | if(strncmp(ptr, kt->keyword, strlen(kt->keyword)) == 0) { 158 | nextptr = ptr + strlen(kt->keyword); 159 | return kt->token; 160 | } 161 | } 162 | } 163 | 164 | if(*ptr >= 'a' && *ptr <= 'z') { 165 | nextptr = ptr + 1; 166 | return TOKENIZER_VARIABLE; 167 | } 168 | 169 | 170 | return TOKENIZER_ERROR; 171 | } 172 | /*---------------------------------------------------------------------------*/ 173 | void 174 | tokenizer_goto(const char *program) 175 | { 176 | ptr = program; 177 | current_token = get_next_token(); 178 | } 179 | /*---------------------------------------------------------------------------*/ 180 | void 181 | tokenizer_init(const char *program) 182 | { 183 | tokenizer_goto(program); 184 | current_token = get_next_token(); 185 | } 186 | /*---------------------------------------------------------------------------*/ 187 | int 188 | tokenizer_token(void) 189 | { 190 | return current_token; 191 | } 192 | /*---------------------------------------------------------------------------*/ 193 | void 194 | tokenizer_next(void) 195 | { 196 | 197 | if(tokenizer_finished()) { 198 | return; 199 | } 200 | 201 | DEBUG_PRINTF("tokenizer_next: %p\n", nextptr); 202 | ptr = nextptr; 203 | 204 | while(*ptr == ' ') { 205 | ++ptr; 206 | } 207 | current_token = get_next_token(); 208 | 209 | if(current_token == TOKENIZER_REM) { 210 | while(!(*nextptr == '\n' || tokenizer_finished())) { 211 | ++nextptr; 212 | } 213 | if(*nextptr == '\n') { 214 | ++nextptr; 215 | } 216 | tokenizer_next(); 217 | } 218 | 219 | DEBUG_PRINTF("tokenizer_next: '%s' %d\n", ptr, current_token); 220 | return; 221 | } 222 | /*---------------------------------------------------------------------------*/ 223 | VARIABLE_TYPE 224 | tokenizer_num(void) 225 | { 226 | return atoi(ptr); 227 | } 228 | /*---------------------------------------------------------------------------*/ 229 | void 230 | tokenizer_string(char *dest, int len) 231 | { 232 | char *string_end; 233 | int string_len; 234 | 235 | if(tokenizer_token() != TOKENIZER_STRING) { 236 | return; 237 | } 238 | string_end = strchr(ptr + 1, '"'); 239 | if(string_end == NULL) { 240 | return; 241 | } 242 | string_len = string_end - ptr - 1; 243 | if(len < string_len) { 244 | string_len = len; 245 | } 246 | memcpy(dest, ptr + 1, string_len); 247 | dest[string_len] = 0; 248 | } 249 | /*---------------------------------------------------------------------------*/ 250 | void 251 | tokenizer_error_print(void) 252 | { 253 | DEBUG_PRINTF("tokenizer_error_print: '%s'\n", ptr); 254 | } 255 | /*---------------------------------------------------------------------------*/ 256 | int 257 | tokenizer_finished(void) 258 | { 259 | return *ptr == 0 || current_token == TOKENIZER_ENDOFINPUT; 260 | } 261 | /*---------------------------------------------------------------------------*/ 262 | int 263 | tokenizer_variable_num(void) 264 | { 265 | return *ptr - 'a'; 266 | } 267 | /*---------------------------------------------------------------------------*/ 268 | char const * 269 | tokenizer_pos(void) 270 | { 271 | return ptr; 272 | } 273 | -------------------------------------------------------------------------------- /tokenizer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, Adam Dunkels 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the author nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | */ 30 | #ifndef __TOKENIZER_H__ 31 | #define __TOKENIZER_H__ 32 | 33 | #include "vartype.h" 34 | 35 | enum { 36 | TOKENIZER_ERROR, 37 | TOKENIZER_ENDOFINPUT, 38 | TOKENIZER_NUMBER, 39 | TOKENIZER_STRING, 40 | TOKENIZER_VARIABLE, 41 | TOKENIZER_LET, 42 | TOKENIZER_PRINT, 43 | TOKENIZER_IF, 44 | TOKENIZER_THEN, 45 | TOKENIZER_ELSE, 46 | TOKENIZER_FOR, 47 | TOKENIZER_TO, 48 | TOKENIZER_NEXT, 49 | TOKENIZER_GOTO, 50 | TOKENIZER_GOSUB, 51 | TOKENIZER_RETURN, 52 | TOKENIZER_CALL, 53 | TOKENIZER_REM, 54 | TOKENIZER_PEEK, 55 | TOKENIZER_POKE, 56 | TOKENIZER_END, 57 | TOKENIZER_COMMA, 58 | TOKENIZER_SEMICOLON, 59 | TOKENIZER_PLUS, 60 | TOKENIZER_MINUS, 61 | TOKENIZER_AND, 62 | TOKENIZER_OR, 63 | TOKENIZER_ASTR, 64 | TOKENIZER_SLASH, 65 | TOKENIZER_MOD, 66 | TOKENIZER_HASH, 67 | TOKENIZER_LEFTPAREN, 68 | TOKENIZER_RIGHTPAREN, 69 | TOKENIZER_LT, 70 | TOKENIZER_GT, 71 | TOKENIZER_EQ, 72 | TOKENIZER_CR, 73 | }; 74 | 75 | void tokenizer_goto(const char *program); 76 | void tokenizer_init(const char *program); 77 | void tokenizer_next(void); 78 | int tokenizer_token(void); 79 | VARIABLE_TYPE tokenizer_num(void); 80 | int tokenizer_variable_num(void); 81 | void tokenizer_string(char *dest, int len); 82 | 83 | int tokenizer_finished(void); 84 | void tokenizer_error_print(void); 85 | 86 | char const *tokenizer_pos(void); 87 | 88 | #endif /* __TOKENIZER_H__ */ 89 | -------------------------------------------------------------------------------- /ubasic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, Adam Dunkels 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the author nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | #define DEBUG 0 32 | 33 | #if DEBUG 34 | #define DEBUG_PRINTF(...) printf(__VA_ARGS__) 35 | #else 36 | #define DEBUG_PRINTF(...) 37 | #endif 38 | 39 | #include "ubasic.h" 40 | #include "tokenizer.h" 41 | 42 | #include /* printf() */ 43 | #include /* exit() */ 44 | 45 | static char const *program_ptr; 46 | #define MAX_STRINGLEN 40 47 | static char string[MAX_STRINGLEN]; 48 | 49 | #define MAX_GOSUB_STACK_DEPTH 10 50 | static int gosub_stack[MAX_GOSUB_STACK_DEPTH]; 51 | static int gosub_stack_ptr; 52 | 53 | struct for_state { 54 | int line_after_for; 55 | int for_variable; 56 | int to; 57 | }; 58 | #define MAX_FOR_STACK_DEPTH 4 59 | static struct for_state for_stack[MAX_FOR_STACK_DEPTH]; 60 | static int for_stack_ptr; 61 | 62 | struct line_index { 63 | int line_number; 64 | char const *program_text_position; 65 | struct line_index *next; 66 | }; 67 | struct line_index *line_index_head = NULL; 68 | struct line_index *line_index_current = NULL; 69 | 70 | #define MAX_VARNUM 26 71 | static VARIABLE_TYPE variables[MAX_VARNUM]; 72 | 73 | static int ended; 74 | 75 | static VARIABLE_TYPE expr(void); 76 | static void line_statement(void); 77 | static void statement(void); 78 | static void index_free(void); 79 | 80 | peek_func peek_function = NULL; 81 | poke_func poke_function = NULL; 82 | 83 | /*---------------------------------------------------------------------------*/ 84 | void 85 | ubasic_init(const char *program) 86 | { 87 | program_ptr = program; 88 | for_stack_ptr = gosub_stack_ptr = 0; 89 | index_free(); 90 | tokenizer_init(program); 91 | ended = 0; 92 | } 93 | /*---------------------------------------------------------------------------*/ 94 | void 95 | ubasic_init_peek_poke(const char *program, peek_func peek, poke_func poke) 96 | { 97 | program_ptr = program; 98 | for_stack_ptr = gosub_stack_ptr = 0; 99 | index_free(); 100 | peek_function = peek; 101 | poke_function = poke; 102 | tokenizer_init(program); 103 | ended = 0; 104 | } 105 | /*---------------------------------------------------------------------------*/ 106 | static void 107 | accept(int token) 108 | { 109 | if(token != tokenizer_token()) { 110 | DEBUG_PRINTF("Token not what was expected (expected %d, got %d)\n", 111 | token, tokenizer_token()); 112 | tokenizer_error_print(); 113 | exit(1); 114 | } 115 | DEBUG_PRINTF("Expected %d, got it\n", token); 116 | tokenizer_next(); 117 | } 118 | /*---------------------------------------------------------------------------*/ 119 | static int 120 | varfactor(void) 121 | { 122 | int r; 123 | DEBUG_PRINTF("varfactor: obtaining %d from variable %d\n", variables[tokenizer_variable_num()], tokenizer_variable_num()); 124 | r = ubasic_get_variable(tokenizer_variable_num()); 125 | accept(TOKENIZER_VARIABLE); 126 | return r; 127 | } 128 | /*---------------------------------------------------------------------------*/ 129 | static int 130 | factor(void) 131 | { 132 | int r; 133 | 134 | DEBUG_PRINTF("factor: token %d\n", tokenizer_token()); 135 | switch(tokenizer_token()) { 136 | case TOKENIZER_NUMBER: 137 | r = tokenizer_num(); 138 | DEBUG_PRINTF("factor: number %d\n", r); 139 | accept(TOKENIZER_NUMBER); 140 | break; 141 | case TOKENIZER_LEFTPAREN: 142 | accept(TOKENIZER_LEFTPAREN); 143 | r = expr(); 144 | accept(TOKENIZER_RIGHTPAREN); 145 | break; 146 | default: 147 | r = varfactor(); 148 | break; 149 | } 150 | return r; 151 | } 152 | /*---------------------------------------------------------------------------*/ 153 | static int 154 | term(void) 155 | { 156 | int f1, f2; 157 | int op; 158 | 159 | f1 = factor(); 160 | op = tokenizer_token(); 161 | DEBUG_PRINTF("term: token %d\n", op); 162 | while(op == TOKENIZER_ASTR || 163 | op == TOKENIZER_SLASH || 164 | op == TOKENIZER_MOD) { 165 | tokenizer_next(); 166 | f2 = factor(); 167 | DEBUG_PRINTF("term: %d %d %d\n", f1, op, f2); 168 | switch(op) { 169 | case TOKENIZER_ASTR: 170 | f1 = f1 * f2; 171 | break; 172 | case TOKENIZER_SLASH: 173 | f1 = f1 / f2; 174 | break; 175 | case TOKENIZER_MOD: 176 | f1 = f1 % f2; 177 | break; 178 | } 179 | op = tokenizer_token(); 180 | } 181 | DEBUG_PRINTF("term: %d\n", f1); 182 | return f1; 183 | } 184 | /*---------------------------------------------------------------------------*/ 185 | static VARIABLE_TYPE 186 | expr(void) 187 | { 188 | int t1, t2; 189 | int op; 190 | 191 | t1 = term(); 192 | op = tokenizer_token(); 193 | DEBUG_PRINTF("expr: token %d\n", op); 194 | while(op == TOKENIZER_PLUS || 195 | op == TOKENIZER_MINUS || 196 | op == TOKENIZER_AND || 197 | op == TOKENIZER_OR) { 198 | tokenizer_next(); 199 | t2 = term(); 200 | DEBUG_PRINTF("expr: %d %d %d\n", t1, op, t2); 201 | switch(op) { 202 | case TOKENIZER_PLUS: 203 | t1 = t1 + t2; 204 | break; 205 | case TOKENIZER_MINUS: 206 | t1 = t1 - t2; 207 | break; 208 | case TOKENIZER_AND: 209 | t1 = t1 & t2; 210 | break; 211 | case TOKENIZER_OR: 212 | t1 = t1 | t2; 213 | break; 214 | } 215 | op = tokenizer_token(); 216 | } 217 | DEBUG_PRINTF("expr: %d\n", t1); 218 | return t1; 219 | } 220 | /*---------------------------------------------------------------------------*/ 221 | static int 222 | relation(void) 223 | { 224 | int r1, r2; 225 | int op; 226 | 227 | r1 = expr(); 228 | op = tokenizer_token(); 229 | DEBUG_PRINTF("relation: token %d\n", op); 230 | while(op == TOKENIZER_LT || 231 | op == TOKENIZER_GT || 232 | op == TOKENIZER_EQ) { 233 | tokenizer_next(); 234 | r2 = expr(); 235 | DEBUG_PRINTF("relation: %d %d %d\n", r1, op, r2); 236 | switch(op) { 237 | case TOKENIZER_LT: 238 | r1 = r1 < r2; 239 | break; 240 | case TOKENIZER_GT: 241 | r1 = r1 > r2; 242 | break; 243 | case TOKENIZER_EQ: 244 | r1 = r1 == r2; 245 | break; 246 | } 247 | op = tokenizer_token(); 248 | } 249 | return r1; 250 | } 251 | /*---------------------------------------------------------------------------*/ 252 | static void 253 | index_free(void) { 254 | if(line_index_head != NULL) { 255 | line_index_current = line_index_head; 256 | do { 257 | DEBUG_PRINTF("Freeing index for line %d.\n", line_index_current); 258 | line_index_head = line_index_current; 259 | line_index_current = line_index_current->next; 260 | free(line_index_head); 261 | } while (line_index_current != NULL); 262 | line_index_head = NULL; 263 | } 264 | } 265 | /*---------------------------------------------------------------------------*/ 266 | static char const* 267 | index_find(int linenum) { 268 | struct line_index *lidx; 269 | lidx = line_index_head; 270 | 271 | #if DEBUG 272 | int step = 0; 273 | #endif 274 | 275 | while(lidx != NULL && lidx->line_number != linenum) { 276 | lidx = lidx->next; 277 | 278 | #if DEBUG 279 | if(lidx != NULL) { 280 | DEBUG_PRINTF("index_find: Step %3d. Found index for line %d: %d.\n", 281 | step, lidx->line_number, 282 | lidx->program_text_position); 283 | } 284 | step++; 285 | #endif 286 | } 287 | if(lidx != NULL && lidx->line_number == linenum) { 288 | DEBUG_PRINTF("index_find: Returning index for line %d.\n", linenum); 289 | return lidx->program_text_position; 290 | } 291 | DEBUG_PRINTF("index_find: Returning NULL.\n", linenum); 292 | return NULL; 293 | } 294 | /*---------------------------------------------------------------------------*/ 295 | static void 296 | index_add(int linenum, char const* sourcepos) { 297 | if(line_index_head != NULL && index_find(linenum)) { 298 | return; 299 | } 300 | 301 | struct line_index *new_lidx; 302 | 303 | new_lidx = malloc(sizeof(struct line_index)); 304 | new_lidx->line_number = linenum; 305 | new_lidx->program_text_position = sourcepos; 306 | new_lidx->next = NULL; 307 | 308 | if(line_index_head != NULL) { 309 | line_index_current->next = new_lidx; 310 | line_index_current = line_index_current->next; 311 | } else { 312 | line_index_current = new_lidx; 313 | line_index_head = line_index_current; 314 | } 315 | DEBUG_PRINTF("index_add: Adding index for line %d: %d.\n", linenum, 316 | sourcepos); 317 | } 318 | /*---------------------------------------------------------------------------*/ 319 | static void 320 | jump_linenum_slow(int linenum) 321 | { 322 | tokenizer_init(program_ptr); 323 | while(tokenizer_num() != linenum) { 324 | do { 325 | do { 326 | tokenizer_next(); 327 | } while(tokenizer_token() != TOKENIZER_CR && 328 | tokenizer_token() != TOKENIZER_ENDOFINPUT); 329 | if(tokenizer_token() == TOKENIZER_CR) { 330 | tokenizer_next(); 331 | } 332 | } while(tokenizer_token() != TOKENIZER_NUMBER); 333 | DEBUG_PRINTF("jump_linenum_slow: Found line %d\n", tokenizer_num()); 334 | } 335 | } 336 | /*---------------------------------------------------------------------------*/ 337 | static void 338 | jump_linenum(int linenum) 339 | { 340 | char const* pos = index_find(linenum); 341 | if(pos != NULL) { 342 | DEBUG_PRINTF("jump_linenum: Going to line %d.\n", linenum); 343 | tokenizer_goto(pos); 344 | } else { 345 | /* We'll try to find a yet-unindexed line to jump to. */ 346 | DEBUG_PRINTF("jump_linenum: Calling jump_linenum_slow.\n", linenum); 347 | jump_linenum_slow(linenum); 348 | } 349 | } 350 | /*---------------------------------------------------------------------------*/ 351 | static void 352 | goto_statement(void) 353 | { 354 | accept(TOKENIZER_GOTO); 355 | jump_linenum(tokenizer_num()); 356 | } 357 | /*---------------------------------------------------------------------------*/ 358 | static void 359 | print_statement(void) 360 | { 361 | accept(TOKENIZER_PRINT); 362 | do { 363 | DEBUG_PRINTF("Print loop\n"); 364 | if(tokenizer_token() == TOKENIZER_STRING) { 365 | tokenizer_string(string, sizeof(string)); 366 | printf("%s", string); 367 | tokenizer_next(); 368 | } else if(tokenizer_token() == TOKENIZER_COMMA) { 369 | printf(" "); 370 | tokenizer_next(); 371 | } else if(tokenizer_token() == TOKENIZER_SEMICOLON) { 372 | tokenizer_next(); 373 | } else if(tokenizer_token() == TOKENIZER_VARIABLE || 374 | tokenizer_token() == TOKENIZER_NUMBER) { 375 | printf("%d", expr()); 376 | } else { 377 | break; 378 | } 379 | } while(tokenizer_token() != TOKENIZER_CR && 380 | tokenizer_token() != TOKENIZER_ENDOFINPUT); 381 | printf("\n"); 382 | DEBUG_PRINTF("End of print\n"); 383 | tokenizer_next(); 384 | } 385 | /*---------------------------------------------------------------------------*/ 386 | static void 387 | if_statement(void) 388 | { 389 | int r; 390 | 391 | accept(TOKENIZER_IF); 392 | 393 | r = relation(); 394 | DEBUG_PRINTF("if_statement: relation %d\n", r); 395 | accept(TOKENIZER_THEN); 396 | if(r) { 397 | statement(); 398 | } else { 399 | do { 400 | tokenizer_next(); 401 | } while(tokenizer_token() != TOKENIZER_ELSE && 402 | tokenizer_token() != TOKENIZER_CR && 403 | tokenizer_token() != TOKENIZER_ENDOFINPUT); 404 | if(tokenizer_token() == TOKENIZER_ELSE) { 405 | tokenizer_next(); 406 | statement(); 407 | } else if(tokenizer_token() == TOKENIZER_CR) { 408 | tokenizer_next(); 409 | } 410 | } 411 | } 412 | /*---------------------------------------------------------------------------*/ 413 | static void 414 | let_statement(void) 415 | { 416 | int var; 417 | 418 | var = tokenizer_variable_num(); 419 | 420 | accept(TOKENIZER_VARIABLE); 421 | accept(TOKENIZER_EQ); 422 | ubasic_set_variable(var, expr()); 423 | DEBUG_PRINTF("let_statement: assign %d to %d\n", variables[var], var); 424 | accept(TOKENIZER_CR); 425 | 426 | } 427 | /*---------------------------------------------------------------------------*/ 428 | static void 429 | gosub_statement(void) 430 | { 431 | int linenum; 432 | accept(TOKENIZER_GOSUB); 433 | linenum = tokenizer_num(); 434 | accept(TOKENIZER_NUMBER); 435 | accept(TOKENIZER_CR); 436 | if(gosub_stack_ptr < MAX_GOSUB_STACK_DEPTH) { 437 | gosub_stack[gosub_stack_ptr] = tokenizer_num(); 438 | gosub_stack_ptr++; 439 | jump_linenum(linenum); 440 | } else { 441 | DEBUG_PRINTF("gosub_statement: gosub stack exhausted\n"); 442 | } 443 | } 444 | /*---------------------------------------------------------------------------*/ 445 | static void 446 | return_statement(void) 447 | { 448 | accept(TOKENIZER_RETURN); 449 | if(gosub_stack_ptr > 0) { 450 | gosub_stack_ptr--; 451 | jump_linenum(gosub_stack[gosub_stack_ptr]); 452 | } else { 453 | DEBUG_PRINTF("return_statement: non-matching return\n"); 454 | } 455 | } 456 | /*---------------------------------------------------------------------------*/ 457 | static void 458 | next_statement(void) 459 | { 460 | int var; 461 | 462 | accept(TOKENIZER_NEXT); 463 | var = tokenizer_variable_num(); 464 | accept(TOKENIZER_VARIABLE); 465 | if(for_stack_ptr > 0 && 466 | var == for_stack[for_stack_ptr - 1].for_variable) { 467 | ubasic_set_variable(var, 468 | ubasic_get_variable(var) + 1); 469 | if(ubasic_get_variable(var) <= for_stack[for_stack_ptr - 1].to) { 470 | jump_linenum(for_stack[for_stack_ptr - 1].line_after_for); 471 | } else { 472 | for_stack_ptr--; 473 | accept(TOKENIZER_CR); 474 | } 475 | } else { 476 | DEBUG_PRINTF("next_statement: non-matching next (expected %d, found %d)\n", for_stack[for_stack_ptr - 1].for_variable, var); 477 | accept(TOKENIZER_CR); 478 | } 479 | 480 | } 481 | /*---------------------------------------------------------------------------*/ 482 | static void 483 | for_statement(void) 484 | { 485 | int for_variable, to; 486 | 487 | accept(TOKENIZER_FOR); 488 | for_variable = tokenizer_variable_num(); 489 | accept(TOKENIZER_VARIABLE); 490 | accept(TOKENIZER_EQ); 491 | ubasic_set_variable(for_variable, expr()); 492 | accept(TOKENIZER_TO); 493 | to = expr(); 494 | accept(TOKENIZER_CR); 495 | 496 | if(for_stack_ptr < MAX_FOR_STACK_DEPTH) { 497 | for_stack[for_stack_ptr].line_after_for = tokenizer_num(); 498 | for_stack[for_stack_ptr].for_variable = for_variable; 499 | for_stack[for_stack_ptr].to = to; 500 | DEBUG_PRINTF("for_statement: new for, var %d to %d\n", 501 | for_stack[for_stack_ptr].for_variable, 502 | for_stack[for_stack_ptr].to); 503 | 504 | for_stack_ptr++; 505 | } else { 506 | DEBUG_PRINTF("for_statement: for stack depth exceeded\n"); 507 | } 508 | } 509 | /*---------------------------------------------------------------------------*/ 510 | static void 511 | peek_statement(void) 512 | { 513 | VARIABLE_TYPE peek_addr; 514 | int var; 515 | 516 | accept(TOKENIZER_PEEK); 517 | peek_addr = expr(); 518 | accept(TOKENIZER_COMMA); 519 | var = tokenizer_variable_num(); 520 | accept(TOKENIZER_VARIABLE); 521 | accept(TOKENIZER_CR); 522 | 523 | ubasic_set_variable(var, peek_function(peek_addr)); 524 | } 525 | /*---------------------------------------------------------------------------*/ 526 | static void 527 | poke_statement(void) 528 | { 529 | VARIABLE_TYPE poke_addr; 530 | VARIABLE_TYPE value; 531 | 532 | accept(TOKENIZER_POKE); 533 | poke_addr = expr(); 534 | accept(TOKENIZER_COMMA); 535 | value = expr(); 536 | accept(TOKENIZER_CR); 537 | 538 | poke_function(poke_addr, value); 539 | } 540 | /*---------------------------------------------------------------------------*/ 541 | static void 542 | end_statement(void) 543 | { 544 | accept(TOKENIZER_END); 545 | ended = 1; 546 | } 547 | /*---------------------------------------------------------------------------*/ 548 | static void 549 | statement(void) 550 | { 551 | int token; 552 | 553 | token = tokenizer_token(); 554 | 555 | switch(token) { 556 | case TOKENIZER_PRINT: 557 | print_statement(); 558 | break; 559 | case TOKENIZER_IF: 560 | if_statement(); 561 | break; 562 | case TOKENIZER_GOTO: 563 | goto_statement(); 564 | break; 565 | case TOKENIZER_GOSUB: 566 | gosub_statement(); 567 | break; 568 | case TOKENIZER_RETURN: 569 | return_statement(); 570 | break; 571 | case TOKENIZER_FOR: 572 | for_statement(); 573 | break; 574 | case TOKENIZER_PEEK: 575 | peek_statement(); 576 | break; 577 | case TOKENIZER_POKE: 578 | poke_statement(); 579 | break; 580 | case TOKENIZER_NEXT: 581 | next_statement(); 582 | break; 583 | case TOKENIZER_END: 584 | end_statement(); 585 | break; 586 | case TOKENIZER_LET: 587 | accept(TOKENIZER_LET); 588 | /* Fall through. */ 589 | case TOKENIZER_VARIABLE: 590 | let_statement(); 591 | break; 592 | default: 593 | DEBUG_PRINTF("ubasic.c: statement(): not implemented %d\n", token); 594 | exit(1); 595 | } 596 | } 597 | /*---------------------------------------------------------------------------*/ 598 | static void 599 | line_statement(void) 600 | { 601 | DEBUG_PRINTF("----------- Line number %d ---------\n", tokenizer_num()); 602 | index_add(tokenizer_num(), tokenizer_pos()); 603 | accept(TOKENIZER_NUMBER); 604 | statement(); 605 | return; 606 | } 607 | /*---------------------------------------------------------------------------*/ 608 | void 609 | ubasic_run(void) 610 | { 611 | if(tokenizer_finished()) { 612 | DEBUG_PRINTF("uBASIC program finished\n"); 613 | return; 614 | } 615 | 616 | line_statement(); 617 | } 618 | /*---------------------------------------------------------------------------*/ 619 | int 620 | ubasic_finished(void) 621 | { 622 | return ended || tokenizer_finished(); 623 | } 624 | /*---------------------------------------------------------------------------*/ 625 | void 626 | ubasic_set_variable(int varnum, VARIABLE_TYPE value) 627 | { 628 | if(varnum >= 0 && varnum <= MAX_VARNUM) { 629 | variables[varnum] = value; 630 | } 631 | } 632 | /*---------------------------------------------------------------------------*/ 633 | VARIABLE_TYPE 634 | ubasic_get_variable(int varnum) 635 | { 636 | if(varnum >= 0 && varnum <= MAX_VARNUM) { 637 | return variables[varnum]; 638 | } 639 | return 0; 640 | } 641 | /*---------------------------------------------------------------------------*/ 642 | -------------------------------------------------------------------------------- /ubasic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, Adam Dunkels 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the author nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | */ 30 | #ifndef __UBASIC_H__ 31 | #define __UBASIC_H__ 32 | 33 | #include "vartype.h" 34 | 35 | typedef VARIABLE_TYPE (*peek_func)(VARIABLE_TYPE); 36 | typedef void (*poke_func)(VARIABLE_TYPE, VARIABLE_TYPE); 37 | 38 | void ubasic_init(const char *program); 39 | void ubasic_run(void); 40 | int ubasic_finished(void); 41 | 42 | VARIABLE_TYPE ubasic_get_variable(int varnum); 43 | void ubasic_set_variable(int varum, VARIABLE_TYPE value); 44 | 45 | #endif /* __UBASIC_H__ */ 46 | -------------------------------------------------------------------------------- /use-ubasic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, Adam Dunkels 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the author nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | #include "ubasic.h" 32 | 33 | static const char program[] = 34 | "10 gosub 100\n\ 35 | 20 for i = 1 to 10\n\ 36 | 30 print i\n\ 37 | 40 next i\n\ 38 | 50 print \"end\"\n\ 39 | 60 end\n\ 40 | 100 print \"subroutine\"\n\ 41 | 110 return\n"; 42 | 43 | /*---------------------------------------------------------------------------*/ 44 | int 45 | main(void) 46 | { 47 | ubasic_init(program); 48 | 49 | do { 50 | ubasic_run(); 51 | } while(!ubasic_finished()); 52 | 53 | return 0; 54 | } 55 | /*---------------------------------------------------------------------------*/ 56 | -------------------------------------------------------------------------------- /vartype.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, Adam Dunkels 3 | * Copyright (c) 2013, Danyil Bohdan 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the author nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | #ifndef __VARTYPE_H__ 32 | #define __VARTYPE_H__ 33 | 34 | #define VARIABLE_TYPE char 35 | 36 | #endif /* __VARTYPE_H__ */ 37 | --------------------------------------------------------------------------------