- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
!! 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");
}
//***************************