!! 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 //****************************************************** // 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 #include #include #include #include // ================================================================================================= 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"); } //***************************