forthtest.cpp

Go to the documentation of this file.
00001 /*
00002 This program is distributed under the terms of the 'MIT license'. The text
00003 of this licence follows...
00004 
00005 Copyright (c) 2005-2009 J.D.Medhurst (a.k.a. Tixy)
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to deal
00009 in the Software without restriction, including without limitation the rights
00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011 copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00020 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00022 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00023 THE SOFTWARE.
00024 */
00025 
00040 #include "common.h"
00041 #include "test/test.h"
00042 #include "../forth.h"
00043 
00045 #define SOURCE_ROOT_PATH "forth/"
00046 
00047 
00048 #include <malloc.h>
00049 #include <stdlib.h>
00050 #include <stdio.h>
00051 
00052 
00053 #include <unistd.h>
00054 #include <termios.h>
00055 
00059 class StdForthIo : public ForthIo
00060     {
00061 public:
00062     StdForthIo()
00063         {
00064         // set new line sequence as CR/LF...
00065         NewLine[0]=2;
00066         NewLine[1]=13;
00067         NewLine[2]=10;
00068 
00069         // if stdin is a terminal then set non-canonical input mode without echo...
00070         if((IsTerminal = tcgetattr(fileno(stdin),&InitialSettings)==0))
00071             {
00072             struct termios settings = InitialSettings;
00073             settings.c_lflag &= ~(ICANON|ECHO);
00074             settings.c_cc[VMIN] = 1;
00075             settings.c_cc[VTIME] = 0;
00076             tcsetattr(fileno(stdin),TCSANOW,&settings);
00077             }
00078         }
00079 
00080     ~StdForthIo()
00081         {
00082         // restore terminal settings...
00083         if(IsTerminal)
00084             tcsetattr(fileno(stdin),TCSANOW,&InitialSettings);
00085         }
00086 
00087 
00088     virtual void ConsoleOut(const CHAR* text,UCELL textLength)
00089         {
00090         while(textLength--)
00091             putchar(*text++);
00092         }
00093 
00094     virtual CELL ConsoleIn()
00095         {
00096         return getchar();
00097         }
00098 
00099 private:
00100     bool IsTerminal;
00101     struct termios InitialSettings;
00102     };
00103 
00104 
00109 class TestForthIo : public ForthIo
00110     {
00111 public:
00112     TestForthIo()
00113         : Input(0)
00114         {
00115         NewLine[0]=2;
00116         NewLine[1]=13;
00117         NewLine[2]=10;
00118         }
00119 
00120     virtual void ConsoleOut(const CHAR* text,UCELL textLength)
00121         {
00122         while(textLength--)
00123             putchar(*text++);
00124         }
00125 
00130     void SetTestInput(const char* input)
00131         {
00132         Input = input;
00133         }
00134 
00135     virtual CELL ConsoleIn()
00136         {
00137         if(Input && Input[0])
00138             return *Input++;
00139         TEST(false); // no input available!
00140         return 13; // default to carriage return
00141         }
00142 private:
00143     const char* Input;
00144     };
00145 
00146 
00158 bool ReadFile(const char* name,void*& address, unsigned& size)
00159     {
00160     FILE* f=fopen(name,"rb");
00161     if(!f)
00162         return false;
00163     if(fseek(f,0,SEEK_END))
00164         { fclose(f); return false; }
00165     size = ftell(f);
00166     if(fseek(f,0,SEEK_SET))
00167         { fclose(f); return false; }
00168     address = malloc(size*sizeof(CHAR));
00169     if(!address)
00170         { fclose(f); return false; }
00171     if(size!=fread(address,sizeof(uint8_t),size,f))
00172         { free(address); fclose(f); return false; }
00173     fclose(f);
00174     CHAR* d=(CHAR*)((CELL)address+size*sizeof(CHAR)/sizeof(uint8_t));
00175     uint8_t* s=(uint8_t*)((CELL)address+size*sizeof(uint8_t));
00176     while((void*)d>(void*)s) *--d=*--s;
00177     return true;
00178     }
00179 
00180 
00181 #if BITS_PER_CHAR==16
00182 
00183 #define STRING(string) L##string
00184 
00185 #define LINE(string) L##string L"\n"
00186 #else
00187 
00188 #define STRING(string) string
00189 
00190 #define LINE(string) string "\n"
00191 #endif
00192 
00193 
00197 class ForthTest : public Forth
00198     {
00199 public:
00205     CELL Include(const char* fileName);
00206 
00212     CELL IncludeLines(const char* fileName);
00213     };
00214 
00215 
00216 CELL ForthTest::Include(const char* fileName)
00217     {
00218     void* file;
00219     unsigned size;
00220     if(ReadFile(fileName,file,size))
00221         {
00222         CELL result = Evaluate((const CHAR*)file,size);
00223         free(file);
00224         return result;
00225         }
00226     else
00227         return -38; // non-existent file
00228     }
00229 
00230 
00231 CELL ForthTest::IncludeLines(const char* fileName)
00232     {
00233     static CELL XT_INTERPRET_LINES = 0;
00234 
00235     static const CHAR InterpretLines[] =
00236         {
00237         // Function which interprets source a line at a time...
00238         LINE("DECIMAL")
00239         LINE(":NONAME   ( c-addr u -- )")
00240         LINE("  (source) 2! 0 >IN !")
00241         LINE("  SOURCE CHARS + >R")
00242         LINE("  BEGIN")
00243         LINE("      SOURCE DROP >IN @ CHARS +")
00244         LINE("      DUP R@ U<")
00245         LINE("  WHILE")
00246         LINE("      R@ OVER - 1 CHARS / (source) 2!")
00247     //  LINE("      BASE @ HEX R@ . (source) 2@ CHARS + . CR BASE !")
00248         LINE("      0 >IN ! 10 PARSE 2DROP >IN @ (source) ! 0 >IN !")
00249     //  LINE("      SOURCE TYPE KEY DROP")
00250         LINE("      INTERPRET")
00251         LINE("  REPEAT")
00252         LINE("  R> 2DROP")
00253         LINE(";")
00254         };
00255 
00256     if(!XT_INTERPRET_LINES)
00257         {
00258         // Create word to interpret a file a line at a time...
00259         CELL result = Evaluate(InterpretLines,sizeof(InterpretLines)/sizeof(CHAR));
00260         if(result)
00261             return result;
00262         XT_INTERPRET_LINES = Pop(1)[0];  // Pop xt for INTERPRET-LINES
00263         }
00264 
00265     void* file;
00266     unsigned size;
00267     if(ReadFile(fileName,file,size))
00268         {
00269         // Interpret file a line at a time...
00270         Push((CELL*)&file,1);
00271         Push((CELL*)&size,1);
00272         CELL result = Execute(XT_INTERPRET_LINES);
00273         free(file);
00274         return result;
00275         }
00276     else
00277         return -38; // non-existent file
00278     }
00279 
00280 
00285 #define COUNTED_STRING(string) (CHAR*)STRING(string),(sizeof(string)-1)
00286 
00287 
00294 void TestForth(bool interactive)
00295     {
00296     // make i/o object...
00297     union
00298         {
00299         ForthIo* io;
00300         StdForthIo* ioStd;
00301         TestForthIo* ioTest;
00302         };
00303     if(interactive)
00304         ioStd = new StdForthIo;
00305     else
00306         ioTest = new TestForthIo;
00307     TEST(io);
00308 
00309     // construct test VM...
00310     unsigned size = 1<<20; // 1Meg of RAM
00311     void* start =  malloc(size);
00312     ForthTest* forth = (ForthTest*)Forth::Construct(start,size,io);
00313 
00314     // test Push and Pop...
00315     CELL args[2];
00316     args[0] = 888;
00317     forth->Push(args,1);
00318     args[0] = 999;
00319     forth->Push(args,1);
00320     args[0] = 11;
00321     args[1] = 123;
00322     forth->Push(args,2);
00323     const CELL* out;
00324     out=forth->Pop(0); // pop zero arguments, i.e. just get a peek at the stack
00325     TEST(out[0]==11);
00326     TEST(out[1]==123);
00327     TEST(out[2]==999);
00328     TEST(out[3]==888);
00329     TEST(!forth->Evaluate(COUNTED_STRING("- SWAP"))); // stack effect is: ( 888 999 123 11 -- 888 112 999 )
00330     out=forth->Pop(0);
00331     TEST(out[0]==999);
00332     TEST(out[1]==112);
00333     TEST(out[2]==888);
00334     out=forth->Pop(2);
00335     TEST(out[0]==999);
00336     TEST(out[1]==112);
00337     out=forth->Pop(1);
00338     TEST(out[0]==888);
00339 
00340     // load additional forth source...
00341     TEST(0==forth->Include(SOURCE_ROOT_PATH "core-ext.f"));
00342     TEST(0==forth->Include(SOURCE_ROOT_PATH "search.f"));
00343     TEST(0==forth->Include(SOURCE_ROOT_PATH "programming-tools.f"));
00344 
00345     // ANS wordset tests...
00346     TEST(0==forth->Include(SOURCE_ROOT_PATH "test/tester.f"));
00347     if(!interactive)
00348         ioTest->SetTestInput("Testing, Testing, 124\b3\n");
00349     TEST(0==forth->IncludeLines(SOURCE_ROOT_PATH "test/core.f"));
00350     TEST(0==forth->IncludeLines(SOURCE_ROOT_PATH "test/core-ext.f"));
00351     TEST(0==forth->IncludeLines(SOURCE_ROOT_PATH "test/search.f"));
00352     TEST(0==forth->IncludeLines(SOURCE_ROOT_PATH "test/search-ext.f"));
00353 
00354 #if 0 // set true to test ARM assembler and disassembler...
00355     TEST(0==forth->Include(SOURCE_ROOT_PATH "arm-disasm.f"));
00356     TEST(0==forth->Include(SOURCE_ROOT_PATH "arm-asm.f"));
00357     if(!interactive)
00358         ioTest->SetTestInput("\n");
00359     TEST(0==forth->Include(SOURCE_ROOT_PATH "test/arm-asm-disasm-test.f"));
00360 #endif
00361 
00362     // start interactive console...
00363     if(!interactive)
00364         ioTest->SetTestInput("2 2 + .\nBYE\n");
00365     forth->Quit();
00366 
00367     // cleanup...
00368     free(forth);
00369     if(interactive)
00370         delete ioStd;
00371     else
00372         delete ioTest;
00373     }
00374  // End of group
00376 

Generated by  doxygen 1.6.1