トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

PRG-stm32-forth

  CFOTH

https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads

https://github.com/MitchBradley/cforth/tree/master

with WROOM32/ESP32

make port=/dev/ttyUSB0 flash 

  Arduino IDE CORE

/* Forth サンプル */
/* オリジナルは以下のところ 
* http://phaendal.hatenablog.com/entry/2015/07/29/091821
* https://github.com/phaendal/documentation- forth/tree/master/006.interactive_rstack_recur/c-sample 
*/
/* 変更内容
 * STM32duino 用に書き換え
 /*
// #define DICT_MAX 65535
// #define DICT_MAX 2048  # STM32F103C6 MAX 
#define DICT_MAX 1024
// #define DICT_MAX 192
// #define DICT_MAX 180

//******************************************************
//#include <avr/pgmspace.h>
//******************************************************
// typedef long int Number;
// typedef int Number;
typedef long Number;
typedef char* FString;

// Core
typedef void (*Core)(void);

// ワードのフラグ
typedef struct  {
 unsigned int immediate:1;
 unsigned int hidden:1;
} wflag;

// Header
typedef struct {
 int    next;
 char  *hname;
 wflag *flag;
} Header ;

typedef union {
 Number number;
 FString str;
 Core   core;
 Header *header;
} DictValue;

// スタック
//=================================================================================================
DictValue dstack[128] ;
// DictValue dstack[64] ;
// DictValue dstack[32] ;
//****************************************************************************************************
long int doToken (char);
void procValue (DictValue);


//=================================================================================================
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
// =================================================================================================


static int dsp = 0;

// int rstack[128];
// static int rstack[64];
// static int rstack[32];
static int rstack[128];
static int rsp = 0;

void rpush (int x) {
 rstack[rsp] = x;
 rsp++;
}

int rpop () {
 rsp--;
 return rstack[rsp];
}

void dpush (DictValue x) {
 dstack[dsp] = x;
 dsp++;
}

DictValue dpop () {
 if ( dsp <= 0 ) {
   Serial.print("Stuck underflow");
    return dstack[dsp];
 }
 dsp--;
 return dstack[dsp];
}


// 辞書とVM
// =================================================================================================
DictValue ip;
int np;

// #define DICT_MAX 65536
// 終了用の番兵
static DictValue dict[DICT_MAX] = { 0 } ; 
// 終了用の番兵

int latest = 0;
int dict_here = 1;

void pushDict(DictValue v) {
 dict[dict_here] = v;
 dict_here++;
}

// to Core Field Address
int toCFA (int addr) {
 return addr + 1;
}

// フラグのチェックと操作
int isHidden (wflag *flag) {
 // hiddenなら0を返す
 return flag->hidden;
}

int isImmediate (wflag *flag) {
 return flag->immediate;
}

void toggleHidden (wflag *flag) {
 flag->hidden = !flag->hidden;
}

void setImmediate (int addr, int flag) {
 Header *word = dict[addr].header;
 word->flag->immediate = flag;
}


// NEXTルーチン
// =================================================================================================
void next () {
 ip = dict[np];
 np++;
}

void docolon () {
 rpush(np);
 np = ip.number + 1;
 next();
}

void execute () {
 while (ip.number != 0) {
   dict[ip.number].core();
 }
}


// ワード定義関数
// ==================================================================================== =============
int createHeader (char *hname) {
 // ヘッダを作り、そのヘッダのアドレスを返す
 // Header *h = malloc(sizeof(Header));
 Header *h = new(Header);
 // wflag *flag = malloc(sizeof(wflag));
 wflag *flag = new(wflag);
 flag->immediate = 0;
 flag->hidden    = 0;

 DictValue d;
 h->next = latest;
 h->hname = strdup(hname);
 h->flag = flag;

 latest = dict_here;
 d.header = h;
 pushDict(d);

 return latest;
}

void freeHeader (Header *h) {
 free(h->hname);
 free(h->flag);
 free(h);
}

int defnative (char *cname, Core core) {
 // Coreのみのネイティブワードを作り、そのアドレスを返す
 int addr = createHeader(cname);

 DictValue d = {.core = core};
 pushDict(d);
 return addr;
}

int defword (char *name, ...) {
 // 可変長引数の準備
 va_list ap;
 va_start(ap, name);

 // コロンワードを作り、そのアドレスを返す
 // dfは0で終わっている必要がある
 int addr = createHeader(name);

 DictValue d = {.core = docolon};
 pushDict(d);

 int word = va_arg(ap, int);
 for (; word != 0; word = va_arg(ap, int)) {
   int cfa = toCFA(word);
   DictValue n = {.number = cfa};
   pushDict(n);
 }

 va_end(ap);

 return addr;
} 


// 組み込みワード用Core
// 
==================================================================================== =============
void pushTwo () {
 DictValue two = {.number = 2};
 dpush(two);
 next();
}

void mul () {
 Number a = dpop().number;
 Number b = dpop().number;
 DictValue x = {.number = a * b};
 dpush(x);
 next();
}

void add () {
 Number a = dpop().number;
 Number b = dpop().number;
 DictValue x = {.number = a + b};
 dpush(x);
 next();
}

void sub () {
 Number b = dpop().number;
 Number a = dpop().number;
 DictValue x = {.number = a - b};
 dpush(x);
 next();
}


// Stack Operation

void w_swap () {
 DictValue a = dpop();
 DictValue b = dpop();
 dpush(a);
 dpush(b);
 next();
}

void w_dup () {
 DictValue x = dpop();
 dpush(x);
 dpush(x);
 next();
}

void w_drop () {
 dpop();
 next();
}


// リターンスタック

void w_rpush () {
 rpush(dpop().number);
 next();
}

void w_rpop () {
 DictValue x;
 x.number = rpop();
 dpush(x);
 next();
}


void printStackItem () {
 // printf("%d ", dpop().number);
 // Serial.print("TTTTTTT");
 Serial.print(dpop().number);
 next();
}

void printStack () {
 Serial.print(dsp);
 int i;
 for (i = 0; i < dsp; i++) {
   Serial.print(dstack[i].number);
 }
 next();
}

void ret () {
 np = rpop();
 next();
}


// vm-mode
// -------------------------------------------------------------------------------------------------
// int vm_mode = 0; // 0: execute, 1: compile
byte vm_mode = 0; // 0: execute, 1: compile

void executeMode () {
 vm_mode = 0;
} 

void w_execute_mode () {
 executeMode();
 next();
}

void compileMode () {
 vm_mode = 1;
}

void w_compile_mode () {
 compileMode();
 next();
}


// read-token>
// -------------------------------------------------------------------------------------------------
// 前方宣言
char* readToken ();

// #define TOKEN_BUFFER_SIZE 16
// #define MAX_TOKEN_LEN 128
#define TOKEN_BUFFER_SIZE 16
#define MAX_TOKEN_LEN 32

char token_buffer[TOKEN_BUFFER_SIZE][MAX_TOKEN_LEN];

int tokenBufPos () {
 // Returns token buffer position(r) and increment cycle counter(i)
 // static i = 0;
 static int i = 0;
 int r = i;

 i = (i + 1) % TOKEN_BUFFER_SIZE;
 return r;
}

char* bufferToken (char* token) {
 int pos = tokenBufPos();
 strcpy(token_buffer[pos], token);
 return token_buffer[pos];
}

void w_read_token () {
 char *token = bufferToken(readToken());
 DictValue s = {.str = token};
 dpush(s);
 next();
}

void printStr () {
 Serial.print(dpop().str);   // printf("str\n")
 Serial.print(F("\n"));
 next();
}

// 辞書操作

void w_create_header () {
 DictValue d = dpop();
 createHeader(d.str);

 // コロンワード用にdocolを置く
 DictValue docol = {.core = docolon};
 pushDict(docol);

 next();
}

void w_toggle_hidden () {
 // latestワードのhiddenフラグを切り替える
 Header *h = dict[latest].header;
 wflag *flag = h->flag;
 toggleHidden(flag);
 next();
}

void w_fetch_dict_here () {
 DictValue x = {.number = dict_here};
 dpush(x);
 next();
}

void w_set_dict_here () {
 dict_here = dpop().number;
 next();
}

void w_latest () {
 DictValue x = {.number = latest};
 dpush(x);
 next();
}

void w_store_latest () {
 latest = dpop().number;
 next();
}

void lit () {
 // lit x という順番で辞書に追加されているxを、データスタックに置く。
 // 今、npがxが入ってるアドレスを指しているので、取り出してスタックに置き、
 // その分npを進める。
 dpush(dict[np]);
 np++;
 next();
}

void w_push_dict () {
 DictValue d = dpop();
 pushDict(d);
 next();
}

void w_immediate () {
 setImmediate(latest, 1);
 next();
}

// メモリ操作

void w_mem_fetch () {
 DictValue d = dpop();
 dpush(dict[d.number]);
 next();
}

void w_mem_set () {
 DictValue a = dpop();
 DictValue v = dpop();
 dict[a.number] = v;
 next();
}

// branch

void w_branch () {
 DictValue offset = dict[np];
 np += offset.number;
 next();
}

void w_0branch () {
 Number x = dpop().number;

 if (x != 0) {
   np++;
   next();
   return;
 }

 w_branch();
}

// find, >cfa

int findWord (char *token, int addr) {
 Header *word;

 while (addr != 0) {
   word = dict[addr].header;

   if (!isHidden(word->flag) != 0 && strcmp(token, word->hname) == 0) {
     return addr;
   }

   addr = word->next;
 }

 return 0;
}

void w_find () {
 DictValue x = dpop();
 int addr = findWord(x.str, latest);
 DictValue a = {.number = addr};
 dpush(a);
 next();
}

void w_tcfa () {
 DictValue x = dpop();
 DictValue a = {.number = toCFA(x.number)};
 dpush(a);
 next();
}

// 比較
#define BINCOMP(NAME,OP)       \
void NAME () {                 \
 DictValue b = dpop();        \
 DictValue a = dpop();        \
 DictValue r = {.number = 0}; \
 if (a.number OP b.number) {  \
   r.number = 1;              \
 }                            \
 dpush(r);                    \
 next();                      \
}

BINCOMP(w_lt,  <);
BINCOMP(w_gt,  >);
BINCOMP(w_le,  <=);
BINCOMP(w_ge,  >=);
BINCOMP(w_eq,  ==);
BINCOMP(w_neq, !=);

void w_bye () {
 exit(0);
}

// コンパイル時などに使用するワード
int word_lit;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++
void prepareBuiltins () {
 
 int word_2   = defnative((char *)F("2"), pushTwo);
 int word_mul = defnative((char *)F("*"), mul);
 int word_add = defnative((char *)F("+"), add);
   
 int word_sub = defnative((char *)F("-"), sub);
 
 int word_swap = defnative((char *)F("swap"), w_swap);
 int word_dup  = defnative((char *)F("dup"),  w_dup);
 int word_drop = defnative((char *)F("drop"), w_drop);
   
 int word_rpush = defnative((char *)F(">r"), w_rpush);
 int word_rpop  = defnative((char *)F("r>"), w_rpop);
 
 int word_find = defnative((char *)F("find"), w_find);
 int word_tcfa = defnative((char *)F(">cfa"), w_tcfa);
  
 int word_dot  = defnative((char *)F("."),  printStackItem);
 int word_print_str  = defnative((char *)F("print"), printStr);
 int word_dots = defnative((char *)F(".s"), printStack);
 
 int word_ret = defnative((char *)F("ret"), ret);

 int word_read_token = defnative((char *)F("read-token>"), w_read_token);

 int word_execute_mode = defnative((char *)F("execute-mode>>"), w_execute_mode);
     setImmediate(word_execute_mode, 1);

 int word_compile_mode = defnative((char *)F("compile-mode>>"), w_compile_mode);

 int word_create_header = defnative((char *)F("create-header"), w_create_header);
 int word_toggle_hidden = defnative((char *)F("toggle-hidden"), w_toggle_hidden);

 int word_fetch_dict_here = defnative((char *)F("dict-here"), w_fetch_dict_here);
 int word_set_dict_here   = defnative((char *)F("dict-here!"), w_set_dict_here);
 
 int word_latest = defnative((char *)F("latest"), w_latest);
 int word_store_latest = defnative((char *)F("latest!"), w_store_latest);
 
 word_lit = defnative((char *)F("lit"), lit);
 int word_push_dict = defnative((char *)F("push-dict"), w_push_dict);

 int word_mem_fetch = defnative((char *)F("@"), w_mem_fetch);
 int word_mem_set   = defnative((char *)F("!"), w_mem_set);

 int word_branch  = defnative((char *)F("branch"), w_branch);
 int word_0branch = defnative((char *)F("0branch"), w_0branch);
  
 int word_immediate = defnative((char *)F("immediate!"), w_immediate);
  
 // 比較
 int word_gt  = defnative((char *)F(">"),  w_gt);
 int word_lt  = defnative((char *)F("<"),  w_lt);
 int word_ge  = defnative((char *)F(">="), w_ge);
 int word_le  = defnative((char *)F("<="), w_le);
 int word_equ = defnative((char *)F("="),  w_eq);
 int word_neq = defnative((char *)F("<>"), w_neq);
 
 // defwordの引数は0で終わること
 int word_2x   = defword((char *)F("2*"), word_2, word_mul, word_ret, 0);
 int word_4x   = defword((char *)F("4*"), word_2x, word_2x, word_ret, 0);
 int word_16x  = defword((char *)F("16*"), word_4x, word_4x, word_ret, 0);
 int word_main = defword((char *)F("main"), word_2, word_16x, word_dot, word_ret, 0);

 int word_colon = defword((char *)F(":"),
           word_read_token, word_create_header,
           word_toggle_hidden, word_compile_mode, word_ret, 0);

 int word_semicolon =
   defword((char *)F(";"),
           word_lit, word_ret, word_push_dict,
           word_toggle_hidden, word_execute_mode, word_ret, 0);
   setImmediate(word_semicolon, 1);

 int word_bye = defnative((char *)F("bye"), w_bye);
 // defnative((char *)F("bye"), w_bye);
}

// interpret
//=================================================================================================
// Reader
// -------------------------------------------------------------------------------------------------
#define READER_BUFFER_SIZE 256
// #define READER_BUFFER_SIZE 128

char rbuffer[READER_BUFFER_SIZE];
char token[READER_BUFFER_SIZE];
int  rpos = 0;
//byte  rpos = 0;

void setupReader (char *cstr) {
 memset(rbuffer, 0, READER_BUFFER_SIZE);
 strcpy(rbuffer, cstr);
 rpos = 0;
}

char reader () {
 // 呼ばれる度に入力を1文字消費して返す
 rpos++;
 return rbuffer[rpos - 1];
}

int isDelimiter (char c) {
 return (c == ' '  ||
         c == '\n' ||
         c == '\0');
}

char skipSpace () {
 // 空白と改行を読み飛ばし続け、空白以外の文字が来たらそれを返す。
 // 入力が尽きたら0を返す(NULL文字)
 char c = reader();
 // Serial.print(c); // GREEN TEST
 // Serial.print(isDelimiter(c));
 while (c != 0 && isDelimiter(c)) {
   c = reader();
 }
 // Serial.print(c); // GREEN TEST
 return c;
}

char* readToken () {
 // トークンをバッファから切り出して、グローバル変数tokenに入れてそのアドレスを返す
 // 入力が尽きていた場合はNULLを返す
 int  pos = 0;
 char c = skipSpace();
 // Serial.print(c); // GREEN TEST
  
 // 入力が尽きていた
 if (c == '\0') { return NULL; }

 // Serial.print(pos);  // GREEN TEST
 token[pos] = c;

 while (!isDelimiter(c)) {
   pos++;
   c = reader();
   token[pos] = c;
 }

 // NULL終端
 token[pos] = 0;

 Serial.print(token); // GREEN TEST
 return token;
}

// ワードの実行、又はリテラルとして解釈
// --------------------------------------------------------------------------------- ----------------
void executeCFA (int cfa) {
 ip.number = cfa;
 np = 0;
 execute();
}

void procWord (int addr) {
 int cfa = toCFA(addr);
   
Header *word = dict[addr].header;
 
 if (vm_mode == 0 || isImmediate(word->flag)) {
   executeCFA(cfa);
   return;
 }

 // コンパイル
 DictValue d = {.number = cfa};
 pushDict(d);
}

DictValue asValue (char *token, char **check) {
 // トークンを値(リテラル)として解釈し、その値を返す
 // 解釈に成功したら、checkにNULLをセットする。
 Number x = strtol(token, check, 10);
 DictValue d = {.number = x};
 return d;
}

void procValue (DictValue value) {
 if (vm_mode == 0) {
   dpush(value);
   return;
 }

 // コンパイル
 DictValue wlit = {.number = toCFA(word_lit)};
 pushDict(wlit);
 pushDict(value);
}

long int doToken (char *token) {
 // トークンを解釈し実行する。
 // 解釈できれば0、できなければ-1を返す。
 
 // DictValue dvalue ;
 int addr  = findWord(token, latest) ;
 char  *check = NULL ;
    
 // ワードが見つかった場合
 if (addr != 0) {
   procWord(addr);
   return 0;
 }

 // 数字として解釈出来た場合
  DictValue dvalue = asValue(token, &check);
 if (*check == '\0') {
   procValue(dvalue);
   return 0;
 }

 // エラー
 Serial.print(F("Word not found::"));
 Serial.print(token);
 Serial.print("::\n");
 // printf("Word not found: %s\n", token);
 return -1;
}

// コード実行
// -------------------------------------------------------------------------------------------------
void interpret (char *code) {
 // Serial.print("GREEN_TEST::");
 // Serial.print(code);  // GREEN.TEST
 // Serial.print("::GREEN_TEST\n");
 setupReader(code);
 // Serial.print(code);   // GreenTEST
 char *token = readToken();
 int succeeded = 0;

 while (token != NULL && succeeded == 0) {
   succeeded = doToken(token);
   token = readToken();
 }
}

// コマンドライン
// -------------------------------------------------------------------------------------------------
void repl () {
 // char buff[64]; //READER_BUFFER_SIZE
 char buff[READER_BUFFER_SIZE];
 // char buff[255];
 int cnt = 0;
 boolean ready = false;
 // ORIGN linux program
 // while (fgets(buff, 255, stdin)) {
 //   interpret(buff);
 // }
 while( true ) {
   if (ready)
    {
       // Serial.print("GREEN_TEST::");
       // Serial.print(buff);  // GREEN.TEST
       // Serial.print("::GREEN_TEST\n");
       interpret(buff);
       ready = false;
    } else while (Serial.available()) {
      char c = Serial.read();
       buff[cnt++] = c;
       if ((c == '\n') || (cnt == sizeof(buff)-1))
       {
           buff[cnt] = '\0';
           cnt = 0;
           ready = true;
       }
  }  }
}

/***********************************************/

void loop() {
 // put your main code here, to run repeatedly:

 //  int main (int argc, char* argv[]) {
 prepareBuiltins();

 // // if
 interpret((char *)F(": 'lit lit lit push-dict ;"));
 interpret((char *)F(": 'push-dict lit push-dict push-dict ;"));
 interpret((char *)F(": compile> 'lit read-token> find >cfa push-dict 'push-dict ; immediate!"));
 // 
 interpret((char *)F(": if compile> 0branch dict-here 0 push-dict ; immediate!"));
 interpret((char *)F(": save-offset dup dict-here swap - swap ! ;"));
 interpret((char *)F(": then save-offset ; immediate!"));
 interpret((char *)F(": save-else-offset swap save-offset ;"));
 interpret((char *)F(": else compile> branch dict-here 0 push-dict save-else-offset ; immediate!"));
 //
 // // ループ
 // // begin ... until
 interpret((char *)F(": begin dict-here ; immediate!"));
 interpret((char *)F(": until compile> 0branch dict-here - push-dict ; immediate!"));
 //
 // // begin .. again
 interpret((char *)F(": 'back-branch compile> branch dict-here - push-dict ;"));
 interpret((char *)F(": again 'back-branch ; immediate!"));
 // 
 // // begin ... while ... repeat
 interpret((char *)F(": while compile> 0branch dict-here 0 push-dict ; immediate!"));
 interpret((char *)F(": repeat  swap 'back-branch  save-offset ; immediate!"));
 // 
 interpret((char *)F(": recur latest >cfa push-dict ; immediate!"));
 // 
 //
 Serial.print("TEST command ");
 interpret((char *)F(": testcmd 1 2 + . ; immediate!"));
 interpret((char *)F(" testcmd "));
 //
 repl();
 //
 Serial.println("EXIT");
 return ;
}
 
//***************************
//***************************
void setup() {
 // put your setup code here, to run once:
 // Serial.begin(9600); 
 //******************************
 pinMode(33, OUTPUT);
 Serial.begin();  // USB does not require BAUD
 // wait for serial monitor to be connected.
 while (!Serial)
 {
   digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off
   delay(100);         // fast blink
 }
 //******************************
 Serial.println("YunoyamaFORTH");
 Serial.println("0.00");
}
//***************************