📄 forthtest.cpp
字号:
/**
@file
@brief Test code for forth virtual machine.
This program has been placed in the Public Domain by J.D.Medhurst (a.k.a. Tixy)
*/
/**
@defgroup forth_test Test - Test code for forth virtual machine
This code has been placed in the Public Domain by J.D.Medhurst (a.k.a. Tixy).
It may be used, modified and distributed in any manner, without any restriction.
@ingroup forth
@{
*/
#include "common.h"
#include "..\forth.h"
/** Path for source code location */
#define SOURCE_ROOT_PATH "..\\forth\\"
#include <conio.h>
/**
ForthIo implementation which uses C standard library console i/o functions.
*/
class StdForthIo : public ForthIo
{
public:
inline StdForthIo()
{ NewLine[0]=2; NewLine[1]=13; NewLine[2]=10; }
virtual void ConsoleOut(const CHAR* text,UCELL textLength)
{ while(textLength--) putch(*text++); }
virtual CELL ConsoleIn()
{ return getch(); }
};
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
/**
Read a files contents into memory.
The file is assumed to contain characters of 8 bit size but they are stored
in memory as characters the same size as the Forth VM's \c CHAR.
@param name The file name.
@param address On success, this is the address of the memory cell containing the
read contents. This memory must be freed when it is no longer required.
@param size On success, this is the number of characters in the file.
@return True, if the read was successful, false otherwise.
*/
bool ReadFile(const char* name,void*& address, uint& size)
{
FILE* f=fopen(name,"rb");
if(!f)
return false;
if(fseek(f,0,SEEK_END))
{ fclose(f); return false; }
size = ftell(f);
if(fseek(f,0,SEEK_SET))
{ fclose(f); return false; }
address = malloc(size*sizeof(CHAR));
if(!address)
{ fclose(f); return false; }
if(size!=fread(address,sizeof(uint8),size,f))
{ free(address); fclose(f); return false; }
fclose(f);
CHAR* d=(CHAR*)((CELL)address+size*sizeof(CHAR)/sizeof(uint8));
uint8* s=(uint8*)((CELL)address+size*sizeof(uint8));
while((void*)d>(void*)s) *--d=*--s;
return true;
}
#if BITS_PER_CHAR==16
/** Macro to include string constants in source which match the width of the \c CHAR type.*/
#define STRING(string) L##string
/** Macro to include a line of text as an in-source constant .*/
#define LINE(string) L##string L"\n"
#else
/** Macro to include string constants in source which match the width of the \c CHAR type.*/
#define STRING(string) string
/** Macro to include a line of text as an in-source constant .*/
#define LINE(string) string "\n"
#endif
/**
Test Forth VM derivation to add file \c INCLUDE functionality.
*/
class ForthTest : public Forth
{
public:
/**
Load the contents of a file and \c EVALUATE it.
@param fileName The name of the file.
@return 0 or a forth execption value.
*/
CELL Include(const char* fileName);
/**
Load the contents of a file and \c EVALUATE it a line at a time.
@param fileName The name of the file.
@return 0 or a forth execption value.
*/
CELL IncludeLines(const char* fileName);
};
CELL ForthTest::Include(const char* fileName)
{
void* file;
uint size;
if(ReadFile(fileName,file,size))
{
CELL result = Evaluate((const CHAR*)file,size);
free(file);
return result;
}
else
return -38; // non-existent file
}
CELL ForthTest::IncludeLines(const char* fileName)
{
static CELL XT_INTERPRET_LINES = 0;
static const CHAR InterpretLines[] =
{
// Function which interprets source a line at a time...
LINE("DECIMAL")
LINE(":NONAME ( c-addr u -- )")
LINE(" (source) 2! 0 >IN !")
LINE(" SOURCE CHARS + >R")
LINE(" BEGIN")
LINE(" SOURCE DROP >IN @ CHARS +")
LINE(" DUP R@ U<")
LINE(" WHILE")
LINE(" R@ OVER - 1 CHARS / (source) 2!")
// LINE(" BASE @ HEX R@ . (source) 2@ CHARS + . CR BASE !")
LINE(" 0 >IN ! 10 PARSE 2DROP >IN @ (source) ! 0 >IN !")
// LINE(" SOURCE TYPE KEY DROP")
LINE(" INTERPRET")
LINE(" REPEAT")
LINE(" R> 2DROP")
LINE(";")
};
if(!XT_INTERPRET_LINES)
{
// Create word to interpret a file a line at a time...
CELL result = Evaluate(InterpretLines,sizeof(InterpretLines)/sizeof(CHAR));
if(result)
return result;
XT_INTERPRET_LINES = Pop(1)[0]; // Pop xt for INTERPRET-LINES
}
void* file;
uint size;
if(ReadFile(fileName,file,size))
{
// Interpret file a line at a time...
Push((CELL*)&file,1);
Push((CELL*)&size,1);
CELL result = Execute(XT_INTERPRET_LINES);
free(file);
return result;
}
else
return -38; // non-existent file
}
/**
Construct counted string arguments in the form <CODE> (CHAR*)string,(CELL)stringLength </CODE>
@param string A quoted string, e.g. <CODE> "A string" </CODE>
*/
#define COUNTED_STRING(string) (CHAR*)STRING(string),(sizeof(string)-1)
/**
Top level test function. Call this to perform all tests.
*/
void TestForth()
{
// construct test VM...
uint size = 1<<20; // 1Meg of RAM
void* start = malloc(size);
StdForthIo io;
ForthTest* forth = (ForthTest*)Forth::Construct(start,size,&io);
// test Push and Pop...
CELL args[2];
args[0] = 888;
forth->Push(args,1);
args[0] = 999;
forth->Push(args,1);
args[0] = 11;
args[1] = 123;
forth->Push(args,2);
const CELL* out;
out=forth->Pop(0); // pop zero arguments, i.e. just get a peek at the stack
ASSERT(out[0]==11)
ASSERT(out[1]==123)
ASSERT(out[2]==999)
ASSERT(out[3]==888)
forth->Evaluate(COUNTED_STRING("- SWAP")); // stack effect is: ( 888 999 123 11 -- 888 112 999 )
out=forth->Pop(0);
ASSERT(out[0]==999)
ASSERT(out[1]==112)
ASSERT(out[2]==888)
out=forth->Pop(2);
ASSERT(out[0]==999)
ASSERT(out[1]==112)
out=forth->Pop(1);
ASSERT(out[0]==888)
// load additional forth source...
ASSERT(0==forth->Include(SOURCE_ROOT_PATH "core-ext.f"));
ASSERT(0==forth->Include(SOURCE_ROOT_PATH "search.f"));
ASSERT(0==forth->Include(SOURCE_ROOT_PATH "programming-tools.f"));
// ANS wordset tests...
ASSERT(0==forth->Include(SOURCE_ROOT_PATH "test\\tester.f"));
ASSERT(0==forth->IncludeLines(SOURCE_ROOT_PATH "test\\core.f"));
ASSERT(0==forth->IncludeLines(SOURCE_ROOT_PATH "test\\core-ext.f"));
ASSERT(0==forth->IncludeLines(SOURCE_ROOT_PATH "test\\search.f"));
ASSERT(0==forth->IncludeLines(SOURCE_ROOT_PATH "test\\search-ext.f"));
#if 0 // set true to test ARM assembler and disassembler...
ASSERT(0==forth->Include(SOURCE_ROOT_PATH "arm-disasm.f"));
ASSERT(0==forth->Include(SOURCE_ROOT_PATH "arm-asm.f"));
ASSERT(0==forth->Include(SOURCE_ROOT_PATH "test\\arm-asm-disasm-test.f"));
#endif
// forth->Quit();
free(forth);
}
/** @} */ // End of group
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -