Tom Van den Bon
/
TinyBasicNucleo
A port of TinyBasic Plus (https://github.com/BleuLlama/TinyBasicPlus) to mbed (focus on Nucleo)
Revision 0:c52ead8719b3, committed 2015-01-21
- Comitter:
- tomvdb
- Date:
- Wed Jan 21 15:32:36 2015 +0000
- Commit message:
- initial commit
Changed in this revision
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
mbed.bld | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r c52ead8719b3 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Jan 21 15:32:36 2015 +0000 @@ -0,0 +1,1773 @@ +/* + +A C implementation of Tiny Basic, with a focus on support for mbed/nucleo. This has been ported from TinyBasic Plus (https://github.com/BleuLlama/TinyBasicPlus) + +Nucleo Port by Tom Van den Bon + +*/ + +#define kVersion "v0.1" + +/* + v0.1: 2015/01/21 + + Initial code from TinyBasic Plus ported to run on the Nucleo + + - filesystem, eeprom and sdcard not implemented yet +*/ + + + +#include "mbed.h" + +Serial pc(SERIAL_TX, SERIAL_RX); + +#ifndef pgm_read_byte +#define pgm_read_byte( A ) *(A) +#endif + +#ifndef boolean +#define boolean int +#define true 1 +#define false 0 +#endif + +boolean inhibitOutput = false; +static boolean runAfterLoad = false; +static boolean triggerRun = false; + +// these will select, at runtime, where IO happens through for load/save +enum { + kStreamSerial = 0, + kStreamEEProm, + kStreamFile +}; +static unsigned char inStream = kStreamSerial; +static unsigned char outStream = kStreamSerial; + +// ASCII Characters +#define CR '\r' +#define NL '\n' +#define LF 0x0a +#define TAB '\t' +#define BELL '\b' +#define SPACE ' ' +#define SQUOTE '\'' +#define DQUOTE '\"' +#define CTRLC 0x03 +#define CTRLH 0x08 +#define CTRLS 0x13 +#define CTRLX 0x18 + +// size of our program ram +#define kRamSize 4096 /* arbitrary */ + +typedef short unsigned LINENUM; + +static unsigned char program[kRamSize]; +static const char * sentinel = "HELLO"; +static unsigned char *txtpos,*list_line; +static unsigned char expression_error; +static unsigned char *tempsp; + +// Keyword table and constants - the last character has 0x80 added to it +static unsigned char keywords[] = { + 'L','I','S','T'+0x80, + 'L','O','A','D'+0x80, + 'N','E','W'+0x80, + 'R','U','N'+0x80, + 'S','A','V','E'+0x80, + 'N','E','X','T'+0x80, + 'L','E','T'+0x80, + 'I','F'+0x80, + 'G','O','T','O'+0x80, + 'G','O','S','U','B'+0x80, + 'R','E','T','U','R','N'+0x80, + 'R','E','M'+0x80, + 'F','O','R'+0x80, + 'I','N','P','U','T'+0x80, + 'P','R','I','N','T'+0x80, + 'P','O','K','E'+0x80, + 'S','T','O','P'+0x80, + 'B','Y','E'+0x80, + 'F','I','L','E','S'+0x80, + 'M','E','M'+0x80, + '?'+ 0x80, + '\''+ 0x80, + 'A','W','R','I','T','E'+0x80, + 'D','W','R','I','T','E'+0x80, + 'D','E','L','A','Y'+0x80, + 'E','N','D'+0x80, + 'R','S','E','E','D'+0x80, + 'C','H','A','I','N'+0x80, +#ifdef ENABLE_TONES + 'T','O','N','E','W'+0x80, + 'T','O','N','E'+0x80, + 'N','O','T','O','N','E'+0x80, +#endif +#ifdef ENABLE_EEPROM + 'E','C','H','A','I','N'+0x80, + 'E','L','I','S','T'+0x80, + 'E','L','O','A','D'+0x80, + 'E','F','O','R','M','A','T'+0x80, + 'E','S','A','V','E'+0x80, +#endif + 0 +}; + +// by moving the command list to an enum, we can easily remove sections +// above and below simultaneously to selectively obliterate functionality. +enum { + KW_LIST = 0, + KW_LOAD, KW_NEW, KW_RUN, KW_SAVE, + KW_NEXT, KW_LET, KW_IF, + KW_GOTO, KW_GOSUB, KW_RETURN, + KW_REM, + KW_FOR, + KW_INPUT, KW_PRINT, + KW_POKE, + KW_STOP, KW_BYE, + KW_FILES, + KW_MEM, + KW_QMARK, KW_QUOTE, + KW_AWRITE, KW_DWRITE, + KW_DELAY, + KW_END, + KW_RSEED, + KW_CHAIN, +#ifdef ENABLE_TONES + KW_TONEW, KW_TONE, KW_NOTONE, +#endif +#ifdef ENABLE_EEPROM + KW_ECHAIN, KW_ELIST, KW_ELOAD, KW_EFORMAT, KW_ESAVE, +#endif + KW_DEFAULT /* always the final one*/ +}; + +struct stack_for_frame { + char frame_type; + char for_var; + short int terminal; + short int step; + unsigned char *current_line; + unsigned char *txtpos; +}; + +struct stack_gosub_frame { + char frame_type; + unsigned char *current_line; + unsigned char *txtpos; +}; + +static unsigned char func_tab[] = { + 'P','E','E','K'+0x80, + 'A','B','S'+0x80, + 'A','R','E','A','D'+0x80, + 'D','R','E','A','D'+0x80, + 'R','N','D'+0x80, + 0 +}; +#define FUNC_PEEK 0 +#define FUNC_ABS 1 +#define FUNC_AREAD 2 +#define FUNC_DREAD 3 +#define FUNC_RND 4 +#define FUNC_UNKNOWN 5 + +static unsigned char to_tab[] = { + 'T','O'+0x80, + 0 +}; + +static unsigned char step_tab[] = { + 'S','T','E','P'+0x80, + 0 +}; + +static unsigned char relop_tab[] = { + '>','='+0x80, + '<','>'+0x80, + '>'+0x80, + '='+0x80, + '<','='+0x80, + '<'+0x80, + '!','='+0x80, + 0 +}; + +#define RELOP_GE 0 +#define RELOP_NE 1 +#define RELOP_GT 2 +#define RELOP_EQ 3 +#define RELOP_LE 4 +#define RELOP_LT 5 +#define RELOP_NE_BANG 6 +#define RELOP_UNKNOWN 7 + +static unsigned char highlow_tab[] = { + 'H','I','G','H'+0x80, + 'H','I'+0x80, + 'L','O','W'+0x80, + 'L','O'+0x80, + 0 +}; +#define HIGHLOW_HIGH 1 +#define HIGHLOW_UNKNOWN 4 + +#define STACK_SIZE (sizeof(struct stack_for_frame)*5) +#define VAR_SIZE sizeof(short int) // Size of variables in bytes + +static unsigned char *stack_limit; +static unsigned char *program_start; +static unsigned char *program_end; +static unsigned char *stack; // Software stack for things that should go on the CPU stack +static unsigned char *variables_begin; +static unsigned char *current_line; +static unsigned char *sp; +#define STACK_GOSUB_FLAG 'G' +#define STACK_FOR_FLAG 'F' +static unsigned char table_index; +static LINENUM linenum; + +static const unsigned char okmsg[] = "OK"; +static const unsigned char whatmsg[] = "What? "; +static const unsigned char howmsg[] = "How?"; +static const unsigned char sorrymsg[] = "Sorry!"; +static const unsigned char initmsg[] = "TinyBasic Nucleo"; +static const unsigned char memorymsg[] = " bytes free."; +#ifdef ENABLE_EEPROM +static const unsigned char eeprommsg[] = " EEProm bytes total."; +static const unsigned char eepromamsg[] = " EEProm bytes available."; +#endif +static const unsigned char breakmsg[] = "break!"; +static const unsigned char unimplimentedmsg[] = "Unimplemented"; +static const unsigned char backspacemsg[] = "\b \b"; +static const unsigned char indentmsg[] = " "; +static const unsigned char sderrormsg[] = "SD card error."; +static const unsigned char sdfilemsg[] = "SD file error."; +static const unsigned char dirextmsg[] = "(dir)"; +static const unsigned char slashmsg[] = "/"; +static const unsigned char spacemsg[] = " "; + +static int inchar(void); +static void outchar(unsigned char c); +static void line_terminator(void); +static short int expression(void); +static unsigned char breakcheck(void); + + + +/***************************************************************************/ +static void ignore_blanks(void) +{ + while(*txtpos == SPACE || *txtpos == TAB) + txtpos++; +} +/***************************************************************************/ +static void scantable(unsigned char *table) +{ + int i = 0; + table_index = 0; + while(1) + { + // Run out of table entries? + if(pgm_read_byte( table ) == 0) + return; + + // Do we match this character? + if(txtpos[i] == pgm_read_byte( table )) + { + i++; + table++; + } + else + { + // do we match the last character of keywork (with 0x80 added)? If so, return + if(txtpos[i]+0x80 == pgm_read_byte( table )) + { + txtpos += i+1; // Advance the pointer to following the keyword + ignore_blanks(); + return; + } + + // Forward to the end of this keyword + while((pgm_read_byte( table ) & 0x80) == 0) + table++; + + // Now move on to the first character of the next word, and reset the position index + table++; + table_index++; + ignore_blanks(); + i = 0; + } + } +} + +/***************************************************************************/ +static void pushb(unsigned char b) +{ + sp--; + *sp = b; +} + +/***************************************************************************/ +static unsigned char popb() +{ + unsigned char b; + b = *sp; + sp++; + return b; +} + +/***************************************************************************/ +void printnum(int num) +{ + int digits = 0; + + if(num < 0) + { + num = -num; + outchar('-'); + } + do { + pushb(num%10+'0'); + num = num/10; + digits++; + } + while (num > 0); + + while(digits > 0) + { + outchar(popb()); + digits--; + } +} + +void printUnum(unsigned int num) +{ + int digits = 0; + + do { + pushb(num%10+'0'); + num = num/10; + digits++; + } + while (num > 0); + + while(digits > 0) + { + outchar(popb()); + digits--; + } +} + +/***************************************************************************/ +static unsigned short testnum(void) +{ + unsigned short num = 0; + ignore_blanks(); + + while(*txtpos>= '0' && *txtpos <= '9' ) + { + // Trap overflows + if(num >= 0xFFFF/10) + { + num = 0xFFFF; + break; + } + + num = num *10 + *txtpos - '0'; + txtpos++; + } + return num; +} + +/***************************************************************************/ +static unsigned char print_quoted_string(void) +{ + int i=0; + unsigned char delim = *txtpos; + if(delim != '"' && delim != '\'') + return 0; + txtpos++; + + // Check we have a closing delimiter + while(txtpos[i] != delim) + { + if(txtpos[i] == NL) + return 0; + i++; + } + + // Print the characters + while(*txtpos != delim) + { + outchar(*txtpos); + txtpos++; + } + txtpos++; // Skip over the last delimiter + + return 1; +} + + +/***************************************************************************/ +void printmsgNoNL(const unsigned char *msg) +{ + while( pgm_read_byte( msg ) != 0 ) { + outchar( pgm_read_byte( msg++ ) ); + }; +} + +/***************************************************************************/ +void printmsg(const unsigned char *msg) +{ + printmsgNoNL(msg); + line_terminator(); +} + +/***************************************************************************/ +static void getln(char prompt) +{ + outchar(prompt); + txtpos = program_end+sizeof(LINENUM); + + while(1) + { + char c = inchar(); + switch(c) + { + case NL: + //break; + case CR: + line_terminator(); + // Terminate all strings with a NL + txtpos[0] = NL; + return; + case CTRLH: + if(txtpos == program_end) + break; + txtpos--; + + printmsg(backspacemsg); + break; + default: + // We need to leave at least one space to allow us to shuffle the line into order + if(txtpos == variables_begin-2) + outchar(BELL); + else + { + txtpos[0] = c; + txtpos++; + outchar(c); + } + } + } +} + +/***************************************************************************/ +static unsigned char *findline(void) +{ + unsigned char *line = program_start; + while(1) + { + if(line == program_end) + return line; + + if(((LINENUM *)line)[0] >= linenum) + return line; + + // Add the line length onto the current address, to get to the next line; + line += line[sizeof(LINENUM)]; + } +} + +/***************************************************************************/ +static void toUppercaseBuffer(void) +{ + unsigned char *c = program_end+sizeof(LINENUM); + unsigned char quote = 0; + + while(*c != NL) + { + // Are we in a quoted string? + if(*c == quote) + quote = 0; + else if(*c == '"' || *c == '\'') + quote = *c; + else if(quote == 0 && *c >= 'a' && *c <= 'z') + *c = *c + 'A' - 'a'; + c++; + } +} + +/***************************************************************************/ +void printline() +{ + LINENUM line_num; + + line_num = *((LINENUM *)(list_line)); + list_line += sizeof(LINENUM) + sizeof(char); + + // Output the line */ + printnum(line_num); + outchar(' '); + while(*list_line != NL) + { + outchar(*list_line); + list_line++; + } + list_line++; + line_terminator(); +} + +/***************************************************************************/ +static short int expr4(void) +{ + // fix provided by Jurg Wullschleger wullschleger@gmail.com + // fixes whitespace and unary operations + ignore_blanks(); + + if( *txtpos == '-' ) { + txtpos++; + return -expr4(); + } + // end fix + + if(*txtpos == '0') + { + txtpos++; + return 0; + } + + if(*txtpos >= '1' && *txtpos <= '9') + { + short int a = 0; + do { + a = a*10 + *txtpos - '0'; + txtpos++; + } + while(*txtpos >= '0' && *txtpos <= '9'); + return a; + } + + // Is it a function or variable reference? + if(txtpos[0] >= 'A' && txtpos[0] <= 'Z') + { + short int a; + // Is it a variable reference (single alpha) + if(txtpos[1] < 'A' || txtpos[1] > 'Z') + { + a = ((short int *)variables_begin)[*txtpos - 'A']; + txtpos++; + return a; + } + + // Is it a function with a single parameter + scantable(func_tab); + if(table_index == FUNC_UNKNOWN) + goto expr4_error; + + unsigned char f = table_index; + + if(*txtpos != '(') + goto expr4_error; + + txtpos++; + a = expression(); + if(*txtpos != ')') + goto expr4_error; + txtpos++; + switch(f) + { + case FUNC_PEEK: + return program[a]; + + case FUNC_ABS: + if(a < 0) + return -a; + return a; + +/* +// fix +#ifdef ARDUINO + case FUNC_AREAD: + pinMode( a, INPUT ); + return analogRead( a ); + case FUNC_DREAD: + pinMode( a, INPUT ); + return digitalRead( a ); +#endif +*/ + + case FUNC_RND: + return 0; +/* +#ifdef ARDUINO + return( random( a )); +#else + return( rand() % a ); +#endif +*/ + } + } + + if(*txtpos == '(') + { + short int a; + txtpos++; + a = expression(); + if(*txtpos != ')') + goto expr4_error; + + txtpos++; + return a; + } + +expr4_error: + expression_error = 1; + return 0; + +} + +/***************************************************************************/ +static short int expr3(void) +{ + short int a,b; + + a = expr4(); + + ignore_blanks(); // fix for eg: 100 a = a + 1 + + while(1) + { + if(*txtpos == '*') + { + txtpos++; + b = expr4(); + a *= b; + } + else if(*txtpos == '/') + { + txtpos++; + b = expr4(); + if(b != 0) + a /= b; + else + expression_error = 1; + } + else + return a; + } +} + +/***************************************************************************/ +static short int expr2(void) +{ + short int a,b; + + if(*txtpos == '-' || *txtpos == '+') + a = 0; + else + a = expr3(); + + while(1) + { + if(*txtpos == '-') + { + txtpos++; + b = expr3(); + a -= b; + } + else if(*txtpos == '+') + { + txtpos++; + b = expr3(); + a += b; + } + else + return a; + } +} +/***************************************************************************/ +static short int expression(void) +{ + short int a,b; + + a = expr2(); + + // Check if we have an error + if(expression_error) return a; + + scantable(relop_tab); + if(table_index == RELOP_UNKNOWN) + return a; + + switch(table_index) + { + case RELOP_GE: + b = expr2(); + if(a >= b) return 1; + break; + case RELOP_NE: + case RELOP_NE_BANG: + b = expr2(); + if(a != b) return 1; + break; + case RELOP_GT: + b = expr2(); + if(a > b) return 1; + break; + case RELOP_EQ: + b = expr2(); + if(a == b) return 1; + break; + case RELOP_LE: + b = expr2(); + if(a <= b) return 1; + break; + case RELOP_LT: + b = expr2(); + if(a < b) return 1; + break; + } + return 0; +} + +/***************************************************************************/ +void loop() +{ + unsigned char *start; + unsigned char *newEnd; + unsigned char linelen; + boolean isDigital; + boolean alsoWait = false; + int val; + +#ifdef ENABLE_TONES + noTone( kPiezoPin ); +#endif + + program_start = program; + program_end = program_start; + sp = program+sizeof(program); // Needed for printnum + stack_limit = program+sizeof(program)-STACK_SIZE; + variables_begin = stack_limit - 27*VAR_SIZE; + + // memory free + printnum(variables_begin-program_end); + printmsg(memorymsg); +#ifdef ENABLE_EEPROM + // eprom size + printnum( E2END+1 ); + printmsg( eeprommsg ); +#endif /* ENABLE_EEPROM */ + +warmstart: + // this signifies that it is running in 'direct' mode. + current_line = 0; + sp = program+sizeof(program); + printmsg(okmsg); + +prompt: + if( triggerRun ){ + triggerRun = false; + current_line = program_start; + goto execline; + } + + getln( '>' ); + toUppercaseBuffer(); + + txtpos = program_end+sizeof(unsigned short); + + // Find the end of the freshly entered line + while(*txtpos != NL) + txtpos++; + + // Move it to the end of program_memory + { + unsigned char *dest; + dest = variables_begin-1; + while(1) + { + *dest = *txtpos; + if(txtpos == program_end+sizeof(unsigned short)) + break; + dest--; + txtpos--; + } + txtpos = dest; + } + + // Now see if we have a line number + linenum = testnum(); + ignore_blanks(); + if(linenum == 0) + goto direct; + + if(linenum == 0xFFFF) + goto qhow; + + // Find the length of what is left, including the (yet-to-be-populated) line header + linelen = 0; + while(txtpos[linelen] != NL) + linelen++; + linelen++; // Include the NL in the line length + linelen += sizeof(unsigned short)+sizeof(char); // Add space for the line number and line length + + // Now we have the number, add the line header. + txtpos -= 3; + *((unsigned short *)txtpos) = linenum; + txtpos[sizeof(LINENUM)] = linelen; + + + // Merge it into the rest of the program + start = findline(); + + // If a line with that number exists, then remove it + if(start != program_end && *((LINENUM *)start) == linenum) + { + unsigned char *dest, *from; + unsigned tomove; + + from = start + start[sizeof(LINENUM)]; + dest = start; + + tomove = program_end - from; + while( tomove > 0) + { + *dest = *from; + from++; + dest++; + tomove--; + } + program_end = dest; + } + + if(txtpos[sizeof(LINENUM)+sizeof(char)] == NL) // If the line has no txt, it was just a delete + goto prompt; + + + + // Make room for the new line, either all in one hit or lots of little shuffles + while(linelen > 0) + { + unsigned int tomove; + unsigned char *from,*dest; + unsigned int space_to_make; + + space_to_make = txtpos - program_end; + + if(space_to_make > linelen) + space_to_make = linelen; + newEnd = program_end+space_to_make; + tomove = program_end - start; + + + // Source and destination - as these areas may overlap we need to move bottom up + from = program_end; + dest = newEnd; + while(tomove > 0) + { + from--; + dest--; + *dest = *from; + tomove--; + } + + // Copy over the bytes into the new space + for(tomove = 0; tomove < space_to_make; tomove++) + { + *start = *txtpos; + txtpos++; + start++; + linelen--; + } + program_end = newEnd; + } + goto prompt; + +unimplemented: + printmsg(unimplimentedmsg); + goto prompt; + +qhow: + printmsg(howmsg); + goto prompt; + +qwhat: + printmsgNoNL(whatmsg); + if(current_line != NULL) + { + unsigned char tmp = *txtpos; + if(*txtpos != NL) + *txtpos = '^'; + list_line = current_line; + printline(); + *txtpos = tmp; + } + line_terminator(); + goto prompt; + +qsorry: + printmsg(sorrymsg); + goto warmstart; + +run_next_statement: + while(*txtpos == ':') + txtpos++; + ignore_blanks(); + if(*txtpos == NL) + goto execnextline; + goto interperateAtTxtpos; + +direct: + txtpos = program_end+sizeof(LINENUM); + if(*txtpos == NL) + goto prompt; + +interperateAtTxtpos: + if(breakcheck()) + { + printmsg(breakmsg); + goto warmstart; + } + + scantable(keywords); + + switch(table_index) + { + case KW_DELAY: + { + + expression_error = 0; + val = expression(); + wait_ms( val ); + goto execnextline; + } + + case KW_FILES: + goto files; + case KW_LIST: + goto list; + case KW_CHAIN: + goto chain; + case KW_LOAD: + goto load; + case KW_MEM: + goto mem; + case KW_NEW: + if(txtpos[0] != NL) + goto qwhat; + program_end = program_start; + goto prompt; + case KW_RUN: + current_line = program_start; + goto execline; + case KW_SAVE: + goto save; + case KW_NEXT: + goto next; + case KW_LET: + goto assignment; + case KW_IF: + short int val; + expression_error = 0; + val = expression(); + if(expression_error || *txtpos == NL) + goto qhow; + if(val != 0) + goto interperateAtTxtpos; + goto execnextline; + + case KW_GOTO: + expression_error = 0; + linenum = expression(); + if(expression_error || *txtpos != NL) + goto qhow; + current_line = findline(); + goto execline; + + case KW_GOSUB: + goto gosub; + case KW_RETURN: + goto gosub_return; + case KW_REM: + case KW_QUOTE: + goto execnextline; // Ignore line completely + case KW_FOR: + goto forloop; + case KW_INPUT: + goto input; + case KW_PRINT: + case KW_QMARK: + goto print; + case KW_POKE: + goto poke; + case KW_END: + case KW_STOP: + // This is the easy way to end - set the current line to the end of program attempt to run it + if(txtpos[0] != NL) + goto qwhat; + current_line = program_end; + goto execline; + case KW_BYE: + // Leave the basic interperater + return; + + case KW_AWRITE: // AWRITE <pin>, HIGH|LOW + isDigital = false; + goto awrite; + case KW_DWRITE: // DWRITE <pin>, HIGH|LOW + isDigital = true; + goto dwrite; + + case KW_RSEED: + goto rseed; + +#ifdef ENABLE_TONES + case KW_TONEW: + alsoWait = true; + case KW_TONE: + goto tonegen; + case KW_NOTONE: + goto tonestop; +#endif + +#ifdef ENABLE_EEPROM + case KW_EFORMAT: + goto eformat; + case KW_ESAVE: + goto esave; + case KW_ELOAD: + goto eload; + case KW_ELIST: + goto elist; + case KW_ECHAIN: + goto echain; +#endif + + case KW_DEFAULT: + goto assignment; + default: + break; + } + +execnextline: + if(current_line == NULL) // Processing direct commands? + goto prompt; + current_line += current_line[sizeof(LINENUM)]; + +execline: + if(current_line == program_end) // Out of lines to run + goto warmstart; + txtpos = current_line+sizeof(LINENUM)+sizeof(char); + goto interperateAtTxtpos; + +#ifdef ENABLE_EEPROM +elist: + { + int i; + for( i = 0 ; i < (E2END +1) ; i++ ) + { + val = EEPROM.read( i ); + + if( val == '\0' ) { + goto execnextline; + } + + if( ((val < ' ') || (val > '~')) && (val != NL) && (val != CR)) { + outchar( '?' ); + } + else { + outchar( val ); + } + } + } + goto execnextline; + +eformat: + { + for( int i = 0 ; i < E2END ; i++ ) + { + if( (i & 0x03f) == 0x20 ) outchar( '.' ); + EEPROM.write( i, 0 ); + } + outchar( LF ); + } + goto execnextline; + +esave: + { + outStream = kStreamEEProm; + eepos = 0; + + // copied from "List" + list_line = findline(); + while(list_line != program_end) + printline(); + + // go back to standard output, close the file + outStream = kStreamSerial; + + goto warmstart; + } + + +echain: + runAfterLoad = true; + +eload: + // clear the program + program_end = program_start; + + // load from a file into memory + eepos = 0; + inStream = kStreamEEProm; + inhibitOutput = true; + goto warmstart; +#endif /* ENABLE_EEPROM */ + +input: + { + unsigned char var; + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qwhat; + var = *txtpos; + txtpos++; + ignore_blanks(); + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + ((short int *)variables_begin)[var-'A'] = 99; + + goto run_next_statement; + } + +forloop: + { + unsigned char var; + short int initial, step, terminal; + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qwhat; + var = *txtpos; + txtpos++; + ignore_blanks(); + if(*txtpos != '=') + goto qwhat; + txtpos++; + ignore_blanks(); + + expression_error = 0; + initial = expression(); + if(expression_error) + goto qwhat; + + scantable(to_tab); + if(table_index != 0) + goto qwhat; + + terminal = expression(); + if(expression_error) + goto qwhat; + + scantable(step_tab); + if(table_index == 0) + { + step = expression(); + if(expression_error) + goto qwhat; + } + else + step = 1; + ignore_blanks(); + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + + + if(!expression_error && *txtpos == NL) + { + struct stack_for_frame *f; + if(sp + sizeof(struct stack_for_frame) < stack_limit) + goto qsorry; + + sp -= sizeof(struct stack_for_frame); + f = (struct stack_for_frame *)sp; + ((short int *)variables_begin)[var-'A'] = initial; + f->frame_type = STACK_FOR_FLAG; + f->for_var = var; + f->terminal = terminal; + f->step = step; + f->txtpos = txtpos; + f->current_line = current_line; + goto run_next_statement; + } + } + goto qhow; + +gosub: + expression_error = 0; + linenum = expression(); + if(!expression_error && *txtpos == NL) + { + struct stack_gosub_frame *f; + if(sp + sizeof(struct stack_gosub_frame) < stack_limit) + goto qsorry; + + sp -= sizeof(struct stack_gosub_frame); + f = (struct stack_gosub_frame *)sp; + f->frame_type = STACK_GOSUB_FLAG; + f->txtpos = txtpos; + f->current_line = current_line; + current_line = findline(); + goto execline; + } + goto qhow; + +next: + // Fnd the variable name + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qhow; + txtpos++; + ignore_blanks(); + if(*txtpos != ':' && *txtpos != NL) + goto qwhat; + +gosub_return: + // Now walk up the stack frames and find the frame we want, if present + tempsp = sp; + while(tempsp < program+sizeof(program)-1) + { + switch(tempsp[0]) + { + case STACK_GOSUB_FLAG: + if(table_index == KW_RETURN) + { + struct stack_gosub_frame *f = (struct stack_gosub_frame *)tempsp; + current_line = f->current_line; + txtpos = f->txtpos; + sp += sizeof(struct stack_gosub_frame); + goto run_next_statement; + } + // This is not the loop you are looking for... so Walk back up the stack + tempsp += sizeof(struct stack_gosub_frame); + break; + case STACK_FOR_FLAG: + // Flag, Var, Final, Step + if(table_index == KW_NEXT) + { + struct stack_for_frame *f = (struct stack_for_frame *)tempsp; + // Is the the variable we are looking for? + if(txtpos[-1] == f->for_var) + { + short int *varaddr = ((short int *)variables_begin) + txtpos[-1] - 'A'; + *varaddr = *varaddr + f->step; + // Use a different test depending on the sign of the step increment + if((f->step > 0 && *varaddr <= f->terminal) || (f->step < 0 && *varaddr >= f->terminal)) + { + // We have to loop so don't pop the stack + txtpos = f->txtpos; + current_line = f->current_line; + goto run_next_statement; + } + // We've run to the end of the loop. drop out of the loop, popping the stack + sp = tempsp + sizeof(struct stack_for_frame); + goto run_next_statement; + } + } + // This is not the loop you are looking for... so Walk back up the stack + tempsp += sizeof(struct stack_for_frame); + break; + default: + //printf("Stack is stuffed!\n"); + goto warmstart; + } + } + // Didn't find the variable we've been looking for + goto qhow; + +assignment: + { + short int value; + short int *var; + + if(*txtpos < 'A' || *txtpos > 'Z') + goto qhow; + var = (short int *)variables_begin + *txtpos - 'A'; + txtpos++; + + ignore_blanks(); + + if (*txtpos != '=') + goto qwhat; + txtpos++; + ignore_blanks(); + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + // Check that we are at the end of the statement + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + *var = value; + } + goto run_next_statement; +poke: + { + short int value; + unsigned char *address; + + // Work out where to put it + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + address = (unsigned char *)value; + + // check for a comma + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + // Now get the value to assign + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + //printf("Poke %p value %i\n",address, (unsigned char)value); + // Check that we are at the end of the statement + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + } + goto run_next_statement; + +list: + linenum = testnum(); // Retuns 0 if no line found. + + // Should be EOL + if(txtpos[0] != NL) + goto qwhat; + + // Find the line + list_line = findline(); + while(list_line != program_end) + printline(); + goto warmstart; + +print: + // If we have an empty list then just put out a NL + if(*txtpos == ':' ) + { + line_terminator(); + txtpos++; + goto run_next_statement; + } + if(*txtpos == NL) + { + goto execnextline; + } + + while(1) + { + ignore_blanks(); + if(print_quoted_string()) + { + ; + } + else if(*txtpos == '"' || *txtpos == '\'') + goto qwhat; + else + { + short int e; + expression_error = 0; + e = expression(); + if(expression_error) + goto qwhat; + printnum(e); + } + + // At this point we have three options, a comma or a new line + if(*txtpos == ',') + txtpos++; // Skip the comma and move onto the next + else if(txtpos[0] == ';' && (txtpos[1] == NL || txtpos[1] == ':')) + { + txtpos++; // This has to be the end of the print - no newline + break; + } + else if(*txtpos == NL || *txtpos == ':') + { + line_terminator(); // The end of the print statement + break; + } + else + goto qwhat; + } + goto run_next_statement; + +mem: + // memory free + printnum(variables_begin-program_end); + printmsg(memorymsg); + +#ifdef ENABLE_EEPROM + { + // eprom size + printnum( E2END+1 ); + printmsg( eeprommsg ); + + // figure out the memory usage; + val = ' '; + int i; + for( i=0 ; (i<(E2END+1)) && (val != '\0') ; i++ ) { + val = EEPROM.read( i ); + } + printnum( (E2END +1) - (i-1) ); + + printmsg( eepromamsg ); + } +#endif /* ENABLE_EEPROM */ + goto run_next_statement; + + + /*************************************************/ + +awrite: // AWRITE <pin>,val +dwrite: + { + short int pinNo; + short int value; + unsigned char *txtposBak; + + // Get the pin number + expression_error = 0; + pinNo = expression(); + if(expression_error) + goto qwhat; + + // check for a comma + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + + txtposBak = txtpos; + scantable(highlow_tab); + if(table_index != HIGHLOW_UNKNOWN) + { + if( table_index <= HIGHLOW_HIGH ) { + value = 1; + } + else { + value = 0; + } + } + else { + + // and the value (numerical) + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + } + /* fix + pinMode( pinNo, OUTPUT ); + if( isDigital ) { + digitalWrite( pinNo, value ); + } + else { + analogWrite( pinNo, value ); + } + */ + } + goto run_next_statement; + + /*************************************************/ +files: + // display a listing of files on the device. + // version 1: no support for subdirectories + +#ifdef ENABLE_FILEIO + cmd_Files(); + goto warmstart; +#else + goto unimplemented; +#endif // ENABLE_FILEIO + + +chain: + runAfterLoad = true; + +load: + // clear the program + program_end = program_start; + + // load from a file into memory +#ifdef ENABLE_FILEIO + { + unsigned char *filename; + + // Work out the filename + expression_error = 0; + filename = filenameWord(); + if(expression_error) + goto qwhat; + +/* +#ifdef ARDUINO + // Arduino specific + if( !SD.exists( (char *)filename )) + { + printmsg( sdfilemsg ); + } + else { + + fp = SD.open( (const char *)filename ); + inStream = kStreamFile; + inhibitOutput = true; + } +#else // ARDUINO + // Desktop specific +#endif // ARDUINO +*/ + // this will kickstart a series of events to read in from the file. + + } + goto warmstart; +#else // ENABLE_FILEIO + goto unimplemented; +#endif // ENABLE_FILEIO + + + +save: + // save from memory out to a file +#ifdef ENABLE_FILEIO + { + unsigned char *filename; + + // Work out the filename + expression_error = 0; + filename = filenameWord(); + if(expression_error) + goto qwhat; +/* +#ifdef ARDUINO + // remove the old file if it exists + if( SD.exists( (char *)filename )) { + SD.remove( (char *)filename ); + } + + // open the file, switch over to file output + fp = SD.open( (const char *)filename, FILE_WRITE ); + outStream = kStreamFile; + + // copied from "List" + list_line = findline(); + while(list_line != program_end) + printline(); + + // go back to standard output, close the file + outStream = kStreamSerial; + + fp.close(); +#else // ARDUINO + // desktop +#endif // ARDUINO +*/ + goto warmstart; + } +#else // ENABLE_FILEIO + goto unimplemented; +#endif // ENABLE_FILEIO + +rseed: + { + short int value; + + //Get the pin number + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + + +/* fix +#ifdef ARDUINO + randomSeed( value ); +#else // ARDUINO + srand( value ); +#endif // ARDUINO +*/ + goto run_next_statement; + } + +#ifdef ENABLE_TONES +tonestop: + noTone( kPiezoPin ); + goto run_next_statement; + +tonegen: + { + // TONE freq, duration + // if either are 0, tones turned off + short int freq; + short int duration; + + //Get the frequency + expression_error = 0; + freq = expression(); + if(expression_error) + goto qwhat; + + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + + //Get the duration + expression_error = 0; + duration = expression(); + if(expression_error) + goto qwhat; + + if( freq == 0 || duration == 0 ) + goto tonestop; + + tone( kPiezoPin, freq, duration ); + if( alsoWait ) { + delay( duration ); + alsoWait = false; + } + goto run_next_statement; + } +#endif /* ENABLE_TONES */ +} + +// returns 1 if the character is valid in a filename +static int isValidFnChar( char c ) +{ + if( c >= '0' && c <= '9' ) return 1; // number + if( c >= 'A' && c <= 'Z' ) return 1; // LETTER + if( c >= 'a' && c <= 'z' ) return 1; // letter (for completeness) + if( c == '_' ) return 1; + if( c == '+' ) return 1; + if( c == '.' ) return 1; + if( c == '~' ) return 1; // Window~1.txt + + return 0; +} + +unsigned char * filenameWord(void) +{ + // SDL - I wasn't sure if this functionality existed above, so I figured i'd put it here + unsigned char * ret = txtpos; + expression_error = 0; + + // make sure there are no quotes or spaces, search for valid characters + //while(*txtpos == SPACE || *txtpos == TAB || *txtpos == SQUOTE || *txtpos == DQUOTE ) txtpos++; + while( !isValidFnChar( *txtpos )) txtpos++; + ret = txtpos; + + if( *ret == '\0' ) { + expression_error = 1; + return ret; + } + + // now, find the next nonfnchar + txtpos++; + while( isValidFnChar( *txtpos )) txtpos++; + if( txtpos != ret ) *txtpos = '\0'; + + // set the error code if we've got no string + if( *ret == '\0' ) { + expression_error = 1; + } + + return ret; +} + +/***************************************************************************/ +static void line_terminator(void) +{ + outchar(NL); + outchar(CR); +} +/***********************************************************/ +static unsigned char breakcheck(void) +{ + if(pc.readable()) + return pc.getc() == CTRLC; + return 0; +} +/***********************************************************/ +static int inchar() +{ + int v; + + switch( inStream ) { + case( kStreamFile ): +#ifdef ENABLE_FILEIO + v = fp.read(); + if( v == NL ) v=CR; // file translate + if( !fp.available() ) { + fp.close(); + goto inchar_loadfinish; + } + return v; +#else +#endif + break; + case( kStreamEEProm ): +#ifdef ENABLE_EEPROM + v = EEPROM.read( eepos++ ); + if( v == '\0' ) { + goto inchar_loadfinish; + } + return v; +#endif + break; + case( kStreamSerial ): + default: + while(1) + { + if(pc.readable()) + return pc.getc(); + } + } + +inchar_loadfinish: + inStream = kStreamSerial; + inhibitOutput = false; + + if( runAfterLoad ) { + runAfterLoad = false; + triggerRun = true; + } + return NL; // trigger a prompt. + +} +/***********************************************************/ +static void outchar(unsigned char c) +{ + if( inhibitOutput ) return; + + pc.putc(c); +} +/***********************************************************/ +int main() +{ + while (1) + { + loop(); + } +} + \ No newline at end of file
diff -r 000000000000 -r c52ead8719b3 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Jan 21 15:32:36 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/4fc01daae5a5 \ No newline at end of file