Subversion Repositories Kolibri OS

Rev

Rev 7141 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /* Tiny Basic Intermediate Language Interpreter -- 2004 July 19 */
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>  /* added 08 Oct 31 */
  6.  
  7. #include <conio.h>
  8.  
  9. char *ExplainErr(int code);
  10.  
  11.  
  12. /* Default input/output file names, if defined (omit otherwise)... */
  13. #define DefaultInputFile "TBasm.txt"
  14. #define DefaultOutputFile "TBout.txt"
  15.  
  16. /* File input/output function macros (adjust for C++ framework) */
  17. #define FileType           FILE*
  18. #define IoFileClose(fi)    fclose(fi)
  19. #define InFileChar(fi)     CfileRead(fi)
  20. #define OutFileChar(fi,ch) fputc(ch,fi)
  21. #define ScreenChar(ch)     con_printf("%c",ch)
  22. #define KeyInChar          (char)getchar()
  23. #define NeedsEcho          true
  24. #define BreakTest          Broken
  25.  
  26. /* File input/output function macros (Qt examples:) */
  27. /* #define FileType           QFile* */
  28. /* #define IoFileClose(fi)    fi->close() */
  29. /* #define InFileChar(fi)     (fi->atEnd()?'\0':fi->getch()) */
  30. /* #define OutFileChar(fi,ch) fi->putch(ch) */
  31.  
  32. char CfileRead(FileType fi) {   /* C file reader, returns '\0' on eof */
  33.   int chn = fgetc(fi);
  34.   if (chn == EOF) return '\0';
  35.   return (char)chn;} /* ~CfileRead */
  36.  
  37. /* Constants: */
  38.  
  39. #define aByte unsigned char
  40. #define CoreTop 65536 /* Core size */
  41. #define UserProg 32   /* Core address of front of Basic program */
  42. #define EndUser 34    /* Core address of end of stack/user space */
  43. #define EndProg 36    /* Core address of end of Basic program */
  44. #define GoStkTop 38   /* Core address of Gosub stack top */
  45. #define LinoCore 40   /* Core address of "Current BASIC line number" */
  46. #define ILPCcore 42   /* Core address of "IL Program Counter" */
  47. #define BPcore 44     /* Core address of "Basic Pointer" */
  48. #define SvPtCore 46   /* Core address of "Saved Pointer" */
  49. #define InLine 48     /* Core address of input line */
  50. #define ExpnStk 128   /* Core address of expression stack (empty) */
  51. #define TabHere 191   /* Core address of output line size, for tabs */
  52. #define WachPoint 255 /* Core address of debug watchpoint USR */
  53. #define ColdGo 256    /* Core address of nominal restart USR */
  54. #define WarmGo 259    /* Core address of nominal warm start USR */
  55. #define InchSub 262   /* Core address of nominal char input USR */
  56. #define OutchSub 265  /* Core address of nominal char output USR */
  57. #define BreakSub 268  /* Core address of nominal break test USR */
  58. #define DumpSub 273   /* Core address of debug core dump USR */
  59. #define PeekSub 276   /* Core address of nominal byte peek USR */
  60. #define Peek2Sub 277  /* Core address of nominal 2-byte peek USR */
  61. #define PokeSub 280   /* Core address of nominal byte poke USR */
  62. #define TrLogSub 283  /* Core address of debug trace log USR */
  63. #define BScode 271    /* Core address of backspace code */
  64. #define CanCode 272   /* Core address of line cancel code */
  65. #define ILfront 286   /* Core address of IL code address */
  66. #define BadOp 15      /* illegal op, default IL code */
  67.   /* Pascal habits die hard.. */
  68. #define true 1
  69. #define false 0
  70.  
  71. /* debugging stuff... */
  72. #define DEBUGON 1     /* 1 enables \t Debugging toggle, 0 disables */
  73. #define LOGSIZE 4096  /* how much to log */
  74. static int Debugging = 0;    /* >0 enables debug code */
  75. int DebugLog[LOGSIZE];       /* quietly logs recent activity */
  76. int LogHere = 0;             /* current index in DebugLog */
  77. int Watcher = 0, Watchee;    /* memory watchpoint */
  78.  
  79. /* Static/global data: */
  80. aByte Core[CoreTop];    /* everything goes in here */
  81. aByte DeCaps[128];      /* capitalization table */
  82. int Lino, ILPC;         /* current line #, IL program counter */
  83. int BP, SvPt;           /* current, saved TB parse pointer */
  84. int SubStk, ExpnTop;    /* stack pointers */
  85. int InLend, SrcEnd;     /* current input line & TB source end */
  86. int UserEnd;
  87. int ILend, XQhere;      /* end of IL code, start of execute loop */
  88. int Broken = false;     /* =true to stop execution or listing */
  89. FileType inFile = NULL; /* from option '-i' or user menu/button */
  90. FileType oFile = NULL;  /* from option '-o' or user menu/button */
  91.  
  92. /************************* Memory Utilities.. *************************/
  93.  
  94. void Poke2(int loc, int valu) {         /* store integer as two bytes */
  95.   Core[loc] = (aByte)((valu>>8)&255);         /* nominally Big-Endian */
  96.   Core[loc+1] = (aByte)(valu&255);} /* ~Poke2 */
  97.  
  98. int Peek2(int loc) {                  /* fetch integer from two bytes */
  99.   return ((int)Core[loc])*256 + ((int)Core[loc+1]);} /* ~Peek2 */
  100.  
  101. /************************** I/O Utilities... **************************/
  102.  
  103. void Ouch(char ch) {                         /* output char to stdout */
  104.   if (oFile != NULL) {                   /* there is an output file.. */
  105.     if (ch>=' ') OutFileChar(oFile,ch);
  106.     else if (ch == '\r') OutFileChar(oFile,'\n');}
  107.   if (ch=='\r') {
  108.     Core[TabHere] = 0;         /* keep count of how long this line is */
  109.     ScreenChar('\n');}
  110.   else if (ch>=' ') if (ch<='~') {  /* ignore non-print control chars */
  111.     Core[TabHere]++;
  112.     ScreenChar(ch);}} /* ~Ouch */
  113.  
  114. char Inch(void) {          /* read input character from stdin or file */
  115.   char ch;
  116.   if (inFile != NULL) {        /* there is a file to get input from.. */
  117.     ch = InFileChar(inFile);
  118.     if (ch == '\n') ch = '\r';
  119.     if (ch == '\0') {          /* switch over to console input at eof */
  120.       IoFileClose(inFile);
  121.       inFile = NULL;}
  122.     else {
  123.       Ouch(ch);         /* echo input to screen (but not output file) */
  124.       return ch;}}
  125.   ch = KeyInChar;                             /* get input from stdin */
  126.  
  127.   // ---Leency
  128.   // int __stdcall con_getch(void);
  129.   // For normal characters function returns ASCII-code.
  130.   // For extended characters (eg, Fx, and arrows), first function call
  131.   // returns 0 and second call returns the extended code (similar to the
  132.   // DOS-function input). Starting from version 7, after closing the
  133.   // console window, this function returns 0.
  134.   if (ch == 0) {
  135.       ch = (char)con_getch();
  136.       if (ch == 0) exit(0);  /* Kolibri specific - user closed window */
  137.       return 0;              /* Do not show anything on press extchar */
  138.   }
  139.  
  140.   if (ch==13) con_printf ("\n");
  141.   if (ch==8) con_printf ("\b ");
  142.   if (NeedsEcho) ScreenChar(ch);   /* alternative input may need this */
  143.   if (oFile != NULL) OutFileChar(oFile,ch); /* echo it to output file */
  144.   if (ch == '\n') {
  145.     ch = '\r';                     /* convert line end to TB standard */
  146.     Core[TabHere] = 0;}                          /* reset tab counter */
  147.   return ch;} /* ~Inch */
  148.  
  149. int StopIt(void) {return BreakTest;}   /* ~StopIt, .. not implemented */
  150.  
  151. void OutStr(char* theMsg) {         /* output a string to the console */
  152.   while (*theMsg != '\0') Ouch(*theMsg++);} /* ~OutStr */
  153.  
  154. void OutLn(void) {            /* terminate output line to the console */
  155.   OutStr("\r");} /* ~OutLn */
  156.  
  157. void OutInt(int theNum) {           /* output a number to the console */
  158.   if (theNum<0) {
  159.     Ouch('-');
  160.     theNum = -theNum;}
  161.   if (theNum>9) OutInt(theNum/10);
  162.   Ouch((char)(theNum%10+48));} /* ~OutInt */
  163.  
  164. /*********************** Debugging Utilities... ***********************/
  165.  
  166. void OutHex(int num, int nd) {  /* output a hex number to the console */
  167.   if (nd>1) OutHex(num>>4, nd-1);
  168.   num = num&15;
  169.   if (num>9) Ouch((char)(num+55));
  170.     else Ouch((char)(num+48));} /* ~OutHex */
  171.  
  172. void ShowSubs(void) {       /* display subroutine stack for debugging */
  173.   int ix;
  174.   OutLn(); OutStr(" [Stk "); OutHex(SubStk,5);
  175.   for (ix=SubStk; ix<UserEnd; ix++) {
  176.     OutStr(" ");
  177.     OutInt(Peek2(ix++));}
  178.   OutStr("]");} /* ~ShowSubs */
  179.  
  180. void ShowExSt(void) {       /* display expression stack for debugging */
  181.   int ix;
  182.   OutLn(); OutStr(" [Exp "); OutHex(ExpnTop,3);
  183.   if ((ExpnTop&1)==0) for (ix=ExpnTop; ix<ExpnStk; ix++) {
  184.     OutStr(" ");
  185.     OutInt((int)((short)Peek2(ix++)));}
  186.   else for (ix=ExpnTop; ix<ExpnStk; ix++) {
  187.     OutStr(".");
  188.     OutInt((int)Core[ix]);}
  189.   OutStr("]");} /* ~ShowExSt */
  190.  
  191. void ShowVars(int whom) {               /* display vars for debugging */
  192.   int ix, valu = 1, prior = 1;
  193.   if (whom==0) whom = 26; else {
  194.     whom = (whom>>1)&31;             /* whom is a specified var, or 0 */
  195.     valu = whom;}
  196.   OutLn(); OutStr("  [Vars");
  197.   for (ix=valu; ix<=whom; ix++) {  /* all non-zero vars, or else whom */
  198.     valu = (int)((short)Peek2(ix*2+ExpnStk));
  199.     if (valu==0) if (prior==0) continue;          /* omit multiple 0s */
  200.     prior = valu;
  201.     OutStr(" ");
  202.     Ouch((char)(ix+64));                             /* show var name */
  203.     OutStr("=");
  204.     OutInt(valu);}
  205.   OutStr("]");} /* ~ShowVars */
  206.  
  207. void ShoMemDump(int here, int nlocs) {     /* display hex memory dump */
  208.   int temp, thar = here&-16;
  209.   while (nlocs>0) {
  210.     temp = thar;
  211.     OutLn();
  212.     OutHex(here,4);
  213.     OutStr(": ");
  214.     while (thar<here) {OutStr("   "); thar++;}
  215.     do {
  216.       OutStr(" ");
  217.       if (nlocs-- >0) OutHex(Core[here],2);
  218.         else OutStr("  ");}
  219.       while (++here%16 !=0);
  220.     OutStr("  ");
  221.     while (temp<thar) {OutStr(" "); temp++;}
  222.     while (thar<here) {
  223.       if (nlocs<0) if ((thar&15) >= nlocs+16) break;
  224.       temp = Core[thar++];
  225.       if (temp == (int)'\r') Ouch('\\');
  226.       else if (temp<32) Ouch('`');
  227.       else if (temp>126) Ouch('~');
  228.         else Ouch((char)temp);}}
  229.   OutLn();} /* ~ShoMemDump */
  230.  
  231. void ShoLogVal(int item) {   /* format & output one activity log item */
  232.   int valu = DebugLog[item];
  233.   OutLn();
  234.   if (valu < -65536) {                         /* store to a variable */
  235.     Ouch((char)(((valu>>17)&31)+64));
  236.     OutStr("=");
  237.     OutInt((valu&0x7FFF)-(valu&0x8000));}
  238.   else if (valu < -32768) {                                /* error # */
  239.     OutStr("Err ");
  240.     OutInt(-valu-32768);}
  241.   else if (valu<0) {                 /* only logs IL sequence changes */
  242.     OutStr("  IL+");
  243.     OutHex(-Peek2(ILfront)-valu,3);}
  244.   else if (valu<65536) {                          /* TinyBasic line # */
  245.     OutStr("#");
  246.     OutInt(valu);}
  247.   else {                                          /* poke memory byte */
  248.     OutStr("!");
  249.     OutHex(valu,4);
  250.     OutStr("=");
  251.     OutInt(valu>>16);}} /* ~ShoLogVal */
  252.  
  253. void ShowLog(void) {            /* display activity log for debugging */
  254.   int ix;
  255.   OutLn();
  256.   OutStr("*** Activity Log @ ");
  257.   OutInt(LogHere);
  258.   OutStr(" ***");
  259.   if (LogHere >= LOGSIZE)   /* circular, show only last 4K activities */
  260.     for (ix=(LogHere&(LOGSIZE-1)); ix<LOGSIZE; ix++) ShoLogVal(ix);
  261.   for (ix=0; ix<(LogHere&(LOGSIZE-1)); ix++) ShoLogVal(ix);
  262.   OutLn();
  263.   OutStr("*****");
  264.   OutLn();} /* ~ShowLog */
  265.  
  266. void LogIt(int valu) {          /* insert this valu into activity log */
  267.   DebugLog[(LogHere++)&(LOGSIZE-1)] = valu;}
  268.  
  269. /************************ Utility functions... ************************/
  270.  
  271. void WarmStart(void) {                 /* initialize existing program */
  272.   UserEnd = Peek2(EndUser);
  273.   SubStk = UserEnd;            /* empty subroutine, expression stacks */
  274.   Poke2(GoStkTop,SubStk);
  275.   ExpnTop = ExpnStk;
  276.   Lino = 0;                                        /* not in any line */
  277.   ILPC = 0;                                      /* start IL at front */
  278.   SvPt = InLine;
  279.   BP = InLine;
  280.   Core[BP] = 0;
  281.   Core[TabHere] = 0;
  282.   InLend = InLine;} /* ~WarmStart */
  283.  
  284. void ColdStart(void) {                 /* initialize program to empty */
  285.   if (Peek2(ILfront) != ILfront+2) ILend = Peek2(ILfront)+0x800;
  286.   Poke2(UserProg,(ILend+255)&-256);   /* start Basic shortly after IL */
  287.   if (CoreTop>65535) {
  288.     Poke2(EndUser,65534);
  289.     Poke2(65534,0xDEAD);}
  290.   else Poke2(EndUser,CoreTop);
  291.   WarmStart();
  292.   SrcEnd = Peek2(UserProg);
  293.   Poke2(SrcEnd++,0);
  294.   Poke2(EndProg,++SrcEnd);} /* ~ColdStart */
  295.  
  296. void TBerror(void) {                      /* report interpreter error */
  297.   if (ILPC == 0) return;                       /* already reported it */
  298.   OutLn();
  299.   LogIt(-ILPC-32768);
  300.   OutStr("Tiny Basic error #");          /* IL address is the error # */
  301.   OutInt(ILPC-Peek2(ILfront));
  302.   // siemargl - add textual explain
  303.   OutStr(" - ");
  304.   OutStr(ExplainErr(ILPC-Peek2(ILfront)));
  305.  
  306.   if (Lino>0) {                          /* Lino=0 if in command line */
  307.     OutStr(" at line ");
  308.     OutInt(Lino);}
  309.   OutLn();
  310.   if (Debugging>0) {                /* some extra info if debugging.. */
  311.     ShowSubs();
  312.     ShowExSt();
  313.     ShowVars(0);
  314.     OutStr(" [BP=");
  315.     OutHex(BP,4);
  316.     OutStr(", TB@");
  317.     OutHex(Peek2(UserProg),4);
  318.     OutStr(", IL@");
  319.     OutHex(Peek2(ILfront),4);
  320.     OutStr("]");
  321.     ShoMemDump((BP-30)&-16,64);}
  322.   Lino = 0;                           /* restart interpreter at front */
  323.   ExpnTop = ExpnStk;                   /* with empty expression stack */
  324.   ILPC = 0;       /* cheap error test; interp reloads it from ILfront */
  325.   BP = InLine;} /* ~TBerror */
  326.  
  327. void PushSub(int valu) {               /* push value onto Gosub stack */
  328.   if (SubStk<=SrcEnd) TBerror(); /* overflow: bumped into program end */
  329.   else {
  330.     SubStk = SubStk-2;
  331.     Poke2(GoStkTop,SubStk);
  332.     Poke2(SubStk,valu);}
  333.   if (Debugging>0) ShowSubs();} /* ~PushSub */
  334.  
  335. int PopSub(void) {                       /* pop value off Gosub stack */
  336.   if (SubStk>=Peek2(EndUser)-1) {   /* underflow (nothing in stack).. */
  337.     TBerror();
  338.     return -1;}
  339.   else {
  340.       if (Debugging>1) ShowSubs();
  341.     SubStk = SubStk+2;
  342.     Poke2(GoStkTop,SubStk);
  343.     return Peek2(SubStk-2);}} /* ~PopSub */
  344.  
  345. void PushExBy(int valu) {          /* push byte onto expression stack */
  346.   if (ExpnTop<=InLend) TBerror(); /* overflow: bumped into input line */
  347.     else Core[--ExpnTop] = (aByte)(valu&255);
  348.   if (Debugging>0) ShowExSt();} /* ~PushExBy */
  349.  
  350. int PopExBy(void) {                  /* pop byte off expression stack */
  351.   if (ExpnTop<ExpnStk) return (int)Core[ExpnTop++];
  352.   TBerror();                          /* underflow (nothing in stack) */
  353.   return -1;} /* ~PopExBy */
  354.  
  355. void PushExInt(int valu) {      /* push integer onto expression stack */
  356.   ExpnTop = ExpnTop-2;
  357.   if (ExpnTop<InLend) TBerror();  /* overflow: bumped into input line */
  358.     else Poke2(ExpnTop,valu);
  359.   if (Debugging>0) ShowExSt();} /* ~PushExInt */
  360.  
  361. int PopExInt(void) {              /* pop integer off expression stack */
  362.   if (++ExpnTop<ExpnStk) return (int)((short)Peek2((ExpnTop++)-1));
  363.   TBerror();    /* underflow (nothing in stack) */
  364.   return -1;} /* ~PopExInt */
  365.  
  366. int DeHex(char* txt, int ndigs) {                /* decode hex -> int */
  367.   int num = 0;
  368.   char ch = ' ';
  369.   while (ch<'0')                              /* first skip to num... */
  370.     if (ch == '\0') return -1; else ch = DeCaps[((int)*txt++)&127];
  371.   if (ch>'F' || ch>'9' && ch<'A') return -1;               /* not hex */
  372.   while ((ndigs--) >0) {                 /* only get requested digits */
  373.     if (ch<'0' || ch>'F') return num;              /* not a hex digit */
  374.     if (ch>='A') num = num*16-55+((int)ch);      /* A-F */
  375.     else if (ch<='9') num = num*16-48+((int)ch); /* 0-9 */
  376.       else return num;          /* something in between, i.e. not hex */
  377.     ch = DeCaps[((int)*txt++)&127];}
  378.   return num;} /* ~DeHex */
  379.  
  380. int SkipTo(int here, char fch) {     /* search for'd past next marker */
  381.   while (true) {
  382.     char ch = (char)Core[here++];                /* look at next char */
  383.     if (ch == fch) return here;                             /* got it */
  384.     if (ch == '\0') return --here;}} /* ~SkipTo */
  385.  
  386. int FindLine(int theLine) {         /* find theLine in TB source code */
  387.   int ix;
  388.   int here = Peek2(UserProg);                       /* start at front */
  389.   while (true) {
  390.     ix = Peek2(here++);
  391.     if (theLine<=ix || ix==0) return --here;  /* found it or overshot */
  392.     here = SkipTo(++here, '\r');}         /* skip to end of this line */
  393.   } /* ~FindLine */
  394.  
  395. void GoToLino(void) {     /* find line # Lino and set BP to its front */
  396.   int here;
  397.   if (Lino <= 0) {              /* Lino=0 is just command line (OK).. */
  398.     BP = InLine;
  399.     if (DEBUGON>0) LogIt(0);
  400.     return;}
  401.   if (DEBUGON>0) LogIt(Lino);
  402.   if (Debugging>0) {OutStr(" [#"); OutInt(Lino); OutStr("]");}
  403.   BP = FindLine(Lino);                  /* otherwise try to find it.. */
  404.   here = Peek2(BP++);
  405.   if (here==0) TBerror();               /* ran off the end, error off */
  406.   else if (Lino != here) TBerror();                      /* not there */
  407.     else BP++;} /* ~GoToLino */                             /* got it */
  408.  
  409. void ListIt(int frm, int too) {            /* list the stored program */
  410.   char ch;
  411.   int here;
  412.   if (frm==0) {           /* 0,0 defaults to all; n,0 defaults to n,n */
  413.     too = 65535;
  414.     frm = 1;}
  415.   else if (too==0) too = frm;
  416.   here = FindLine(frm);                   /* try to find first line.. */
  417.   while (!StopIt()) {
  418.     frm = Peek2(here++);             /* get this line's # to print it */
  419.     if (frm>too || frm==0) break;
  420.     here++;
  421.     OutInt(frm);
  422.     Ouch(' ');
  423.     do {                                            /* print the text */
  424.       ch = (char)Core[here++];
  425.       Ouch(ch);}
  426.       while (ch>'\r');}} /* ~ListIt */
  427.  
  428. void ConvtIL(char* txt) {                 /* convert & load TBIL code */
  429.   int valu;
  430.   ILend = ILfront+2;
  431.   Poke2(ILfront,ILend);    /* initialize pointers as promised in TBEK */
  432.   Poke2(ColdGo+1,ILend);
  433.   Core[ILend] = (aByte)BadOp;   /* illegal op, in case nothing loaded */
  434.   if (txt == NULL) return;
  435.   while (*txt != '\0') {                            /* get the data.. */
  436.     while (*txt > '\r') txt++;               /* (no code on 1st line) */
  437.     if (*txt++ == '\0') break;                      /* no code at all */
  438.     while (*txt > ' ') txt++;                    /* skip over address */
  439.     if (*txt++ == '\0') break;
  440.     while (true) {
  441.       valu = DeHex(txt++, 2);                           /* get a byte */
  442.       if (valu<0) break;                      /* no more on this line */
  443.       Core[ILend++] = (aByte)valu;      /* insert this byte into code */
  444.       txt++;}}
  445.   XQhere = 0;                        /* requires new XQ to initialize */
  446.   Core[ILend] = 0;} /* ~ConvtIL */
  447.  
  448. void LineSwap(int here) {   /* swap SvPt/BP if here is not in InLine  */
  449.   if (here<InLine || here>=InLend) {
  450.     here = SvPt;
  451.     SvPt = BP;
  452.     BP = here;}
  453.   else SvPt = BP;} /* ~LineSwap */
  454.  
  455. /************************** Main Interpreter **************************/
  456.  
  457. void Interp(void) {
  458.   char ch;    /* comments from TinyBasic Experimenter's Kit, pp.15-21 */
  459.   int op, ix, here, chpt;                                    /* temps */
  460.   Broken = false;          /* initialize this for possible later test */
  461.   while (true) {
  462.     if (StopIt()) {
  463.       Broken = false;
  464.       OutLn();
  465.       OutStr("*** User Break ***");
  466.       TBerror();}
  467.     if (ILPC==0) {
  468.       ILPC = Peek2(ILfront);
  469.       if (DEBUGON>0) LogIt(-ILPC);
  470.       if (Debugging>0) {
  471.         OutLn(); OutStr("[IL="); OutHex(ILPC,4); OutStr("]");}}
  472.     if (DEBUGON>0) if (Watcher>0) {             /* check watchpoint.. */
  473.       if (((Watchee<0) && (Watchee+256+(int)Core[Watcher]) !=0)
  474.           || ((Watchee >= 0) && (Watchee==(int)Core[Watcher]))) {
  475.         OutLn();
  476.         OutStr("*** Watched ");
  477.         OutHex(Watcher,4);
  478.         OutStr(" = ");
  479.         OutInt((int)Core[Watcher]);
  480.         OutStr(" *** ");
  481.         Watcher = 0;
  482.         TBerror();
  483.         continue;}}
  484.     op = (int)Core[ILPC++];
  485.       if (Debugging>0) {
  486.         OutLn(); OutStr("[IL+"); OutHex(ILPC-Peek2(ILfront)-1,3);
  487.         OutStr("="); OutHex(op,2); OutStr("]");}
  488.     switch (op>>5) {
  489.     default: switch (op) {
  490.       case 15:
  491.         TBerror();
  492.         return;
  493.  
  494. /* SX n    00-07   Stack Exchange. */
  495. /*                 Exchange the top byte of computational stack with  */
  496. /* that "n" bytes into the stack. The top/left byte of the stack is   */
  497. /* considered to be byte 0, so SX 0 does nothing.                     */
  498.       case 1: case 2: case 3: case 4: case 5: case 6: case 7:
  499.         if (ExpnTop+op>=ExpnStk) {       /* swap is below stack depth */
  500.           TBerror();
  501.           return;}
  502.         ix = (int)Core[ExpnTop];
  503.         Core[ExpnTop] = Core[ExpnTop+op];
  504.         Core[ExpnTop+op] = (aByte)ix;
  505.         if (Debugging>0) ShowExSt();
  506.         break;
  507.  
  508. /* LB n    09nn    Push Literal Byte onto Stack.                      */
  509. /*                 This adds one byte to the expression stack, which  */
  510. /* is the second byte of the instruction. An error stop will occur if */
  511. /* the stack overflows. */
  512.       case 9:
  513.         PushExBy((int)Core[ILPC++]);                  /* push IL byte */
  514.         break;
  515.  
  516. /* LN n    0Annnn  Push Literal Number.                               */
  517. /*                 This adds the following two bytes to the           */
  518. /* computational stack, as a 16-bit number. Stack overflow results in */
  519. /* an error stop. Numbers are assumed to be Big-Endian.               */
  520.       case 10:
  521.         PushExInt(Peek2(ILPC++));              /* get next 2 IL bytes */
  522.         ILPC++;
  523.         break;
  524.  
  525. /* DS      0B      Duplicate Top Number (two bytes) on Stack.         */
  526. /*                 An error stop will occur if there are less than 2  */
  527. /* bytes (1 int) on the expression stack or if the stack overflows.   */
  528.       case 11:
  529.         op = ExpnTop;
  530.         ix = PopExInt();
  531.         if (ILPC == 0) break;                            /* underflow */
  532.         ExpnTop = op;
  533.         PushExInt(ix);
  534.         break;
  535.  
  536. /* SP      0C      Stack Pop.                                         */
  537. /*                 The top two bytes are removed from the expression  */
  538. /* stack and discarded. Underflow results in an error stop.           */
  539.       case 12:
  540.         ix = PopExInt();
  541.           if (Debugging>0) ShowExSt();
  542.         break;
  543.  
  544. /* SB      10      Save BASIC Pointer.                                */
  545. /*                 If BASIC pointer is pointing into the input line   */
  546. /* buffer, it is copied to the Saved Pointer; otherwise the two       */
  547. /* pointers are exchanged.                                            */
  548.       case 16:
  549.         LineSwap(BP);
  550.         break;
  551.  
  552. /* RB      11      Restore BASIC Pointer.                             */
  553. /*                 If the Saved Pointer points into the input line    */
  554. /* buffer, it is replaced by the value in the BASIC pointer;          */
  555. /* otherwise the two pointers are exchanged.                          */
  556.       case 17:
  557.         LineSwap(SvPt);
  558.         break;
  559.  
  560. /* FV      12      Fetch Variable.                                    */
  561. /*                 The top byte of the computational stack is used to */
  562. /* index into Page 00. It is replaced by the two bytes fetched. Error */
  563. /* stops occur with stack overflow or underflow.                      */
  564.       case 18:
  565.         op = PopExBy();
  566.         if (ILPC != 0) PushExInt(Peek2(op));
  567.           if (Debugging>1) ShowVars(op);
  568.         break;
  569.  
  570. /* SV      13      Store Variable.                                    */
  571. /*                 The top two bytes of the computational stack are   */
  572. /* stored into memory at the Page 00 address specified by the third   */
  573. /* byte on the stack. All three bytes are deleted from the stack.     */
  574. /* Underflow results in an error stop.                                */
  575.       case 19:
  576.         ix = PopExInt();
  577.         op = PopExBy();
  578.         if (ILPC == 0) break;
  579.         Poke2(op,ix);
  580.           if (DEBUGON>0) LogIt((ix&0xFFFF)+((op-256)<<16));
  581.           if (Debugging>0) {ShowVars(op); if (Debugging>1) ShowExSt();}
  582.         break;
  583.  
  584. /* GS      14      GOSUB Save.                                        */
  585. /*                 The current BASIC line number is pushed            */
  586. /* onto the BASIC region of the control stack. It is essential that   */
  587. /* the IL stack be empty for this to work properly but no check is    */
  588. /* made for that condition. An error stop occurs on stack overflow.   */
  589.       case 20:
  590.         PushSub(Lino);                   /* push line # (possibly =0) */
  591.         break;
  592.  
  593. /* RS      15      Restore Saved Line.                                */
  594. /*                 Pop the top two bytes off the BASIC region of the  */
  595. /* control stack, making them the current line number. Set the BASIC  */
  596. /* pointer at the beginning of that line. Note that this is the line  */
  597. /* containing the GOSUB which caused the line number to be saved. As  */
  598. /* with the GS opcode, it is essential that the IL region of the      */
  599. /* control stack be empty. If the line number popped off the stack    */
  600. /* does not correspond to a line in the BASIC program an error stop   */
  601. /* occurs. An error stop also results from stack underflow.           */
  602.       case 21:
  603.         Lino = PopSub();         /* get line # (possibly =0) from pop */
  604.         if (ILPC != 0) GoToLino() ;             /* stops run if error */
  605.         break;
  606.  
  607. /* GO      16      GOTO.                                              */
  608. /*                 Make current the BASIC line whose line number is   */
  609. /* equal to the value of the top two bytes in the expression stack.   */
  610. /* That is, the top two bytes are popped off the computational stack, */
  611. /* and the BASIC program is searched until a matching line number is  */
  612. /* found. The BASIC pointer is then positioned at the beginning of    */
  613. /* that line and the RUN mode flag is turned on. Stack underflow and  */
  614. /* non-existent BASIC line result in error stops.                     */
  615.       case 22:
  616.         ILPC = XQhere;                /* the IL assumes an implied NX */
  617.         if (DEBUGON>0) LogIt(-ILPC);
  618.         Lino = PopExInt();
  619.         if (ILPC != 0) GoToLino() ;             /* stops run if error */
  620.         break;
  621.  
  622. /* NE      17      Negate (two's complement).                         */
  623. /*                 The number in the top two bytes of the expression  */
  624. /* stack is replaced with its negative.                               */
  625.       case 23:
  626.         ix = PopExInt();
  627.         if (ILPC != 0) PushExInt(-ix);
  628.         break;
  629.  
  630. /* AD      18      Add.                                               */
  631. /*                 Add the two numbers represented by the top four    */
  632. /* bytes of the expression stack, and replace them with the two-byte  */
  633. /* sum. Stack underflow results in an error stop.                     */
  634.       case 24:
  635.         ix = PopExInt();
  636.         op = PopExInt();
  637.         if (ILPC != 0) PushExInt(op+ix);
  638.         break;
  639.  
  640. /* SU      19      Subtract.                                          */
  641. /*                 Subtract the two-byte number on the top of the     */
  642. /* expression stack from the next two bytes and replace the 4 bytes   */
  643. /* with the two-byte difference.                                      */
  644.       case 25:
  645.         ix = PopExInt();
  646.         op = PopExInt();
  647.         if (ILPC != 0) PushExInt(op-ix);
  648.         break;
  649.  
  650. /* MP      1A      Multiply.                                          */
  651. /*                 Multiply the two numbers represented by the top 4  */
  652. /* bytes of the computational stack, and replace them with the least  */
  653. /* significant 16 bits of the product. Stack underflow is possible.   */
  654.       case 26:
  655.         ix = PopExInt();
  656.         op = PopExInt();
  657.         if (ILPC != 0) PushExInt(op*ix);
  658.         break;
  659.  
  660. /* DV      1B      Divide.                                            */
  661. /*                 Divide the number represented by the top two bytes */
  662. /* of the computational stack into that represented by the next two.  */
  663. /* Replace the 4 bytes with the quotient and discard the remainder.   */
  664. /* This is a signed (two's complement) integer divide, resulting in a */
  665. /* signed integer quotient. Stack underflow or attempted division by  */
  666. /* zero result in an error stop. */
  667.       case 27:
  668.         ix = PopExInt();
  669.         op = PopExInt();
  670.         if (ix == 0) TBerror();                      /* divide by 0.. */
  671.         else if (ILPC != 0) PushExInt(op/ix);
  672.         break;
  673.  
  674. /* CP      1C      Compare.                                           */
  675. /*                 The number in the top two bytes of the expression  */
  676. /* stack is compared to (subtracted from) the number in the 4th and   */
  677. /* fifth bytes of the stack, and the result is determined to be       */
  678. /* Greater, Equal, or Less. The low three bits of the third byte mask */
  679. /* a conditional skip in the IL program to test these conditions; if  */
  680. /* the result corresponds to a one bit, the next byte of the IL code  */
  681. /* is skipped and not executed. The three bits correspond to the      */
  682. /* conditions as follows:                                             */
  683. /*         bit 0   Result is Less                                     */
  684. /*         bit 1   Result is Equal                                    */
  685. /*         bit 2   Result is Greater                                  */
  686. /* Whether the skip is taken or not, all five bytes are deleted from  */
  687. /* the stack. This is a signed (two's complement) comparison so that  */
  688. /* any positive number is greater than any negative number. Multiple  */
  689. /* conditions, such as greater-than-or-equal or unequal (i.e.greater- */
  690. /* than-or-less-than), may be tested by forming the condition mask    */
  691. /* byte of the sum of the respective bits. In particular, a mask byte */
  692. /* of 7 will force an unconditional skip and a mask byte of 0 will    */
  693. /* force no skip. The other 5 bits of the control byte are ignored.   */
  694. /* Stack underflow results in an error stop.                          */
  695.       case 28:
  696.         ix = PopExInt();
  697.         op = PopExBy();
  698.         ix = PopExInt()-ix;                         /* <0 or =0 or >0 */
  699.         if (ILPC == 0) return;                         /* underflow.. */
  700.         if (ix<0) ix = 1;
  701.         else if (ix>0) ix = 4;              /* choose the bit to test */
  702.           else ix = 2;
  703.         if ((ix&op)>0) ILPC++;           /* skip next IL op if bit =1 */
  704.           if (Debugging>0) ShowExSt();
  705.         break;
  706.  
  707. /* NX      1D      Next BASIC Statement.                              */
  708. /*                 Advance to next line in the BASIC program, if in   */
  709. /* RUN mode, or restart the IL program if in the command mode. The    */
  710. /* remainder of the current line is ignored. In the Run mode if there */
  711. /* is another line it becomes current with the pointer positioned at  */
  712. /* its beginning. At this time, if the Break condition returns true,  */
  713. /* execution is aborted and the IL program is restarted after         */
  714. /* printing an error message. Otherwise IL execution proceeds from    */
  715. /* the saved IL address (see the XQ instruction). If there are no     */
  716. /* more BASIC statements in the program an error stop occurs.         */
  717.       case 29:
  718.         if (Lino == 0) ILPC = 0;
  719.         else {
  720.           BP = SkipTo(BP, '\r');          /* skip to end of this line */
  721.           Lino = Peek2(BP++);                           /* get line # */
  722.           if (Lino==0) {                           /* ran off the end */
  723.             TBerror();
  724.             break;}
  725.           else BP++;
  726.           ILPC = XQhere;          /* restart at saved IL address (XQ) */
  727.           if (DEBUGON>0) LogIt(-ILPC);}
  728.         if (DEBUGON>0) LogIt(Lino);
  729.         if (Debugging>0) {OutStr(" [#"); OutInt(Lino); OutStr("]");}
  730.         break;
  731.  
  732. /* LS      1F      List The Program.                                  */
  733. /*                 The expression stack is assumed to have two 2-byte */
  734. /* numbers. The top number is the line number of the last line to be  */
  735. /* listed, and the next is the line number of the first line to be    */
  736. /* listed. If the specified line numbers do not exist in the program, */
  737. /* the next available line (i.e. with the next higher line number) is */
  738. /* assumed instead in each case. If the last line to be listed comes  */
  739. /* before the first, no lines are listed. If Break condition comes    */
  740. /* true during a List operation, the remainder of the listing is      */
  741. /* aborted. Zero is not a valid line number, and an error stop occurs */
  742. /* if either line number specification is zero. The line number       */
  743. /* specifications are deleted from the stack.                         */
  744.       case 31:
  745.         op = 0;
  746.         ix = 0;          /* The IL seems to assume we can handle zero */
  747.         while (ExpnTop<ExpnStk) {   /* or more numbers, so get them.. */
  748.           op = ix;
  749.           ix = PopExInt();}       /* get final line #, then initial.. */
  750.         if (op<0 || ix<0) TBerror();
  751.           else ListIt(ix,op);
  752.         break;
  753.  
  754. /* PN      20      Print Number.                                      */
  755. /*                 The number represented by the top two bytes of the */
  756. /* expression stack is printed in decimal with leading zero           */
  757. /* suppression. If it is negative, it is preceded by a minus sign     */
  758. /* and the magnitude is printed. Stack underflow is possible.         */
  759.       case 32:
  760.         ix = PopExInt();
  761.         if (ILPC != 0) OutInt(ix);
  762.         break;
  763.  
  764. /* PQ      21      Print BASIC String.                                */
  765. /*                 The ASCII characters beginning with the current    */
  766. /* position of BASIC pointer are printed on the console. The string   */
  767. /* to be printed is terminated by quotation mark ("), and the BASIC   */
  768. /* pointer is left at the character following the terminal quote. An  */
  769. /* error stop occurs if a carriage return is imbedded in the string.  */
  770.       case 33:
  771.         while (true) {
  772.           ch = (char)Core[BP++];
  773.           if (ch=='\"') break;                 /* done on final quote */
  774.           if (ch<' ') {      /* error if return or other control char */
  775.             TBerror();
  776.             break;}
  777.           Ouch(ch);}                                      /* print it */
  778.         break;
  779.  
  780. /* PT      22      Print Tab.                                         */
  781. /*                 Print one or more spaces on the console, ending at */
  782. /* the next multiple of eight character positions (from the left      */
  783. /* margin).                                                           */
  784.       case 34:
  785.         do {Ouch(' ');} while (Core[TabHere]%8>0);
  786.         break;
  787.  
  788. /* NL      23      New Line.                                          */
  789. /*                 Output a carriage-return-linefeed sequence to the  */
  790. /* console.                                                           */
  791.       case 35:
  792.         Ouch('\r');
  793.         break;
  794.  
  795. /* PC "xxxx"  24xxxxxxXx   Print Literal String.                      */
  796. /*                         The ASCII string follows opcode and its    */
  797. /* last byte has the most significant bit set to one.                 */
  798.       case 36:
  799.         do {
  800.           ix = (int)Core[ILPC++];
  801.           Ouch((char)(ix&127));          /* strip high bit for output */
  802.           } while ((ix&128)==0);
  803.         break;
  804.  
  805. /* GL      27      Get Input Line.                                    */
  806. /*                 ASCII characters are accepted from console input   */
  807. /* to fill the line buffer. If the line length exceeds the available  */
  808. /* space, the excess characters are ignored and bell characters are   */
  809. /* output. The line is terminated by a carriage return. On completing */
  810. /* one line of input, the BASIC pointer is set to point to the first  */
  811. /* character in the input line buffer, and a carriage-return-linefeed */
  812. /* sequence is [not] output.                                          */
  813.       case 39:
  814.         InLend = InLine;
  815.         while (true) {               /* read input line characters... */
  816.           ch = Inch();
  817.           if (!ch) continue;
  818.           else if (ch=='\r') break;                     /* end of the line */
  819.           else if (ch=='\t') {
  820.             Debugging = (Debugging+DEBUGON)&1;  /* maybe toggle debug */
  821.             ch = ' ';}                       /* convert tabs to space */
  822.           else if (ch==(char)Core[BScode]) {        /* backspace code */
  823.             if (InLend>InLine) InLend--;    /* assume console already */
  824.             else {   /* backing up over front of line: just kill it.. */
  825.               Ouch('\r');
  826.               break;}}
  827.           else if (ch==(char)Core[CanCode]) {     /* cancel this line */
  828.             InLend = InLine;
  829.             Ouch('\r');                /* also start a new input line */
  830.             break;}
  831.           else if (ch<' ') continue;   /* ignore non-ASCII & controls */
  832.           else if (ch>'~') continue;
  833.           if (InLend>ExpnTop-2) continue;    /* discard overrun chars */
  834.                   /* Siemargl fix for not so smart consoles*/
  835.                   if (ch != (char)Core[BScode])        
  836.                           Core[InLend++] = (aByte)ch;
  837.                   }  /* insert this char in buffer */
  838.         while (InLend>InLine && Core[InLend-1] == ' ')
  839.           InLend--;                  /* delete excess trailing spaces */
  840.         Core[InLend++] = (aByte) '\r';  /* insert final return & null */
  841.         Core[InLend] = 0;
  842.         BP = InLine;
  843.         break;
  844.  
  845. /* IL      2A      Insert BASIC Line.                                 */
  846. /*                 Beginning with the current position of the BASIC   */
  847. /* pointer and continuing to the [end of it], the line is inserted    */
  848. /* into the BASIC program space; for a line number, the top two bytes */
  849. /* of the expression stack are used. If this number matches a line    */
  850. /* already in the program it is deleted and the new one replaces it.  */
  851. /* If the new line consists of only a carriage return, it is not      */
  852. /* inserted, though any previous line with the same number will have  */
  853. /* been deleted. The lines are maintained in the program space sorted */
  854. /* by line number. If the new line to be inserted is a different size */
  855. /* than the old line being replaced, the remainder of the program is  */
  856. /* shifted over to make room or to close up the gap as necessary. If  */
  857. /* there is insufficient memory to fit in the new line, the program   */
  858. /* space is unchanged and an error stop occurs (with the IL address   */
  859. /* decremented). A normal error stop occurs on expression stack       */
  860. /* underflow or if the number is zero, which is not a valid line      */
  861. /* number. After completing the insertion, the IL program is          */
  862. /* restarted in the command mode.                                     */
  863.       case 42:
  864.         Lino = PopExInt();                              /* get line # */
  865.         if (Lino <= 0) {          /* don't insert line #0 or negative */
  866.           if (ILPC != 0) TBerror();
  867.             else return;
  868.           break;}
  869.         while (((char)Core[BP]) == ' ') BP++;  /* skip leading spaces */
  870.         if (((char)Core[BP]) == '\r') ix = 0;       /* nothing to add */
  871.           else ix = InLend-BP+2;         /* the size of the insertion */
  872.         op = 0;         /* this will be the number of bytes to delete */
  873.         chpt = FindLine(Lino);             /* try to find this line.. */
  874.         if (Peek2(chpt) == Lino)       /* there is a line to delete.. */
  875.           op = (SkipTo(chpt+2, '\r')-chpt);
  876.         if (ix == 0) if (op==0) {  /* nothing to add nor delete; done */
  877.           Lino = 0;
  878.           break;}
  879.         op = ix-op;      /* = how many more bytes to add or (-)delete */
  880.         if (SrcEnd+op>=SubStk) {                         /* too big.. */
  881.           TBerror();
  882.           break;}
  883.         SrcEnd = SrcEnd+op;                               /* new size */
  884.         if (op>0) for (here=SrcEnd; (here--)>chpt+ix; )
  885.           Core[here] = Core[here-op];  /* shift backend over to right */
  886.         else if (op<0) for (here=chpt+ix; here<SrcEnd; here++)
  887.           Core[here] = Core[here-op];   /* shift it left to close gap */
  888.         if (ix>0) Poke2(chpt++,Lino);        /* insert the new line # */
  889.         while (ix>2) {                       /* insert the new line.. */
  890.           Core[++chpt] = Core[BP++];
  891.           ix--;}
  892.         Poke2(EndProg,SrcEnd);
  893.         ILPC = 0;
  894.         Lino = 0;
  895.           if (Debugging>0) ListIt(0,0);
  896.         break;
  897.  
  898. /* MT      2B      Mark the BASIC program space Empty.                */
  899. /*                 Also clears the BASIC region of the control stack  */
  900. /* and restart the IL program in the command mode. The memory bounds  */
  901. /* and stack pointers are reset by this instruction to signify empty  */
  902. /* program space, and the line number of the first line is set to 0,  */
  903. /* which is the indication of the end of the program.                 */
  904.       case 43:
  905.         ColdStart();
  906.           if (Debugging>0) {ShowSubs(); ShowExSt(); ShowVars(0);}
  907.         break;
  908.  
  909. /* XQ      2C      Execute.                                           */
  910. /*                 Turns on RUN mode. This instruction also saves     */
  911. /* the current value of the IL program counter for use of the NX      */
  912. /* instruction, and sets the BASIC pointer to the beginning of the    */
  913. /* BASIC program space. An error stop occurs if there is no BASIC     */
  914. /* program. This instruction must be executed at least once before    */
  915. /* the first execution of a NX instruction.                           */
  916.       case 44:
  917.         XQhere = ILPC;
  918.         BP = Peek2(UserProg);
  919.         Lino = Peek2(BP++);
  920.         BP++;
  921.         if (Lino == 0) TBerror();
  922.         else if (Debugging>0)
  923.           {OutStr(" [#"); OutInt(Lino); OutStr("]");}
  924.         break;
  925.  
  926. /* WS      2D      Stop.                                              */
  927. /*                 Stop execution and restart the IL program in the   */
  928. /* command mode. The entire control stack (including BASIC region)    */
  929. /* is also vacated by this instruction. This instruction effectively  */
  930. /* jumps to the Warm Start entry of the ML interpreter.               */
  931.       case 45:
  932.         WarmStart();
  933.           if (Debugging>0) ShowSubs();
  934.         break;
  935.  
  936. /* US      2E      Machine Language Subroutine Call.                  */
  937. /*                 The top six bytes of the expression stack contain  */
  938. /* 3 numbers with the following interpretations: The top number is    */
  939. /* loaded into the A (or A and B) register; the next number is loaded */
  940. /* into 16 bits of Index register; the third number is interpreted as */
  941. /* the address of a machine language subroutine to be called. These   */
  942. /* six bytes on the expression stack are replaced with the 16-bit     */
  943. /* result returned by the subroutine. Stack underflow results in an   */
  944. /* error stop.                                                        */
  945.       case 46:
  946.         Poke2(LinoCore,Lino);    /* bring these memory locations up.. */
  947.         Poke2(ILPCcore,ILPC);      /* ..to date, in case user looks.. */
  948.         Poke2(BPcore,BP);
  949.         Poke2(SvPtCore,SvPt);
  950.         ix = PopExInt()&0xFFFF;                            /* datum A */
  951.         here = PopExInt()&0xFFFF;                          /* datum X */
  952.         op = PopExInt()&0xFFFF;            /* nominal machine address */
  953.         if (ILPC == 0) break;
  954.         if (op>=Peek2(ILfront) && op<ILend) { /* call IL subroutine.. */
  955.           PushExInt(here);
  956.           PushExInt(ix);
  957.           PushSub(ILPC);                      /* push return location */
  958.           ILPC = op;
  959.           if (DEBUGON>0) LogIt(-ILPC);
  960.           break;}
  961.         switch (op) {
  962.         case WachPoint:    /* we only do a few predefined functions.. */
  963.           Watcher = here;
  964.           if (ix>32767) ix = -(int)Core[here]-256;
  965.           Watchee = ix;
  966.           if (Debugging>0) {
  967.             OutLn(); OutStr("[** Watch "); OutHex(here,4); OutStr("]");}
  968.           PushExInt((int)Core[here]);
  969.           break;
  970.         case ColdGo:
  971.           ColdStart();
  972.           break;
  973.         case WarmGo:
  974.           WarmStart();
  975.           break;
  976.         case InchSub:
  977.           PushExInt((int)Inch());
  978.           break;
  979.         case OutchSub:
  980.           Ouch((char)(ix&127));
  981.           PushExInt(0);
  982.           break;
  983.         case BreakSub:
  984.           PushExInt(StopIt());
  985.           break;
  986.         case PeekSub:
  987.           PushExInt((int)Core[here]);
  988.           break;
  989.         case Peek2Sub:
  990.           PushExInt(Peek2(here));
  991.           break;
  992.         case PokeSub:
  993.           ix = ix&0xFF;
  994.           Core[here] = (aByte)ix;
  995.           PushExInt(ix);
  996.           if (DEBUGON>0) LogIt(((ix+256)<<16)+here);
  997.           Lino = Peek2(LinoCore);         /* restore these pointers.. */
  998.           ILPC = Peek2(ILPCcore);    /* ..in case user changed them.. */
  999.           BP = Peek2(BPcore);
  1000.           SvPt = Peek2(SvPtCore);
  1001.           break;
  1002.         case DumpSub:
  1003.           ShoMemDump(here,ix);
  1004.           PushExInt(here+ix);
  1005.           break;
  1006.         case TrLogSub:
  1007.           ShowLog();
  1008.           PushExInt(LogHere);
  1009.           break;
  1010.         default: TBerror();}
  1011.         break;
  1012.  
  1013. /* RT      2F      IL Subroutine Return.                              */
  1014. /*                 The IL control stack is popped to give the address */
  1015. /* of the next IL instruction. An error stop occurs if the entire     */
  1016. /* control stack (IL and BASIC) is empty.                             */
  1017.       case 47:
  1018.         ix = PopSub();                         /* get return from pop */
  1019.         if (ix<Peek2(ILfront) || ix>=ILend) TBerror();
  1020.         else if (ILPC != 0) {
  1021.           ILPC = ix;
  1022.           if (DEBUGON>0) LogIt(-ILPC);}
  1023.         break;
  1024.  
  1025. /* JS a    3000-37FF       IL Subroutine Call.                        */
  1026. /*                         The least significant eleven bits of this  */
  1027. /* 2-byte instruction are added to the base address of the IL program */
  1028. /* to become address of the next instruction. The previous contents   */
  1029. /* of the IL program counter are pushed onto the IL region of the     */
  1030. /* control stack. Stack overflow results in an error stop.            */
  1031.       case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55:
  1032.         PushSub(ILPC+1);                /* push return location there */
  1033.         if (ILPC == 0) break;
  1034.         ILPC = (Peek2(ILPC-1)&0x7FF)+Peek2(ILfront);
  1035.         if (DEBUGON>0) LogIt(-ILPC);
  1036.         break;
  1037.  
  1038. /* J a     3800-3FFF       Jump.                                      */
  1039. /*                         The low eleven bits of this 2-byte         */
  1040. /* instruction are added to the IL program base address to determine  */
  1041. /* the address of the next IL instruction. The previous contents of   */
  1042. /* the IL program counter is lost. */
  1043.       case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63:
  1044.         ILPC = (Peek2(ILPC-1)&0x7FF)+Peek2(ILfront);
  1045.         if (DEBUGON>0) LogIt(-ILPC);
  1046.         break;
  1047.  
  1048. /* NO      08      No Operation.                                      */
  1049. /*                 This may be used as a space filler (such as to     */
  1050. /* ignore a skip).                                                    */
  1051.       default: break;} /* last of inner switch cases */
  1052.       break; /* end of outer switch cases 0,1 */
  1053.  
  1054. /* BR a    40-7F   Relative Branch.                                   */
  1055. /*                 The low six bits of this instruction opcode are    */
  1056. /* added algebraically to the current value of the IL program counter */
  1057. /* to give the address of the next IL instruction. Bit 5 of opcode is */
  1058. /* the sign, with + signified by 1, - by 0. The range of this branch  */
  1059. /* is +/-31 bytes from address of the byte following the opcode. An   */
  1060. /* offset of zero (i.e. opcode 60) results in an error stop. The      */
  1061. /* branch operation is unconditional.                                 */
  1062.       case 2: case 3:
  1063.         ILPC = ILPC+op-96;
  1064.         if (DEBUGON>0) LogIt(-ILPC);
  1065.         break;
  1066.  
  1067. /* BC a "xxx"   80xxxxXx-9FxxxxXx  String Match Branch.               */
  1068. /*                                 The ASCII character string in IL   */
  1069. /* following this opcode is compared to the string beginning with the */
  1070. /* current position of the BASIC pointer, ignoring blanks in BASIC    */
  1071. /* program. The comparison continues until either a mismatch, or an   */
  1072. /* IL byte is reached with the most significant bit set to one. This  */
  1073. /* is the last byte of the string in the IL, compared as a 7-bit      */
  1074. /* character; if equal, the BASIC pointer is positioned after the     */
  1075. /* last matching character in the BASIC program and the IL continues  */
  1076. /* with the next instruction in sequence. Otherwise the BASIC pointer */
  1077. /* is not altered and the low five bits of the Branch opcode are      */
  1078. /* added to the IL program counter to form the address of the next    */
  1079. /* IL instruction. If the strings do not match and the branch offset  */
  1080. /* is zero an error stop occurs.                                      */
  1081.       case 4:
  1082.         if (op==128) here = 0;                /* to error if no match */
  1083.           else here = ILPC+op-128;
  1084.         chpt = BP;
  1085.         ix = 0;
  1086.         while ((ix&128)==0) {
  1087.           while (((char)Core[BP]) == ' ') BP++;   /* skip over spaces */
  1088.           ix = (int)Core[ILPC++];
  1089.           if (((char)(ix&127)) != DeCaps[((int)Core[BP++])&127]) {
  1090.             BP = chpt;         /* back up to front of string in Basic */
  1091.             if (here==0) TBerror();
  1092.               else ILPC = here;                 /* jump forward in IL */
  1093.             break;}}
  1094.         if (DEBUGON>0) if (ILPC>0) LogIt(-ILPC);
  1095.         break;
  1096.  
  1097. /* BV a    A0-BF   Branch if Not Variable.                            */
  1098. /*                 If the next non-blank character pointed to by the  */
  1099. /* BASIC pointer is a capital letter, its ASCII code is [doubled and] */
  1100. /* pushed onto the expression stack and the IL program advances to    */
  1101. /* next instruction in sequence, leaving the BASIC pointer positioned */
  1102. /* after the letter; if not a letter the branch is taken and BASIC    */
  1103. /* pointer is left pointing to that character. An error stop occurs   */
  1104. /* if the next character is not a letter and the offset of the branch */
  1105. /* is zero, or on stack overflow.                                     */
  1106.       case 5:
  1107.         while (((char)Core[BP]) == ' ') BP++;     /* skip over spaces */
  1108.         ch = (char)Core[BP];
  1109.         if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z')
  1110.           PushExBy((((int)Core[BP++])&0x5F)*2);
  1111.         else if (op==160) TBerror();           /* error if not letter */
  1112.           else ILPC = ILPC+op-160;
  1113.         if (DEBUGON>0) if (ILPC>0) LogIt(-ILPC);
  1114.         break;
  1115.  
  1116. /* BN a    C0-DF   Branch if Not a Number.                            */
  1117. /*                 If the next non-blank character pointed to by the  */
  1118. /* BASIC pointer is not a decimal digit, the low five bits of the     */
  1119. /* opcode are added to the IL program counter, or if zero an error    */
  1120. /* stop occurs. If the next character is a digit, then it and all     */
  1121. /* decimal digits following it (ignoring blanks) are converted to a   */
  1122. /* 16-bit binary number which is pushed onto the expression stack. In */
  1123. /* either case the BASIC pointer is positioned at the next character  */
  1124. /* which is neither blank nor digit. Stack overflow will result in an */
  1125. /* error stop.                                                        */
  1126.       case 6:
  1127.         while (((char)Core[BP]) == ' ') BP++;     /* skip over spaces */
  1128.         ch = (char)Core[BP];
  1129.         if (ch >= '0' && ch <= '9') {
  1130.           op = 0;
  1131.           while (true) {
  1132.             here = (int)Core[BP++];
  1133.             if (here==32) continue;               /* skip over spaces */
  1134.             if (here<48 || here>57) break;     /* not a decimal digit */
  1135.             op = op*10+here-48;}                 /* insert into value */
  1136.           BP--;                             /* back up over non-digit */
  1137.           PushExInt(op);}
  1138.         else if (op==192) TBerror();             /* error if no digit */
  1139.           else ILPC = ILPC+op-192;
  1140.         if (DEBUGON>0) if (ILPC>0) LogIt(-ILPC);
  1141.         break;
  1142.  
  1143. /* BE a    E0-FF   Branch if Not Endline.                             */
  1144. /*                 If the next non-blank character pointed to by the  */
  1145. /* BASIC pointer is a carriage return, the IL program advances to the */
  1146. /* next instruction in sequence; otherwise the low five bits of the   */
  1147. /* opcode (if not 0) are added to the IL program counter to form the  */
  1148. /* address of next IL instruction. In either case the BASIC pointer   */
  1149. /* is left pointing to the first non-blank character; this            */
  1150. /* instruction will not pass over the carriage return, which must     */
  1151. /* remain for testing by the NX instruction. As with the other        */
  1152. /* conditional branches, the branch may only advance the IL program   */
  1153. /* counter from 1 to 31 bytes; an offset of zero results in an error  */
  1154. /* stop.                                                              */
  1155.       case 7:
  1156.         while (((char)Core[BP]) == ' ') BP++;     /* skip over spaces */
  1157.         if (((char)Core[BP]) == '\r') ;
  1158.         else if (op==224) TBerror();            /* error if no offset */
  1159.           else ILPC = ILPC+op-224;
  1160.         if (DEBUGON>0) if (ILPC>0) LogIt(-ILPC);
  1161.         break;}}} /* ~Interp */
  1162.  
  1163. /***************** Intermediate Interpreter Assembled *****************/
  1164.  
  1165. char* DefaultIL() {
  1166.   static char s[9000];    /* be sure to increase size if you add text */
  1167.   strcpy(s,"0000 ;       1 .  ORIGINAL TINY BASIC INTERMEDIATE INTERPRETER\n");
  1168.   strcat(s,"0000 ;       2 .\n");
  1169.   strcat(s,"0000 ;       3 .  EXECUTIVE INITIALIZATION\n");
  1170.   strcat(s,"0000 ;       4 .\n");
  1171.   strcat(s,"0000 ;       5 :STRT PC \":Q^\"        COLON, X-ON\n");
  1172.   strcat(s,"0000 243A91;\n");
  1173.   strcat(s,"0003 ;       6       GL\n");
  1174.   strcat(s,"0003 27;     7       SB\n");
  1175.   strcat(s,"0004 10;     8       BE L0           BRANCH IF NOT EMPTY\n");
  1176.   strcat(s,"0005 E1;     9       BR STRT         TRY AGAIN IF NULL LINE\n");
  1177.   strcat(s,"0006 59;    10 :L0   BN STMT         TEST FOR LINE NUMBER\n");
  1178.   strcat(s,"0007 C5;    11       IL              IF SO, INSERT INTO PROGRAM\n");
  1179.   strcat(s,"0008 2A;    12       BR STRT         GO GET NEXT\n");
  1180.   strcat(s,"0009 56;    13 :XEC  SB              SAVE POINTERS FOR RUN WITH\n");
  1181.   strcat(s,"000A 10;    14       RB                CONCATENATED INPUT\n");
  1182.   strcat(s,"000B 11;    15       XQ\n");
  1183.   strcat(s,"000C 2C;    16 .\n");
  1184.   strcat(s,"000D ;      17 .  STATEMENT EXECUTOR\n");
  1185.   strcat(s,"000D ;      18 .\n");
  1186.   strcat(s,"000D ;      19 :STMT BC GOTO \"LET\"\n");
  1187.   strcat(s,"000D 8B4C45D4;\n");
  1188.   strcat(s,"0011 ;      20       BV *            MUST BE A VARIABLE NAME\n");
  1189.   strcat(s,"0011 A0;    21       BC * \"=\"\n");
  1190.   strcat(s,"0012 80BD;  22 :LET  JS EXPR         GO GET EXPRESSION\n");
  1191.   strcat(s,"0014 30BC;  23       BE *            IF STATEMENT END,\n");
  1192.   strcat(s,"0016 E0;    24       SV                STORE RESULT\n");
  1193.   strcat(s,"0017 13;    25       NX\n");
  1194.   strcat(s,"0018 1D;    26 .\n");
  1195.   strcat(s,"0019 ;      27 :GOTO BC PRNT \"GO\"\n");
  1196.   strcat(s,"0019 9447CF;\n");
  1197.   strcat(s,"001C ;      28       BC GOSB \"TO\"\n");
  1198.   strcat(s,"001C 8854CF;\n");
  1199.   strcat(s,"001F ;      29       JS EXPR         GET LINE NUMBER\n");
  1200.   strcat(s,"001F 30BC;  30       BE *\n");
  1201.   strcat(s,"0021 E0;    31       SB              (DO THIS FOR STARTING)\n");
  1202.   strcat(s,"0022 10;    32       RB\n");
  1203.   strcat(s,"0023 11;    33       GO              GO THERE\n");
  1204.   strcat(s,"0024 16;    34 .\n");
  1205.   strcat(s,"0025 ;      35 :GOSB BC * \"SUB\"      NO OTHER WORD BEGINS \"GO...\"\n");
  1206.   strcat(s,"0025 805355C2;\n");
  1207.   strcat(s,"0029 ;      36       JS EXPR\n");
  1208.   strcat(s,"0029 30BC;  37       BE *\n");
  1209.   strcat(s,"002B E0;    38       GS\n");
  1210.   strcat(s,"002C 14;    39       GO\n");
  1211.   strcat(s,"002D 16;    40 .\n");
  1212.   strcat(s,"002E ;      41 :PRNT BC SKIP \"PR\"\n");
  1213.   strcat(s,"002E 9050D2;\n");
  1214.   strcat(s,"0031 ;      42       BC P0 \"INT\"     OPTIONALLY OMIT \"INT\"\n");
  1215.   strcat(s,"0031 83494ED4;\n");
  1216.   strcat(s,"0035 ;      43 :P0   BE P3\n");
  1217.   strcat(s,"0035 E5;    44       BR P6           IF DONE, GO TO END\n");
  1218.   strcat(s,"0036 71;    45 :P1   BC P4 \";\"\n");
  1219.   strcat(s,"0037 88BB;  46 :P2   BE P3\n");
  1220.   strcat(s,"0039 E1;    47       NX              NO CRLF IF ENDED BY ; OR ,\n");
  1221.   strcat(s,"003A 1D;    48 :P3   BC P7 '\"'\n");
  1222.   strcat(s,"003B 8FA2;  49       PQ              QUOTE MARKS STRING\n");
  1223.   strcat(s,"003D 21;    50       BR P1           GO CHECK DELIMITER\n");
  1224.   strcat(s,"003E 58;    51 :SKIP BR IF           (ON THE WAY THRU)\n");
  1225.   strcat(s,"003F 6F;    52 :P4   BC P5 \",\"\n");
  1226.   strcat(s,"0040 83AC;  53       PT              COMMA SPACING\n");
  1227.   strcat(s,"0042 22;    54       BR P2\n");
  1228.   strcat(s,"0043 55;    55 :P5   BC P6 \":\"\n");
  1229.   strcat(s,"0044 83BA;  56       PC \"S^\"         OUTPUT X-OFF\n");
  1230.   strcat(s,"0046 2493;  57 :P6   BE *\n");
  1231.   strcat(s,"0048 E0;    58       NL              THEN CRLF\n");
  1232.   strcat(s,"0049 23;    59       NX\n");
  1233.   strcat(s,"004A 1D;    60 :P7   JS EXPR         TRY FOR AN EXPRESSION\n");
  1234.   strcat(s,"004B 30BC;  61       PN\n");
  1235.   strcat(s,"004D 20;    62       BR P1\n");
  1236.   strcat(s,"004E 48;    63 .\n");
  1237.   strcat(s,"004F ;      64 :IF   BC INPT \"IF\"\n");
  1238.   strcat(s,"004F 9149C6;\n");
  1239.   strcat(s,"0052 ;      65       JS EXPR\n");
  1240.   strcat(s,"0052 30BC;  66       JS RELO\n");
  1241.   strcat(s,"0054 3134;  67       JS EXPR\n");
  1242.   strcat(s,"0056 30BC;  68       BC I1 \"THEN\"    OPTIONAL NOISEWORD\n");
  1243.   strcat(s,"0058 84544845CE;\n");
  1244.   strcat(s,"005D ;      69 :I1   CP              COMPARE SKIPS NEXT IF TRUE\n");
  1245.   strcat(s,"005D 1C;    70       NX              FALSE.\n");
  1246.   strcat(s,"005E 1D;    71       J STMT          TRUE. GO PROCESS STATEMENT\n");
  1247.   strcat(s,"005F 380D;  72 .\n");
  1248.   strcat(s,"0061 ;      73 :INPT BC RETN \"INPUT\"\n");
  1249.   strcat(s,"0061 9A494E5055D4;\n");
  1250.   strcat(s,"0067 ;      74 :I2   BV *            GET VARIABLE\n");
  1251.   strcat(s,"0067 A0;    75       SB              SWAP POINTERS\n");
  1252.   strcat(s,"0068 10;    76       BE I4\n");
  1253.   strcat(s,"0069 E7;    77 :I3   PC \"? Q^\"       LINE IS EMPTY; TYPE PROMPT\n");
  1254.   strcat(s,"006A 243F2091;\n");
  1255.   strcat(s,"006E ;      78       GL              READ INPUT LINE\n");
  1256.   strcat(s,"006E 27;    79       BE I4           DID ANYTHING COME?\n");
  1257.   strcat(s,"006F E1;    80       BR I3           NO, TRY AGAIN\n");
  1258.   strcat(s,"0070 59;    81 :I4   BC I5 \",\"       OPTIONAL COMMA\n");
  1259.   strcat(s,"0071 81AC;  82 :I5   JS EXPR         READ A NUMBER\n");
  1260.   strcat(s,"0073 30BC;  83       SV              STORE INTO VARIABLE\n");
  1261.   strcat(s,"0075 13;    84       RB              SWAP BACK\n");
  1262.   strcat(s,"0076 11;    85       BC I6 \",\"       ANOTHER?\n");
  1263.   strcat(s,"0077 82AC;  86       BR I2           YES IF COMMA\n");
  1264.   strcat(s,"0079 4D;    87 :I6   BE *            OTHERWISE QUIT\n");
  1265.   strcat(s,"007A E0;    88       NX\n");
  1266.   strcat(s,"007B 1D;    89 .\n");
  1267.   strcat(s,"007C ;      90 :RETN BC END \"RETURN\"\n");
  1268.   strcat(s,"007C 895245545552CE;\n");
  1269.   strcat(s,"0083 ;      91       BE *\n");
  1270.   strcat(s,"0083 E0;    92       RS              RECOVER SAVED LINE\n");
  1271.   strcat(s,"0084 15;    93       NX\n");
  1272.   strcat(s,"0085 1D;    94 .\n");
  1273.   strcat(s,"0086 ;      95 :END  BC LIST \"END\"\n");
  1274.   strcat(s,"0086 85454EC4;\n");
  1275.   strcat(s,"008A ;      96       BE *\n");
  1276.   strcat(s,"008A E0;    97       WS\n");
  1277.   strcat(s,"008B 2D;    98 .\n");
  1278.   strcat(s,"008C ;      99 :LIST BC RUN \"LIST\"\n");
  1279.   strcat(s,"008C 984C4953D4;\n");
  1280.   strcat(s,"0091 ;     100       BE L2\n");
  1281.   strcat(s,"0091 EC;   101 :L1   PC \"@^@^@^@^J^@^\" PUNCH LEADER\n");
  1282.   strcat(s,"0092 24000000000A80;\n");
  1283.   strcat(s,"0099 ;     102       LS              LIST\n");
  1284.   strcat(s,"0099 1F;   103       PC \"S^\"         PUNCH X-OFF\n");
  1285.   strcat(s,"009A 2493; 104       NL\n");
  1286.   strcat(s,"009C 23;   105       NX\n");
  1287.   strcat(s,"009D 1D;   106 :L2   JS EXPR         GET A LINE NUMBER\n");
  1288.   strcat(s,"009E 30BC; 107       BE L3\n");
  1289.   strcat(s,"00A0 E1;   108       BR L1\n");
  1290.   strcat(s,"00A1 50;   109 :L3   BC * \",\"        SEPARATED BY COMMAS\n");
  1291.   strcat(s,"00A2 80AC; 110       BR L2\n");
  1292.   strcat(s,"00A4 59;   111 .\n");
  1293.   strcat(s,"00A5 ;     112 :RUN  BC CLER \"RUN\"\n");
  1294.   strcat(s,"00A5 855255CE;\n");
  1295.   strcat(s,"00A9 ;     113       J XEC\n");
  1296.   strcat(s,"00A9 380A; 114 .\n");
  1297.   strcat(s,"00AB ;     115 :CLER BC REM \"CLEAR\"\n");
  1298.   strcat(s,"00AB 86434C4541D2;\n");
  1299.   strcat(s,"00B1 ;     116       MT\n");
  1300.   strcat(s,"00B1 2B;   117 .\n");
  1301.   strcat(s,"00B2 ;     118 :REM  BC DFLT \"REM\"\n");
  1302.   strcat(s,"00B2 845245CD;\n");
  1303.   strcat(s,"00B6 ;     119       NX\n");
  1304.   strcat(s,"00B6 1D;   120 .\n");
  1305.   strcat(s,"00B7 ;     121 :DFLT BV *            NO KEYWORD...\n");
  1306.   strcat(s,"00B7 A0;   122       BC * \"=\"        TRY FOR LET\n");
  1307.   strcat(s,"00B8 80BD; 123       J LET           IT'S A GOOD BET.\n");
  1308.   strcat(s,"00BA 3814; 124 .\n");
  1309.   strcat(s,"00BC ;     125 .  SUBROUTINES\n");
  1310.   strcat(s,"00BC ;     126 .\n");
  1311.   strcat(s,"00BC ;     127 :EXPR BC E0 \"-\"       TRY FOR UNARY MINUS\n");
  1312.   strcat(s,"00BC 85AD; 128       JS TERM         AHA\n");
  1313.   strcat(s,"00BE 30D3; 129       NE\n");
  1314.   strcat(s,"00C0 17;   130       BR E1\n");
  1315.   strcat(s,"00C1 64;   131 :E0   BC E4 \"+\"       IGNORE UNARY PLUS\n");
  1316.   strcat(s,"00C2 81AB; 132 :E4   JS TERM\n");
  1317.   strcat(s,"00C4 30D3; 133 :E1   BC E2 \"+\"       TERMS SEPARATED BY PLUS\n");
  1318.   strcat(s,"00C6 85AB; 134       JS TERM\n");
  1319.   strcat(s,"00C8 30D3; 135       AD\n");
  1320.   strcat(s,"00CA 18;   136       BR E1\n");
  1321.   strcat(s,"00CB 5A;   137 :E2   BC E3 \"-\"       TERMS SEPARATED BY MINUS\n");
  1322.   strcat(s,"00CC 85AD; 138       JS TERM\n");
  1323.   strcat(s,"00CE 30D3; 139       SU\n");
  1324.   strcat(s,"00D0 19;   140       BR E1\n");
  1325.   strcat(s,"00D1 54;   141 :E3   RT\n");
  1326.   strcat(s,"00D2 2F;   142 .\n");
  1327.   strcat(s,"00D3 ;     143 :TERM JS FACT\n");
  1328.   strcat(s,"00D3 30E2; 144 :T0   BC T1 \"*\"       FACTORS SEPARATED BY TIMES\n");
  1329.   strcat(s,"00D5 85AA; 145       JS FACT\n");
  1330.   strcat(s,"00D7 30E2; 146       MP\n");
  1331.   strcat(s,"00D9 1A;   147       BR T0\n");
  1332.   strcat(s,"00DA 5A;   148 :T1   BC T2 \"/\"       FACTORS SEPARATED BY DIVIDE\n");
  1333.   strcat(s,"00DB 85AF; 149       JS  FACT\n");
  1334.   strcat(s,"00DD 30E2; 150       DV\n");
  1335.   strcat(s,"00DF 1B;   151       BR T0\n");
  1336.   strcat(s,"00E0 54;   152 :T2   RT\n");
  1337.   strcat(s,"00E1 2F;   153 .\n");
  1338.   strcat(s,"00E2 ;     154 :FACT BC F0 \"RND\"     *RND FUNCTION*\n");
  1339.   strcat(s,"00E2 97524EC4;\n");
  1340.   strcat(s,"00E6 ;     155       LN 257*128      STACK POINTER FOR STORE\n");
  1341.   strcat(s,"00E6 0A;\n");
  1342.   strcat(s,"00E7 8080; 156       FV              THEN GET RNDM\n");
  1343.   strcat(s,"00E9 12;   157       LN 2345         R:=R*2345+6789\n");
  1344.   strcat(s,"00EA 0A;\n");
  1345.   strcat(s,"00EB 0929; 158       MP\n");
  1346.   strcat(s,"00ED 1A;   159       LN 6789\n");
  1347.   strcat(s,"00EE 0A;\n");
  1348.   strcat(s,"00EF 1A85; 160       AD\n");
  1349.   strcat(s,"00F1 18;   161       SV\n");
  1350.   strcat(s,"00F2 13;   162       LB 128          GET IT AGAIN\n");
  1351.   strcat(s,"00F3 0980; 163       FV\n");
  1352.   strcat(s,"00F5 12;   164       DS\n");
  1353.   strcat(s,"00F6 0B;   165       JS FUNC         GET ARGUMENT\n");
  1354.   strcat(s,"00F7 3130; 166       BR F1\n");
  1355.   strcat(s,"00F9 61;   167 :F0   BR F2           (SKIPPING)\n");
  1356.   strcat(s,"00FA 73;   168 :F1   DS\n");
  1357.   strcat(s,"00FB 0B;   169       SX 2            PUSH TOP INTO STACK\n");
  1358.   strcat(s,"00FC 02;   170       SX 4\n");
  1359.   strcat(s,"00FD 04;   171       SX 2\n");
  1360.   strcat(s,"00FE 02;   172       SX 3\n");
  1361.   strcat(s,"00FF 03;   173       SX 5\n");
  1362.   strcat(s,"0100 05;   174       SX 3\n");
  1363.   strcat(s,"0101 03;   175       DV              PERFORM MOD FUNCTION\n");
  1364.   strcat(s,"0102 1B;   176       MP\n");
  1365.   strcat(s,"0103 1A;   177       SU\n");
  1366.   strcat(s,"0104 19;   178       DS              PERFORM ABS FUNCTION\n");
  1367.   strcat(s,"0105 0B;   179       LB 6\n");
  1368.   strcat(s,"0106 0906; 180       LN 0\n");
  1369.   strcat(s,"0108 0A;\n");
  1370.   strcat(s,"0109 0000; 181       CP              (SKIP IF + OR 0)\n");
  1371.   strcat(s,"010B 1C;   182       NE\n");
  1372.   strcat(s,"010C 17;   183       RT\n");
  1373.   strcat(s,"010D 2F;   184 :F2   BC F3 \"USR\"     *USR FUNCTION*\n");
  1374.   strcat(s,"010E 8F5553D2;\n");
  1375.   strcat(s,"0112 ;     185       BC * \"(\"        3 ARGUMENTS POSSIBLE\n");
  1376.   strcat(s,"0112 80A8; 186       JS EXPR         ONE REQUIRED\n");
  1377.   strcat(s,"0114 30BC; 187       JS ARG\n");
  1378.   strcat(s,"0116 312A; 188       JS ARG\n");
  1379.   strcat(s,"0118 312A; 189       BC * \")\"\n");
  1380.   strcat(s,"011A 80A9; 190       US              GO DO IT\n");
  1381.   strcat(s,"011C 2E;   191       RT\n");
  1382.   strcat(s,"011D 2F;   192 :F3   BV F4           VARIABLE?\n");
  1383.   strcat(s,"011E A2;   193       FV              YES.  GET IT\n");
  1384.   strcat(s,"011F 12;   194       RT\n");
  1385.   strcat(s,"0120 2F;   195 :F4   BN F5           NUMBER?\n");
  1386.   strcat(s,"0121 C1;   196       RT              GOT IT.\n");
  1387.   strcat(s,"0122 2F;   197 :F5   BC * \"(\"        OTHERWISE MUST BE (EXPR)\n");
  1388.   strcat(s,"0123 80A8; 198 :F6   JS EXPR\n");
  1389.   strcat(s,"0125 30BC; 199       BC * \")\"\n");
  1390.   strcat(s,"0127 80A9; 200       RT\n");
  1391.   strcat(s,"0129 2F;   201 .\n");
  1392.   strcat(s,"012A ;     202 :ARG  BC A0 \",\"        COMMA?\n");
  1393.   strcat(s,"012A 83AC; 203       J  EXPR          YES, GET EXPRESSION\n");
  1394.   strcat(s,"012C 38BC; 204 :A0   DS               NO, DUPLICATE STACK TOP\n");
  1395.   strcat(s,"012E 0B;   205       RT\n");
  1396.   strcat(s,"012F 2F;   206 .\n");
  1397.   strcat(s,"0130 ;     207 :FUNC BC * \"(\"\n");
  1398.   strcat(s,"0130 80A8; 208       BR F6\n");
  1399.   strcat(s,"0132 52;   209       RT\n");
  1400.   strcat(s,"0133 2F;   210 .\n");
  1401.   strcat(s,"0134 ;     211 :RELO BC R0 \"=\"        CONVERT RELATION OPERATORS\n");
  1402.   strcat(s,"0134 84BD; 212       LB 2             TO CODE BYTE ON STACK\n");
  1403.   strcat(s,"0136 0902; 213       RT               =\n");
  1404.   strcat(s,"0138 2F;   214 :R0   BC R4 \"<\"\n");
  1405.   strcat(s,"0139 8EBC; 215       BC R1 \"=\"\n");
  1406.   strcat(s,"013B 84BD; 216       LB 3             <=\n");
  1407.   strcat(s,"013D 0903; 217       RT\n");
  1408.   strcat(s,"013F 2F;   218 :R1   BC R3 \">\"\n");
  1409.   strcat(s,"0140 84BE; 219       LB 5             <>\n");
  1410.   strcat(s,"0142 0905; 220       RT\n");
  1411.   strcat(s,"0144 2F;   221 :R3   LB 1             <\n");
  1412.   strcat(s,"0145 0901; 222       RT\n");
  1413.   strcat(s,"0147 2F;   223 :R4   BC * \">\"\n");
  1414.   strcat(s,"0148 80BE; 224       BC R5 \"=\"\n");
  1415.   strcat(s,"014A 84BD; 225       LB 6             >=\n");
  1416.   strcat(s,"014C 0906; 226       RT\n");
  1417.   strcat(s,"014E 2F;   227 :R5   BC R6 \"<\"\n");
  1418.   strcat(s,"014F 84BC; 228       LB 5             ><\n");
  1419.   strcat(s,"0151 0905; 229       RT\n");
  1420.   strcat(s,"0153 2F;   230 :R6   LB 4             >\n");
  1421.   strcat(s,"0154 0904; 231       RT\n");
  1422.   strcat(s,"0156 2F;   232 .\n");
  1423.   strcat(s,"0157 ;    0000\n");
  1424.   return s;} /* ~DefaultIL */
  1425.  
  1426. /**************************** Startup Code ****************************/
  1427.  
  1428. void StartTinyBasic(char* ILtext) {
  1429.   int nx;
  1430.   for (nx=0; nx<CoreTop; nx++) Core[nx] = 0;          /* clear Core.. */
  1431.   Poke2(ExpnStk,8191);                          /* random number seed */
  1432.   Core[BScode] = 8; /* backspace */
  1433.   Core[CanCode] = 27; /*escape */
  1434.   for (nx=0; nx<32; nx++) DeCaps[nx] = '\0';     /* fill caps table.. */
  1435.   for (nx=32; nx<127; nx++) DeCaps[nx] = (char)nx;
  1436.   for (nx=65; nx<91; nx++) DeCaps[nx+32] = (char)nx;
  1437.   DeCaps[9] = ' ';
  1438.   DeCaps[10] = '\r';
  1439.   DeCaps[13] = '\r';
  1440.   DeCaps[127] = '\0';
  1441.   if (ILtext == NULL) ILtext = DefaultIL();  /* no IL given, use mine */
  1442.   ConvtIL(ILtext);              /* convert IL assembly code to binary */
  1443.   ColdStart();
  1444.   Interp();                                               /* go do it */
  1445.   if (oFile != NULL) IoFileClose(oFile);         /* close output file */
  1446.   if (inFile != NULL) IoFileClose(inFile);        /* close input file */
  1447.   oFile = NULL;
  1448.   inFile = NULL;} /* ~StartTinyBasic */
  1449.  
  1450. int main(int argc, char* argv[]) {
  1451. /*  CONSOLE_INIT("TinyBasic"); */
  1452.   if (con_init_console_dll()) return 1; // init fail
  1453.   con_set_title("TinyBasic");
  1454.  
  1455.   int nx;
  1456.   long int len;
  1457.   char* IL = NULL;
  1458.   FileType tmpFile;
  1459.   inFile = NULL;
  1460.   oFile = NULL;
  1461.   for (nx=1; nx<argc; nx++) {         /* look for command-line args.. */
  1462.     if (strcmp(argv[nx],"-b")==0 && ++nx<argc) {     /* alt IL file.. */
  1463.       tmpFile = fopen(argv[nx],"r");
  1464.       if (tmpFile != NULL) if (fseek(tmpFile,0,SEEK_END)==0) {
  1465.         len = ftell(tmpFile);                      /* get file size.. */
  1466.         if (fseek(tmpFile,0,SEEK_SET)==0) if (len>9) {
  1467.           len = len/8+len;            /* allow for line end expansion */
  1468.           IL = (char*)malloc(len+1);
  1469.           if (IL != NULL) len = fread(IL,1,len,tmpFile);
  1470.           IL[len] = '\0';
  1471.           IoFileClose(tmpFile);}}
  1472.       else con_printf("Could not open file %s", argv[nx]);}
  1473.     else if (strcmp(argv[nx],"-o")==0 && ++nx<argc)    /* output file */
  1474.       oFile = fopen(argv[nx],"w");
  1475.     else if (strcmp(argv[nx],"-i")==0 && ++nx<argc)     /* input file */
  1476.       inFile = fopen(argv[nx],"r");
  1477.     else if (inFile==NULL)  /* default (unadorned) is also input file */
  1478.       inFile = fopen(argv[nx],"r");}             /* ignore other args */
  1479.  
  1480. #ifdef DefaultInputFile
  1481.   if (inFile==NULL) inFile = fopen(DefaultInputFile,"r");
  1482. #endif
  1483. #ifdef DefaultOutputFile
  1484.   if (oFile==NULL) oFile = fopen(DefaultOutputFile,"w");
  1485. #endif
  1486.  
  1487.   StartTinyBasic(IL);                                     /* go do it */
  1488.   return 0;} /* ~main */
  1489.  
  1490.  
  1491.   char *ExplainErr(int code)
  1492.   {
  1493.         switch (code)
  1494.         {
  1495.           case  0:              return     "Break during execution";
  1496.           case  8:      return     "Memory overflow; line not inserted";
  1497.           case  9:              return     "Line number 0 not allowed";
  1498.       case  13:         return     "RUN with no program in memory";
  1499.           case  18:             return     "LET is missing a variable name";
  1500.           case  20:             return     "LET is missing an =";
  1501.           case  23:             return     "Improper syntax in LET";
  1502.           case  25:             return     "LET is not followed by END";
  1503.           case  34:             return     "Improper syntax in GOTO";
  1504.           case  37:             return     "No line to GO TO";
  1505.           case  39:             return     "Misspelled GOTO";
  1506.           case  40:
  1507.           case  41:             return     "Misspelled GOSUB";
  1508.           case  46:             return     "GOSUB subroutine does not exist";
  1509.           case  59:             return     "PRINT not followed by END";
  1510.           case  62:             return     "Missing close quote in PRINT string";
  1511.           case  73:             return     "Colon in PRINT is not at end of statement";
  1512.           case  75:             return     "PRINT not followed by END";
  1513.           case  95:             return     "IF not followed by END";
  1514.           case 104:             return     "INPUT syntax bad - expects variable name";
  1515.           case 123:             return     "INPUT syntax bad - expects comma";
  1516.           case 124:             return     "INPUT not followed by END";
  1517.           case 132:             return     "RETURN syntax bad";
  1518.           case 133:             return     "RETURN has no matching GOSUB";
  1519.           case 134:             return     "GOSUB not followed by END";
  1520.           case 139:             return     "END syntax bad";
  1521.           case 154:             return     "Can't LIST line number 0";
  1522.           case 164:             return     "LIST syntax error - expects comma";
  1523.           case 183:             return     "REM not followed by END";
  1524.           case 184:             return     "Missing statement type keyword";
  1525.           case 186:             return     "Misspelled statement type keyword";
  1526.           case 188:             return     "Memory overflow: too many GOSUB's ...";
  1527.           case 211:             return     "Memory overflow: ... or expression too complex";
  1528.           case 224:             return     "Divide by 0";
  1529.           case 226:             return     "Memory overflow";
  1530.           case 232:             return     "Expression too complex ...";
  1531.           case 233:             return     "Expression too complex ... using RND ...";
  1532.           case 234:             return     "Expression too complex ... in direct evaluation";
  1533.           case 253:             return     "Expression too complex ... simplify the expression";
  1534.           case 259:             return     "RND (0) not allowed";
  1535.           case 266:             return     "Expression too complex ...";
  1536.           case 267:             return     "Expression too complex ... for RND";
  1537.           case 275:             return     "USR expects \"(\" before arguments";
  1538.           case 284:             return     "USR expects \")\" after arguments";
  1539.           case 287:             return     "Expression too complex ...";
  1540.           case 288:             return     "Expression too complex ... for USR";
  1541.           case 290:             return     "Expression too complex";
  1542.           case 293:             return     "Syntax error in expression - expects value";
  1543.           case 296:             return     "Syntax error - expects \")\"";
  1544.           case 298:             return     "Memory overflow (in USR)";
  1545.           case 303:             return     "Expression too complex (in USR)";
  1546.           case 304:             return     "Memory overflow (in function evaluation)";
  1547.           case 306:             return     "Syntax error - expects \"(\" for function arguments";
  1548.           case 330:             return     "IF syntax error - expects relation operator";
  1549.           default:      return "Unknown error, interpreter is malfunctioning";
  1550.         }
  1551.   }