Advertisement
Pew446

TinyBasic.cpp

Oct 8th, 2013
226
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // TinyBasic.cpp : An implementation of TinyBASIC in C
  2. //
  3. // Author : Mike Field - hamster@snap.net.nz
  4. //
  5. // Based on TinyBasic for 68000, by Gordon Brandly
  6. // (see http://members.shaw.ca/gbrandly/68ktinyb.html)
  7. //
  8. // which itself was Derived from Palo Alto Tiny BASIC as
  9. // published in the May 1976 issue of Dr. Dobb's Journal.  
  10. //
  11. // 0.03 21/01/2011 : Added INPUT routine
  12. //                 : Reorganised memory layout
  13. //                 : Expanded all error messages
  14. //                 : Break key added
  15. //                 : Removed the calls to printf (left by debugging)
  16.  
  17. #ifndef ARDUINO
  18. #include "stdafx.h"
  19. #include <conio.h>
  20. #endif
  21.  
  22. #include "Chatpad.h"
  23. Chatpad pad;
  24.  
  25. #include <LiquidCrystal.h>
  26.  
  27. // ASCII Characters
  28. #define CR  '\r'
  29. #define NL  '\n'
  30. #define TAB '\t'
  31. #define BELL    '\b'
  32. #define DEL '\177'
  33. #define SPACE   ' '
  34. #define CTRLC   0x03
  35. #define CTRLH   0x08
  36. #define CTRLS   0x13
  37. #define CTRLX   0x18
  38.  
  39. static const byte kInitMessage[] = { 0x87, 0x02, 0x8C, 0x1F, 0xCC };
  40.  
  41. LiquidCrystal lcd(7, 6, 2, 3, 4, 5);
  42.  
  43. typedef short unsigned LINENUM;
  44.  
  45. /***********************************************************/
  46. // Keyword table and constants - the last character has 0x80 added to it
  47. static unsigned char keywords[] = {
  48.     'L','I','S','T'+0x80,
  49.     'L','O','A','D'+0x80,
  50.     'N','E','W'+0x80,
  51.     'R','U','N'+0x80,
  52.     'S','A','V','E'+0x80,
  53.     'N','E','X','T'+0x80,
  54.     'L','E','T'+0x80,
  55.     'I','F'+0x80,
  56.     'G','O','T','O'+0x80,
  57.     'G','O','S','U','B'+0x80,
  58.     'R','E','T','U','R','N'+0x80,
  59.     'R','E','M'+0x80,
  60.     'F','O','R'+0x80,
  61.     'I','N','P','U','T'+0x80,
  62.     'P','R','I','N','T'+0x80,
  63.     'P','O','K','E'+0x80,
  64.     'S','T','O','P'+0x80,
  65.     'B','Y','E'+0x80,
  66.     0
  67. };
  68.  
  69. #define KW_LIST     0
  70. #define KW_LOAD     1
  71. #define KW_NEW      2
  72. #define KW_RUN      3
  73. #define KW_SAVE     4
  74. #define KW_NEXT     5
  75. #define KW_LET      6
  76. #define KW_IF       7
  77. #define KW_GOTO     8
  78. #define KW_GOSUB    9
  79. #define KW_RETURN   10
  80. #define KW_REM      11
  81. #define KW_FOR      12
  82. #define KW_INPUT    13
  83. #define KW_PRINT    14
  84. #define KW_POKE     15
  85. #define KW_STOP     16
  86. #define KW_BYE      17
  87. #define KW_DEFAULT  18
  88.  
  89. struct stack_for_frame {
  90.     char frame_type;
  91.     char for_var;
  92.     short int terminal;
  93.     short int step;
  94.     unsigned char *current_line;
  95.     unsigned char *txtpos;
  96. };
  97.  
  98. struct stack_gosub_frame {
  99.     char frame_type;
  100.     unsigned char *current_line;
  101.     unsigned char *txtpos;
  102. };
  103.  
  104. static unsigned char func_tab[] = {
  105.     'P','E','E','K'+0x80,
  106.     'A','B','S'+0x80,
  107.     0
  108. };
  109. #define FUNC_PEEK    0
  110. #define FUNC_ABS     1
  111. #define FUNC_UNKNOWN 2
  112.  
  113. static unsigned char to_tab[] = {
  114.     'T','O'+0x80,
  115.     0
  116. };
  117.  
  118. static unsigned char step_tab[] = {
  119.     'S','T','E','P'+0x80,
  120.     0
  121. };
  122.  
  123. static unsigned char relop_tab[] = {
  124.     '>','='+0x80,
  125.     '<','>'+0x80,
  126.     '>'+0x80,
  127.     '='+0x80,
  128.     '<','='+0x80,
  129.     '<'+0x80,
  130.     0
  131. };
  132.  
  133. #define RELOP_GE        0
  134. #define RELOP_NE        1
  135. #define RELOP_GT        2
  136. #define RELOP_EQ        3
  137. #define RELOP_LE        4
  138. #define RELOP_LT        5
  139. #define RELOP_UNKNOWN   6
  140.  
  141. #define VAR_SIZE sizeof(short int) // Size of variables in bytes
  142.  
  143. static unsigned char memory[1400];
  144. static unsigned char *txtpos,*list_line;
  145. static unsigned char expression_error;
  146. static unsigned char *tempsp;
  147. static unsigned char *stack_limit;
  148. static unsigned char *program_start;
  149. static unsigned char *program_end;
  150. static unsigned char *stack; // Software stack for things that should go on the CPU stack
  151. static unsigned char *variables_table;
  152. static unsigned char *current_line;
  153. static unsigned char *sp;
  154. #define STACK_GOSUB_FLAG 'G'
  155. #define STACK_FOR_FLAG 'F'
  156. static unsigned char table_index;
  157. static LINENUM linenum;
  158.  
  159. static const unsigned char okmsg[]      = "";
  160. static const unsigned char badlinemsg[]     = "Invalid line number";
  161. static const unsigned char invalidexprmsg[] = "Invalid expression";
  162. static const unsigned char syntaxmsg[] = "Syntax Error";
  163. static const unsigned char badinputmsg[] = "\nBad number";
  164. static const unsigned char nomemmsg[]   = "Not enough memory!";
  165. static const unsigned char initmsg[]    = "TinyBasic";
  166. static const unsigned char memorymsg[]  = " bytes free.";
  167. static const unsigned char breakmsg[]   = "break!";
  168. static const unsigned char stackstuffedmsg[] = "Stack is stuffed!\n";
  169. static const unsigned char unimplimentedmsg[]   = "Unimplemented";
  170. static const unsigned char backspacemsg[]       = "\b \b";
  171.  
  172. short cursorX;
  173. char screenMem[80] = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
  174.                      32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
  175.                      32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
  176.                      32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
  177. boolean chatPadUsed = false;
  178. char chatPadChar;
  179.  
  180. boolean startup = true;
  181.  
  182. static int inchar(void);
  183. static void outchar(unsigned char c);
  184. static void lcdChar(int c);
  185. void clearScreen();
  186. static void drawScreen(int upTo);
  187. static void line_terminator(void);
  188. static short int expression(void);
  189. static unsigned char breakcheck(void);
  190. void print_keys(Chatpad &pad, Chatpad::keycode_t code,
  191.     Chatpad::eventtype_t type);
  192. /***************************************************************************/
  193. static void ignore_blanks(void)
  194. {
  195.     while(*txtpos == SPACE || *txtpos == TAB)
  196.         txtpos++;
  197. }
  198.  
  199. /***************************************************************************/
  200. static void scantable(unsigned char *table)
  201. {
  202.     int i = 0;
  203.     ignore_blanks();
  204.     table_index = 0;
  205.     while(1)
  206.     {
  207.         // Run out of table entries?
  208.         if(table[0] == 0)
  209.             return;
  210.  
  211.         // Do we match this character?
  212.         if(txtpos[i] == table[0])
  213.         {
  214.             i++;
  215.             table++;
  216.         }
  217.         else
  218.         {
  219.             // do we match the last character of keywork (with 0x80 added)? If so, return
  220.             if(txtpos[i]+0x80 == table[0])
  221.             {
  222.                 txtpos += i+1;  // Advance the pointer to following the keyword
  223.                 ignore_blanks();
  224.                 return;
  225.             }
  226.  
  227.             // Forward to the end of this keyword
  228.             while((table[0] & 0x80) == 0)
  229.                 table++;
  230.  
  231.             // Now move on to the first character of the next word, and reset the position index
  232.             table++;
  233.             table_index++;
  234.             i = 0;
  235.         }
  236.     }
  237. }
  238.  
  239. /***************************************************************************/
  240. static void pushb(unsigned char b)
  241. {
  242.     sp--;
  243.     *sp = b;
  244. }
  245.  
  246. /***************************************************************************/
  247. static unsigned char popb()
  248. {
  249.     unsigned char b;
  250.     b = *sp;
  251.     sp++;
  252.     return b;
  253. }
  254.  
  255. /***************************************************************************/
  256. static void printnum(int num)
  257. {
  258.     int digits = 0;
  259.  
  260.     if(num < 0)
  261.     {
  262.         num = -num;
  263.         outchar('-');
  264.     }
  265.  
  266.     do {
  267.         pushb(num%10+'0');
  268.         num = num/10;
  269.         digits++;
  270.     }
  271.     while (num > 0);
  272.  
  273.     while(digits > 0)
  274.     {
  275.         outchar(popb());
  276.         digits--;
  277.     }
  278. }
  279. /***************************************************************************/
  280. static unsigned short testnum(void)
  281. {
  282.     unsigned short num = 0;
  283.     ignore_blanks();
  284.    
  285.     while(*txtpos>= '0' && *txtpos <= '9' )
  286.     {
  287.         // Trap overflows
  288.         if(num >= 0xFFFF/10)
  289.         {
  290.             num = 0xFFFF;
  291.             break;
  292.         }
  293.  
  294.         num = num *10 + *txtpos - '0';
  295.         txtpos++;
  296.     }
  297.     return  num;
  298. }
  299.  
  300. /***************************************************************************/
  301. unsigned char check_statement_end(void)
  302. {
  303.     ignore_blanks();
  304.     return (*txtpos == NL) || (*txtpos == ':');
  305. }
  306.  
  307. /***************************************************************************/
  308. static void printmsgNoNL(const unsigned char *msg)
  309. {
  310.     while(*msg)
  311.     {
  312.         outchar(*msg);
  313.         msg++;
  314.     }
  315.     drawScreen(80);
  316. }
  317.  
  318. /***************************************************************************/
  319. static unsigned char print_quoted_string(void)
  320. {
  321.     int i=0;
  322.     unsigned char delim = *txtpos;
  323.     if(delim != '"' && delim != '\'')
  324.         return 0;
  325.     txtpos++;
  326.  
  327.     // Check we have a closing delimiter
  328.     while(txtpos[i] != delim)
  329.     {
  330.         if(txtpos[i] == NL)
  331.             return 0;
  332.         i++;
  333.     }
  334.  
  335.     // Print the characters
  336.     while(*txtpos != delim)
  337.     {
  338.         outchar(*txtpos);
  339.         txtpos++;
  340.     }
  341.     txtpos++; // Skip over the last delimiter
  342.     ignore_blanks();
  343.  
  344.     return 1;
  345. }
  346.  
  347. /***************************************************************************/
  348. static void printmsg(const unsigned char *msg)
  349. {
  350.     printmsgNoNL(msg);
  351.     line_terminator();
  352. }
  353.  
  354. /***************************************************************************/
  355. unsigned char getln(char prompt)
  356. {
  357.  
  358.     outchar(prompt);
  359.     txtpos = program_end+sizeof(LINENUM);
  360.         drawScreen(80);
  361.        
  362.     while(1)
  363.     {
  364.                 if(!chatPadUsed){
  365.                   pollChatPad();
  366.                 }
  367.                 else
  368.                 {
  369.                   chatPadUsed = false;
  370.         char c = chatPadChar;
  371.         switch(c)
  372.         {
  373.             case CR:
  374.             case NL:
  375.                   line_terminator();
  376.                 // Terminate all strings with a NL
  377.                 txtpos[0] = NL;
  378.                 return 1;
  379.             case CTRLC:
  380.                 return 0;
  381.             case CTRLH:
  382.                 if(txtpos == program_end)
  383.                     break;
  384.                 txtpos--;
  385.                 printmsgNoNL(backspacemsg);
  386.                 break;
  387.             default:
  388.                 // We need to leave at least one space to allow us to shuffle the line into order
  389.                 if(txtpos == sp-2)
  390.                     outchar(BELL);
  391.                 else
  392.                 {
  393.                     txtpos[0] = c;
  394.                     txtpos++;
  395.                     outchar(c);
  396.                 }
  397.         }
  398.               }
  399.     }
  400. }
  401.  
  402. /***************************************************************************/
  403. static unsigned char *findline(void)
  404. {
  405.     unsigned char *line = program_start;
  406.     while(1)
  407.     {
  408.         if(line == program_end)
  409.             return line;
  410.  
  411.         if(((LINENUM *)line)[0] >= linenum)
  412.             return line;
  413.  
  414.         // Add the line length onto the current address, to get to the next line;
  415.         line += line[sizeof(LINENUM)];
  416.     }
  417. }
  418.  
  419. /***************************************************************************/
  420. static void toUppercaseBuffer(void)
  421. {
  422.     unsigned char *c = program_end+sizeof(LINENUM);
  423.     unsigned char quote = 0;
  424.  
  425.     while(*c != NL)
  426.     {
  427.         // Are we in a quoted string?
  428.         if(*c == quote)
  429.             quote = 0;
  430.         else if(*c == '"' || *c == '\'')
  431.             quote = *c;
  432.         else if(quote == 0 && *c >= 'a' && *c <= 'z')
  433.             *c = *c + 'A' - 'a';
  434.         c++;
  435.     }
  436. }
  437.  
  438. /***************************************************************************/
  439. void printline()
  440. {
  441.     LINENUM line_num;
  442.    
  443.     line_num = *((LINENUM *)(list_line));
  444.     list_line += sizeof(LINENUM) + sizeof(char);
  445.  
  446.     // Output the line */
  447.     printnum(line_num);
  448.     outchar(' ');
  449.     while(*list_line != NL)
  450.     {
  451.         outchar(*list_line);
  452.         list_line++;
  453.     }
  454.     list_line++;
  455.     line_terminator();
  456. }
  457.  
  458. /***************************************************************************/
  459. static short int expr4(void)
  460. {
  461.     short int a = 0;
  462.  
  463.     if(*txtpos == '0')
  464.     {
  465.         txtpos++;
  466.         a = 0;
  467.         goto success;
  468.     }
  469.  
  470.     if(*txtpos >= '1' && *txtpos <= '9')
  471.     {
  472.         do  {
  473.             a = a*10 + *txtpos - '0';
  474.             txtpos++;
  475.         } while(*txtpos >= '0' && *txtpos <= '9');
  476.             goto success;
  477.     }
  478.  
  479.     // Is it a function or variable reference?
  480.     if(txtpos[0] >= 'A' && txtpos[0] <= 'Z')
  481.     {
  482.         // Is it a variable reference (single alpha)
  483.         if(txtpos[1] < 'A' || txtpos[1] > 'Z')
  484.         {
  485.             a = ((short int *)variables_table)[*txtpos - 'A'];
  486.             txtpos++;
  487.             goto success;
  488.         }
  489.  
  490.         // Is it a function with a single parameter
  491.         scantable(func_tab);
  492.         if(table_index == FUNC_UNKNOWN)
  493.             goto expr4_error;
  494.  
  495.         unsigned char f = table_index;
  496.  
  497.         if(*txtpos != '(')
  498.             goto expr4_error;
  499.  
  500.         txtpos++;
  501.         a = expression();
  502.         if(*txtpos != ')')
  503.                 goto expr4_error;
  504.         txtpos++;
  505.         switch(f)
  506.         {
  507.             case FUNC_PEEK:
  508.                 a =  memory[a];
  509.                 goto success;
  510.             case FUNC_ABS:
  511.                 if(a < 0)
  512.                     a = -a;
  513.                 goto success;
  514.         }
  515.     }
  516.  
  517.     if(*txtpos == '(')
  518.     {
  519.         txtpos++;
  520.         a = expression();
  521.         if(*txtpos != ')')
  522.             goto expr4_error;
  523.  
  524.         txtpos++;
  525.         goto success;
  526.     }
  527.  
  528. expr4_error:
  529.     expression_error = 1;
  530. success:
  531.     ignore_blanks();
  532.     return a;
  533. }
  534.  
  535. /***************************************************************************/
  536. static short int expr3(void)
  537. {
  538.     short int a,b;
  539.  
  540.     a = expr4();
  541.     while(1)
  542.     {
  543.         if(*txtpos == '*')
  544.         {
  545.             txtpos++;
  546.             b = expr4();
  547.             a *= b;
  548.         }
  549.         else if(*txtpos == '/')
  550.         {
  551.             txtpos++;
  552.             b = expr4();
  553.             if(b != 0)
  554.                 a /= b;
  555.             else
  556.                 expression_error = 1;
  557.         }
  558.         else
  559.             return a;
  560.     }
  561. }
  562.  
  563. /***************************************************************************/
  564. static short int expr2(void)
  565. {
  566.     short int a,b;
  567.  
  568.     if(*txtpos == '-' || *txtpos == '+')
  569.         a = 0;
  570.     else
  571.         a = expr3();
  572.  
  573.     while(1)
  574.     {
  575.         if(*txtpos == '-')
  576.         {
  577.             txtpos++;
  578.             b = expr3();
  579.             a -= b;
  580.         }
  581.         else if(*txtpos == '+')
  582.         {
  583.             txtpos++;
  584.             b = expr3();
  585.             a += b;
  586.         }
  587.         else
  588.             return a;
  589.     }
  590. }
  591. /***************************************************************************/
  592. static short int expression(void)
  593. {
  594.     short int a,b;
  595.  
  596.     a = expr2();
  597.     // Check if we have an error
  598.     if(expression_error)    return a;
  599.  
  600.     scantable(relop_tab);
  601.     if(table_index == RELOP_UNKNOWN)
  602.         return a;
  603.    
  604.     switch(table_index)
  605.     {
  606.     case RELOP_GE:
  607.         b = expr2();
  608.         if(a >= b) return 1;
  609.         break;
  610.     case RELOP_NE:
  611.         b = expr2();
  612.         if(a != b) return 1;
  613.         break;
  614.     case RELOP_GT:
  615.         b = expr2();
  616.         if(a > b) return 1;
  617.         break;
  618.     case RELOP_EQ:
  619.         b = expr2();
  620.         if(a == b) return 1;
  621.         break;
  622.     case RELOP_LE:
  623.         b = expr2();
  624.         if(a <= b) return 1;
  625.         break;
  626.     case RELOP_LT:
  627.         b = expr2();
  628.         if(a < b) return 1;
  629.         break;
  630.     }
  631.     return 0;
  632. }
  633.  
  634. /***************************************************************************/
  635. void loop()
  636. {
  637.  
  638.         clearScreen();
  639.     unsigned char *start;
  640.     unsigned char *newEnd;
  641.     unsigned char linelen;
  642.    
  643.     variables_table = memory;
  644.     program_start = memory + 27*VAR_SIZE + 80*VAR_SIZE;
  645.     program_end = program_start;
  646.     sp = memory+sizeof(memory);  // Needed for printnum
  647.     printmsg(initmsg);
  648.     printnum(sp-program_end);
  649.     printmsg(memorymsg);
  650.  
  651. warmstart:
  652.     // this signifies that it is running in 'direct' mode.
  653.     current_line = 0;
  654.     sp = memory+sizeof(memory);
  655.     printmsg(okmsg);
  656.  
  657. prompt:
  658.     while(!getln('>'))
  659.         line_terminator();
  660.     toUppercaseBuffer();
  661.  
  662.     txtpos = program_end+sizeof(unsigned short);
  663.  
  664.     // Find the end of the freshly entered line
  665.     while(*txtpos != NL)
  666.         txtpos++;
  667.  
  668.     // Move it to the end of program_memory
  669.     {
  670.         unsigned char *dest;
  671.         dest = sp-1;
  672.         while(1)
  673.         {
  674.             *dest = *txtpos;
  675.             if(txtpos == program_end+sizeof(unsigned short))
  676.                 break;
  677.             dest--;
  678.             txtpos--;
  679.         }
  680.         txtpos = dest;
  681.     }
  682.  
  683.     // Now see if we have a line number
  684.     linenum = testnum();
  685.     ignore_blanks();
  686.     if(linenum == 0)
  687.         goto direct;
  688.  
  689.     if(linenum == 0xFFFF)
  690.         goto badline;
  691.  
  692.     // Find the length of what is left, including the (yet-to-be-populated) line header
  693.     linelen = 0;
  694.     while(txtpos[linelen] != NL)
  695.         linelen++;
  696.     linelen++; // Include the NL in the line length
  697.     linelen += sizeof(unsigned short)+sizeof(char); // Add space for the line number and line length
  698.  
  699.     // Now we have the number, add the line header.
  700.     txtpos -= 3;
  701.     *((unsigned short *)txtpos) = linenum;
  702.     txtpos[sizeof(LINENUM)] = linelen;
  703.  
  704.  
  705.     // Merge it into the rest of the program
  706.     start = findline();
  707.  
  708.     // If a line with that number exists, then remove it
  709.     if(start != program_end && *((LINENUM *)start) == linenum)
  710.     {
  711.         unsigned char *dest, *from;
  712.         unsigned tomove;
  713.  
  714.         from = start + start[sizeof(LINENUM)];
  715.         dest = start;
  716.  
  717.         tomove = program_end - from;
  718.         while( tomove > 0)
  719.         {
  720.             *dest = *from;
  721.             from++;
  722.             dest++;
  723.             tomove--;
  724.         }  
  725.         program_end = dest;
  726.     }
  727.  
  728.     if(txtpos[sizeof(LINENUM)+sizeof(char)] == NL) // If the line has no txt, it was just a delete
  729.         goto prompt;
  730.  
  731.  
  732.  
  733.     // Make room for the new line, either all in one hit or lots of little shuffles
  734.     while(linelen > 0)
  735.     {  
  736.         unsigned int tomove;
  737.         unsigned char *from,*dest;
  738.         unsigned int space_to_make;
  739.    
  740.         space_to_make = txtpos - program_end;
  741.  
  742.         if(space_to_make > linelen)
  743.             space_to_make = linelen;
  744.         newEnd = program_end+space_to_make;
  745.         tomove = program_end - start;
  746.  
  747.  
  748.         // Source and destination - as these areas may overlap we need to move bottom up
  749.         from = program_end;
  750.         dest = newEnd;
  751.         while(tomove > 0)
  752.         {
  753.             from--;
  754.             dest--;
  755.             *dest = *from;
  756.             tomove--;
  757.         }
  758.  
  759.         // Copy over the bytes into the new space
  760.         for(tomove = 0; tomove < space_to_make; tomove++)
  761.         {
  762.             *start = *txtpos;
  763.             txtpos++;
  764.             start++;
  765.             linelen--;
  766.         }
  767.         program_end = newEnd;
  768.     }
  769.     goto prompt;
  770.  
  771. unimplemented:
  772.     printmsg(unimplimentedmsg);
  773.     goto prompt;
  774.  
  775. badline:   
  776.     printmsg(badlinemsg);
  777.     goto prompt;
  778. invalidexpr:
  779.     printmsg(invalidexprmsg);
  780.     goto prompt;
  781. syntaxerror:
  782.     printmsg(syntaxmsg);
  783.     if(current_line != (void *)0)
  784.     {
  785.            unsigned char tmp = *txtpos;
  786.            if(*txtpos != NL)
  787.                 *txtpos = '^';
  788.            list_line = current_line;
  789.            printline();
  790.            *txtpos = tmp;
  791.     }
  792.     line_terminator();
  793.     goto prompt;
  794.  
  795. stackstuffed:  
  796.     printmsg(stackstuffedmsg);
  797.     goto warmstart;
  798. nomem: 
  799.     printmsg(nomemmsg);
  800.     goto warmstart;
  801.  
  802. run_next_statement:
  803.     while(*txtpos == ':')
  804.         txtpos++;
  805.     ignore_blanks();
  806.     if(*txtpos == NL)
  807.         goto execnextline;
  808.     goto interperateAtTxtpos;
  809.  
  810. direct:
  811.     txtpos = program_end+sizeof(LINENUM);
  812.     if(*txtpos == NL)
  813.         goto prompt;
  814.  
  815. interperateAtTxtpos:
  816.         if(breakcheck())
  817.         {
  818.           printmsg(breakmsg);
  819.           goto warmstart;
  820.         }
  821.  
  822.     scantable(keywords);
  823.     ignore_blanks();
  824.  
  825.     switch(table_index)
  826.     {
  827.         case KW_LIST:
  828.             goto list;
  829.         case KW_LOAD:
  830.             goto unimplemented; /////////////////
  831.         case KW_NEW:
  832.             if(txtpos[0] != NL)
  833.                 goto syntaxerror;
  834.             program_end = program_start;
  835.             goto prompt;
  836.         case KW_RUN:
  837.             current_line = program_start;
  838.             goto execline;
  839.         case KW_SAVE:
  840.             goto unimplemented; //////////////////////
  841.         case KW_NEXT:
  842.             goto next;
  843.         case KW_LET:
  844.             goto assignment;
  845.         case KW_IF:
  846.             {
  847.             short int val;
  848.             expression_error = 0;
  849.             val = expression();
  850.             if(expression_error || *txtpos == NL)
  851.                 goto invalidexpr;
  852.             if(val != 0)
  853.                 goto interperateAtTxtpos;
  854.             goto execnextline;
  855.             }
  856.         case KW_GOTO:
  857.             expression_error = 0;
  858.             linenum = expression();
  859.             if(expression_error || *txtpos != NL)
  860.                 goto invalidexpr;
  861.             current_line = findline();
  862.             goto execline;
  863.  
  864.         case KW_GOSUB:
  865.             goto gosub;
  866.         case KW_RETURN:
  867.             goto gosub_return;
  868.         case KW_REM:   
  869.             goto execnextline;  // Ignore line completely
  870.         case KW_FOR:
  871.             goto forloop;
  872.         case KW_INPUT:
  873.             goto input;
  874.         case KW_PRINT:
  875.             goto print;
  876.         case KW_POKE:
  877.             goto poke;
  878.         case KW_STOP:
  879.             // This is the easy way to end - set the current line to the end of program attempt to run it
  880.             if(txtpos[0] != NL)
  881.                 goto syntaxerror;
  882.             current_line = program_end;
  883.             goto execline;
  884.         case KW_BYE:
  885.             // Leave the basic interperater
  886.             return;
  887.         case KW_DEFAULT:
  888.             goto assignment;
  889.         default:
  890.             break;
  891.     }
  892.    
  893. execnextline:
  894.     if(current_line == (void *)0)       // Processing direct commands?
  895.         goto prompt;
  896.     current_line +=  current_line[sizeof(LINENUM)];
  897.  
  898. execline:
  899.     if(current_line == program_end) // Out of lines to run
  900.         goto warmstart;
  901.     txtpos = current_line+sizeof(LINENUM)+sizeof(char);
  902.     goto interperateAtTxtpos;
  903.  
  904. input:
  905.     {
  906.         unsigned char isneg=0;
  907.         unsigned char *temptxtpos;
  908.         short int *var;
  909.         ignore_blanks();
  910.         if(*txtpos < 'A' || *txtpos > 'Z')
  911.             goto syntaxerror;
  912.         var = ((short int *)variables_table)+*txtpos-'A';
  913.         txtpos++;
  914.         if(!check_statement_end())
  915.             goto syntaxerror;
  916. again:
  917.         temptxtpos = txtpos;
  918.         if(!getln('?'))
  919.             goto warmstart;
  920.  
  921.         // Go to where the buffer is read
  922.         txtpos = program_end+sizeof(LINENUM);
  923.         if(*txtpos == '-')
  924.         {
  925.             isneg = 1;
  926.             txtpos++;
  927.         }
  928.  
  929.         *var = 0;
  930.         do  {
  931.             *var = *var*10 + *txtpos - '0';
  932.             txtpos++;
  933.         } while(*txtpos >= '0' && *txtpos <= '9');
  934.         ignore_blanks();
  935.         if(*txtpos != NL)
  936.         {
  937.             printmsg(badinputmsg);
  938.             goto again;
  939.         }
  940.    
  941.         if(isneg)
  942.             *var = -*var;
  943.  
  944.         goto run_next_statement;
  945.     }
  946. forloop:
  947.     {
  948.         unsigned char var;
  949.         short int initial, step, terminal;
  950.  
  951.         if(*txtpos < 'A' || *txtpos > 'Z')
  952.             goto syntaxerror;
  953.         var = *txtpos;
  954.         txtpos++;
  955.        
  956.         scantable(relop_tab);
  957.         if(table_index != RELOP_EQ)
  958.             goto syntaxerror;
  959.  
  960.         expression_error = 0;
  961.         initial = expression();
  962.         if(expression_error)
  963.             goto invalidexpr;
  964.    
  965.         scantable(to_tab);
  966.         if(table_index != 0)
  967.             goto syntaxerror;
  968.    
  969.         terminal = expression();
  970.         if(expression_error)
  971.             goto invalidexpr;
  972.    
  973.         scantable(step_tab);
  974.         if(table_index == 0)
  975.         {
  976.             step = expression();
  977.             if(expression_error)
  978.                 goto invalidexpr;
  979.         }
  980.         else
  981.             step = 1;
  982.         if(!check_statement_end())
  983.             goto syntaxerror;
  984.  
  985.  
  986.         if(!expression_error && *txtpos == NL)
  987.         {
  988.             struct stack_for_frame *f;
  989.             if(sp + sizeof(struct stack_for_frame) < stack_limit)
  990.                 goto nomem;
  991.  
  992.             sp -= sizeof(struct stack_for_frame);
  993.             f = (struct stack_for_frame *)sp;
  994.             ((short int *)variables_table)[var-'A'] = initial;
  995.             f->frame_type = STACK_FOR_FLAG;
  996.             f->for_var = var;
  997.             f->terminal = terminal;
  998.             f->step     = step;
  999.             f->txtpos   = txtpos;
  1000.             f->current_line = current_line;
  1001.             goto run_next_statement;
  1002.         }
  1003.     }
  1004.     goto syntaxerror;
  1005.  
  1006. gosub:
  1007.     expression_error = 0;
  1008.     linenum = expression();
  1009.     if(expression_error)
  1010.         goto invalidexpr;
  1011.     if(!expression_error && *txtpos == NL)
  1012.     {
  1013.         struct stack_gosub_frame *f;
  1014.         if(sp + sizeof(struct stack_gosub_frame) < stack_limit)
  1015.             goto nomem;
  1016.  
  1017.         sp -= sizeof(struct stack_gosub_frame);
  1018.         f = (struct stack_gosub_frame *)sp;
  1019.         f->frame_type = STACK_GOSUB_FLAG;
  1020.         f->txtpos = txtpos;
  1021.         f->current_line = current_line;
  1022.         current_line = findline();
  1023.         goto execline;
  1024.     }
  1025.     goto syntaxerror;
  1026.  
  1027. next:
  1028.     // Fnd the variable name
  1029.     ignore_blanks();
  1030.     if(*txtpos < 'A' || *txtpos > 'Z')
  1031.         goto syntaxerror;
  1032.     txtpos++;
  1033.     if(!check_statement_end())
  1034.         goto syntaxerror;
  1035.    
  1036. gosub_return:
  1037.     // Now walk up the stack frames and find the frame we want, if present
  1038.     tempsp = sp;
  1039.     while(tempsp < memory+sizeof(memory)-1)
  1040.     {
  1041.         switch(tempsp[0])
  1042.         {
  1043.             case STACK_GOSUB_FLAG:
  1044.                 if(table_index == KW_RETURN)
  1045.                 {
  1046.                     struct stack_gosub_frame *f = (struct stack_gosub_frame *)tempsp;
  1047.                     current_line    = f->current_line;
  1048.                     txtpos          = f->txtpos;
  1049.                     sp += sizeof(struct stack_gosub_frame);
  1050.                     goto run_next_statement;
  1051.                 }
  1052.                 // This is not the loop you are looking for... so Walk back up the stack
  1053.                 tempsp += sizeof(struct stack_gosub_frame);
  1054.                 break;
  1055.             case STACK_FOR_FLAG:
  1056.                 // Flag, Var, Final, Step
  1057.                 if(table_index == KW_NEXT)
  1058.                 {
  1059.                     struct stack_for_frame *f = (struct stack_for_frame *)tempsp;
  1060.                     // Is the the variable we are looking for?
  1061.                     if(txtpos[-1] == f->for_var)
  1062.                     {
  1063.                         short int *varaddr = ((short int *)variables_table) + txtpos[-1] - 'A';
  1064.                         *varaddr = *varaddr + f->step;
  1065.                         // Use a different test depending on the sign of the step increment
  1066.                         if((f->step > 0 && *varaddr <= f->terminal) || (f->step < 0 && *varaddr >= f->terminal))
  1067.                         {
  1068.                             // We have to loop so don't pop the stack
  1069.                             txtpos = f->txtpos;
  1070.                             current_line = f->current_line;
  1071.                             goto run_next_statement;
  1072.                         }
  1073.                         // We've run to the end of the loop. drop out of the loop, popping the stack
  1074.                         sp = tempsp + sizeof(struct stack_for_frame);
  1075.                         goto run_next_statement;
  1076.                     }
  1077.                 }
  1078.                 // This is not the loop you are looking for... so Walk back up the stack
  1079.                 tempsp += sizeof(struct stack_for_frame);
  1080.                 break;
  1081.             default:
  1082.                 goto stackstuffed;
  1083.         }
  1084.     }
  1085.     // Didn't find the variable we've been looking for
  1086.     goto syntaxerror;
  1087.  
  1088. assignment:
  1089.     {
  1090.         short int value;
  1091.         short int *var;
  1092.  
  1093.         if(*txtpos < 'A' || *txtpos > 'Z')
  1094.             goto syntaxerror;
  1095.         var = (short int *)variables_table + *txtpos - 'A';
  1096.         txtpos++;
  1097.  
  1098.         ignore_blanks();
  1099.  
  1100.         if (*txtpos != '=')
  1101.             goto syntaxerror;
  1102.         txtpos++;
  1103.         ignore_blanks();
  1104.         expression_error = 0;
  1105.         value = expression();
  1106.         if(expression_error)
  1107.             goto invalidexpr;
  1108.         // Check that we are at the end of the statement
  1109.         if(!check_statement_end())
  1110.             goto syntaxerror;
  1111.         *var = value;
  1112.     }
  1113.     goto run_next_statement;
  1114. poke:
  1115.     {
  1116.         short int value;
  1117.         unsigned char *address;
  1118.  
  1119.         // Work out where to put it
  1120.         expression_error = 0;
  1121.         value = expression();
  1122.         if(expression_error)
  1123.             goto invalidexpr;
  1124.         address = (unsigned char *)value;
  1125.  
  1126.         // check for a comma
  1127.         ignore_blanks();
  1128.         if (*txtpos != ',')
  1129.             goto syntaxerror;
  1130.         txtpos++;
  1131.         ignore_blanks();
  1132.  
  1133.         // Now get the value to assign
  1134.         expression_error = 0;
  1135.         value = expression();
  1136.         if(expression_error)
  1137.             goto invalidexpr;
  1138. //      printf("Poke %p value %i\n",address, (unsigned char)value);
  1139.         // Check that we are at the end of the statement
  1140.         if(!check_statement_end())
  1141.             goto syntaxerror;
  1142.     }
  1143.     goto run_next_statement;
  1144.  
  1145. list:
  1146.     linenum = testnum(); // Retuns 0 if no line found.
  1147.  
  1148.     // Should be EOL
  1149.     if(txtpos[0] != NL)
  1150.         goto syntaxerror;
  1151.  
  1152.     // Find the line
  1153.     list_line = findline();
  1154.     while(list_line != program_end)
  1155.           printline();
  1156.     goto warmstart;
  1157.  
  1158. print:
  1159.     // If we have an empty list then just put out a NL
  1160.     if(*txtpos == ':' )
  1161.     {
  1162.         line_terminator();
  1163.         txtpos++;
  1164.         goto run_next_statement;
  1165.     }
  1166.     if(*txtpos == NL)
  1167.     {
  1168.         goto execnextline;
  1169.     }
  1170.  
  1171.     while(1)
  1172.     {
  1173.         ignore_blanks();
  1174.         if(print_quoted_string())
  1175.         {
  1176.             ;
  1177.         }
  1178.         else if(*txtpos == '"' || *txtpos == '\'')
  1179.             goto syntaxerror;
  1180.         else
  1181.         {
  1182.             short int e;
  1183.             expression_error = 0;
  1184.             e = expression();
  1185.             if(expression_error)
  1186.                 goto invalidexpr;
  1187.             printnum(e);
  1188.         }
  1189.  
  1190.         // At this point we have three options, a comma or a new line
  1191.         if(*txtpos == ',')
  1192.             txtpos++;   // Skip the comma and move onto the next
  1193.         else if(txtpos[0] == ';' && (txtpos[1] == NL || txtpos[1] == ':'))
  1194.         {
  1195.             txtpos++; // This has to be the end of the print - no newline
  1196.             break;
  1197.         }
  1198.         else if(check_statement_end())
  1199.         {
  1200.             line_terminator();  // The end of the print statement
  1201.             break;
  1202.         }
  1203.         else
  1204.             goto syntaxerror;  
  1205.     }
  1206.  
  1207.     goto run_next_statement;
  1208. }
  1209.  
  1210. /***************************************************************************/
  1211. static void line_terminator(void)
  1212. {
  1213.   outchar(NL);
  1214.   outchar(CR);
  1215. }
  1216.  
  1217.  
  1218. /***********************************************************/
  1219. static unsigned char breakcheck(void)
  1220. {
  1221.   if(chatPadUsed == true)
  1222.     if(chatPadChar == CTRLC)
  1223.       return 1;
  1224.   return 0;
  1225. }
  1226.  
  1227. /***********************************************************/
  1228. static void outchar(unsigned char c)
  1229. {
  1230.   lcdChar(c);
  1231. }
  1232.  
  1233. static void lcdChar(byte c)
  1234. {
  1235.     if(c != 13 and c != 10 and c != 8) { //Any other character
  1236.       screenMem[60+cursorX] = c;
  1237.       cursorX += 1;
  1238.       if(cursorX == 20)
  1239.       {
  1240.          cursorX = 0;
  1241.       }
  1242.     }
  1243.    
  1244.     if(c == 10 or cursorX == 20) { //Enter
  1245.        cursorX = 0;
  1246.        scrollLineUp();
  1247.     }
  1248.    
  1249.     if(c == 8) { //Backspace
  1250.       screenMem[60+cursorX] = 32;
  1251.       cursorX -= 1;  
  1252.   }
  1253. }
  1254.  
  1255. static void scrollLineUp()
  1256. {
  1257.    for(int i=0; i < 20; i++)
  1258.    {
  1259.        screenMem[0+i] = screenMem[20+i];
  1260.        screenMem[20+i] = screenMem[40+i];
  1261.        screenMem[40+i] = screenMem[60+i];
  1262.        screenMem[60+i] = 32;
  1263.    }
  1264.    drawScreen(80);
  1265. }
  1266.  
  1267. static void drawScreen(int upTo)
  1268. {
  1269.    lcd.setCursor(0, 0);
  1270.    for(int i=0; i < upTo; i++)
  1271.    {
  1272.        lcd.print(screenMem[i]);
  1273.    }
  1274.    lcd.setCursor(0, 0);
  1275. }
  1276.  
  1277. void clearScreen()
  1278. {
  1279.     cursorX = 0;
  1280.     for(int i = 0; i < 80; i++)
  1281.     {
  1282.       screenMem[i] = 32;
  1283.     }
  1284.     drawScreen(80);
  1285. }
  1286.  
  1287. void pollChatPad()
  1288. {
  1289.  //pad.poll();
  1290. }
  1291.  
  1292. void print_keys(Chatpad &pad, Chatpad::keycode_t code,
  1293.     Chatpad::eventtype_t type) {
  1294.   if (type == Chatpad::Down) {
  1295.     char a = pad.toAscii(code);
  1296.     if (a != 0)
  1297.    {
  1298.     chatPadUsed = true;
  1299.     chatPadChar = a;
  1300.    }
  1301.   }
  1302. }
  1303.  
  1304. void setup()
  1305. {
  1306.   // set up the LCD's number of columns and rows:
  1307.   lcd.begin(20, 4);
  1308.   chatPadUsed = false;
  1309.   pad.init(Serial, print_keys);
  1310. }
Advertisement
RAW Paste Data Copied
Advertisement