Arduino-FVM
Byte Token Threaded Forth Virtual Machine (FVM) for Arduino
FVM.cpp
Go to the documentation of this file.
1 
24 #include "FVM.h"
25 
31 #define FVM_THREADING 1
32 
40 #define FVM_TRACE 1
41 
48 #define FVM_KERNEL_DICT 1
49 
55 #define FVM_KERNEL_OPT 1
56 
57 // Forth Virtual Machine support macros
58 #define OP(n) case OP_ ## n:
59 #define NEXT() goto INNER
60 #define FALLTHROUGH()
61 #define CALL(fn) tp = fn; goto FNCALL
62 #define MAP(if) (-ir-1)
63 
64 #if defined(ARDUINO_ARCH_AVR)
65 # define FNTAB(ix) (code_P) pgm_read_word(fntab+ix)
66 # define FNSTR(ix) (const __FlashStringHelper*) pgm_read_word(fnstr+ix)
67 # define OPSTR(ix) (const __FlashStringHelper*) pgm_read_word(opstr+ix)
68 #else
69 # define FNTAB(ix) fntab[ix]
70 # define FNSTR(ix) fnstr[ix]
71 # define OPSTR(ix) opstr[ix]
72 #endif
73 
74 // Configurate for threading program memory only or also data memory
75 #if (FVM_THREADING == 0) || !defined(ARDUINO_ARCH_AVR)
76 # if defined(ARDUINO_ARCH_AVR)
77 # define fetch_byte(ip) (int8_t) pgm_read_byte(ip)
78 # define fetch_word(ip) (cell_t) pgm_read_word(ip)
79 # else
80 # define fetch_byte(ip) (*((int8_t*) (ip)))
81 # define fetch_word(ip) (*((cell_t*) (ip)))
82 # endif
83 #else
84 
85 int8_t fetch_byte(FVM::code_P ip)
86 {
87  if (ip < (FVM::code_P) FVM::CODE_P_MAX)
88  return ((int8_t) pgm_read_byte(ip));
89  return (*(((int8_t*) ip) - FVM::CODE_P_MAX));
90 }
91 
93 {
94  if (ip < (FVM::code_P) FVM::CODE_P_MAX)
95  return ((FVM::cell_t) pgm_read_word(ip));
96  return (*(FVM::cell_t*) (((int8_t*) ip) - FVM::CODE_P_MAX));
97 }
98 
99 #endif
100 
101 int FVM::lookup(const char* name)
102 {
103  const char* s;
104 
105  // Search dynamic sketch dictionary, return index
106  for (int i = 0; i < m_next; i++)
107  if (!strcmp(name, m_name[i])) return (i + FVM::APPLICATION_MAX);
108 
109  // Search static sketch dictionary, return index
110  for (int i = 0; (s = (const char*) FNSTR(i)) != 0; i++)
111  if (!strcmp_P(name, s)) return (i + FVM::KERNEL_MAX);
112 
113  // Search static kernel dictionary, return index
114  for (int i = 0; (s = (const char*) OPSTR(i)) != 0; i++)
115  if (!strcmp_P(name, s)) return (i);
116 
117  // Return error code
118  return (-1);
119 }
120 
121 int FVM::scan(char* bp, task_t& task)
122 {
123  Stream& ios = task.m_ios;
124  char c;
125 
126  // Skip white space (blocking)
127  do {
128  while (!ios.available());
129  c = ios.read();
130  } while (c <= ' ');
131 
132  // Scan until white space (blocking)
133  do {
134  *bp++ = c;
135  while (!ios.available());
136  c = ios.read();
137  } while (c > ' ');
138  *bp = 0;
139 
140  return (c);
141 }
142 
144 {
145  // Restore virtual machine state
146  Stream& ios = task.m_ios;
147  const code_t** rp = task.m_rp;
148  const code_t* ip = *rp--;
149  cell_t* sp = task.m_sp;
150  cell_t tos = *sp--;
151  const code_t* tp;
152  cell_t tmp;
153  int8_t ir;
154 
155  // Benchmark support in trace mode; measure micro-seconds per operation
156 #if (FVM_TRACE == 2)
157  uint32_t start = micros();
158 #endif
159 
160  INNER:
161  // Positive opcode (0..127) are direct operation codes. Negative
162  // opcodes (-1..-128) are negative index (plus one) in threaded code
163  // table. Direct operation codes may be implemented as a primitive
164  // or as an internal threaded code call.
165  //
166  // The virtual machine allows 512 tokens. These are used as follows:
167  // Kernel tokens 0..255: 0..127 direct, 128..255 OP_SYSCALL prefix.
168  // Application tokens 256..511: 256..383 direct, -1..-128, indexing
169  // threaded code table in program memory 0..127, 384..511, indexing
170  // threaded code table in data memory 0..127 OP_CALL prefix.
171  //
172  // Kernel inner may be configured for tail call optimization.
173  //
174  // Kernel operations are documented according to ANSI X3.215-1994,
175  // American National Standard for Information Systems, Programming
176  // Languages - Forth, March 24, 1994.
177 #if (FVM_TRACE == 0)
178 
179  while ((ir = fetch_byte(ip++)) < 0) {
180 #if (FVM_KERNEL_OPT == 1)
181  if (fetch_byte(ip)) *++rp = ip;
182 #else
183  *++rp = ip;
184 #endif
185  ip = FNTAB(MAP(ir));
186  }
187 
188 #else
189  // Trace execution; micro-seconds, instruction pointer,
190  // return stack depth, token, and stack contents
191  do {
192  if (task.m_trace) {
193 #if (FVM_TRACE == 2)
194  uint32_t stop = micros();
195 #endif
196  ios.print(F("task@"));
197  ios.print((ucell_t) &task);
198  ios.print(':');
199 #if (FVM_TRACE == 2)
200  // Print measurement of latest operation; micro-seconds
201  ios.print(stop - start);
202  ios.print(':');
203  // Print current instruction pointer
204  ios.print((ucell_t) ip);
205  ios.print(':');
206  // Print current return stack depth
207  ios.print((uint16_t) (rp - task.m_rp0));
208  ios.print(':');
209 #else
210  // Print leading spaces, indent, with return stack depth
211  uint16_t depth = (uint16_t) (rp - task.m_rp0);
212  while (depth--) ios.print(' ');
213 #endif
214  }
215  // Fetch next instruction and check for threaded call or primitive
216  // Print name or token
217  ir = fetch_byte(ip++);
218  if (ir < 0 ) {
219 #if (FVM_KERNEL_OPT == 1)
220  if (fetch_byte(ip)) *++rp = ip;
221 #else
222  *++rp = ip;
223 #endif
224  ip = FNTAB(MAP(ir));
225  if (task.m_trace) {
226 #if (FVM_KERNEL_DICT == 0)
227  ios.print(KERNEL_MAX-ir-1);
228 #else
229  ios.print(FNSTR(MAP(ir)));
230 #endif
231  }
232  }
233  else if (task.m_trace) {
234 #if (FVM_KERNEL_DICT == 0)
235  ios.print(ir);
236 #else
237 #if (FVM_THREADING == 1)
238  if (ir == OP_CALL)
239  ios.print(m_name[(uint8_t) fetch_byte(ip)]);
240  else if (ir == OP_SYSCALL)
241  ios.print(OPSTR((uint8_t) fetch_byte(ip)));
242  else
243 #endif
244  ios.print(OPSTR(ir));
245 #endif
246  }
247  // Print stack contents
248  if (task.m_trace) {
249  tmp = (sp - task.m_sp0);
250  ios.print(F(":["));
251  ios.print(tmp);
252  ios.print(F("]: "));
253  if (tmp > 0) {
254  cell_t* tp = task.m_sp0 + 1;
255  while (--tmp) {
256  ios.print(*++tp);
257  ios.print(' ');
258  }
259  ios.print(tos);
260  }
261  ios.println();
262  }
263  // Flush output and start measurement
264  ios.flush();
265 #if (FVM_TRACE == 2)
266  if (task.m_trace) start = micros();
267 #endif
268  } while (ir < 0);
269 #endif
270 
271  // Dispatch instruction; primitive or internal threaded code call
272 DISPATCH:
273  switch ((uint8_t) ir) {
274 
275  // ?exit ( flag -- )
276  // Exit from call if zero/false.
277  OP(ZERO_EXIT)
278  tmp = tos;
279  tos = *sp--;
280  if (tmp != 0) NEXT();
281  FALLTHROUGH();
282 
283  // exit ( -- ) ( R: nest-sys -- )
284  // Return control to the calling definition specified by nest-sys.
285  OP(EXIT)
286  ip = *rp--;
287  NEXT();
288 
289  // (lit) ( -- x )
290  // Push literal data (little-endian).
291  OP(LIT)
292  *++sp = tos;
293  tos = (uint8_t) fetch_byte(ip++);
294  tos |= (fetch_byte(ip++) << 8);
295  NEXT();
296 
297  // (clit) ( -- x )
298  // Push literal data (signed byte).
299  OP(CLIT)
300  *++sp = tos;
301  tos = fetch_byte(ip++);
302  NEXT();
303 
304  // (var) ( -- addr )
305  // Push address of variable (pointer to cell).
306  OP(VAR)
307  *++sp = tos;
308 #if defined(ARDUINO_ARCH_AVR)
309  tos = (cell_t) (ip - CODE_P_MAX);
310 #else
311  tos = (cell_t) ip;
312 #endif
313  ip = *rp--;
314  NEXT();
315 
316  // (const) ( -- value )
317  // Push value of contant.
318  OP(CONST)
319  *++sp = tos;
320  tos = fetch_word(ip);
321  ip = *rp--;
322  NEXT();
323 
324  // (func) ( xn..x0 -- ym..y0 )
325  // Call extension function wrapper.
326  OP(FUNC)
327  {
328  void* env = (void*) fetch_word(ip + sizeof(fn_t));
329  fn_t fn = (fn_t) fetch_word(ip);
330  *++sp = tos;
331  task.m_sp = sp;
332  task.m_rp = rp;
333  fn(task, env);
334  rp = task.m_rp;
335  sp = task.m_sp;
336  tos = *sp--;
337  ip = *rp--;
338  }
339  NEXT();
340 
341  // (does) ( -- addr )
342  // Push object pointer accessed by return address.
343  OP(DOES)
344  *++sp = tos;
345  tp = *rp--;
346 #if defined(ARDUINO_ARCH_AVR)
347  tos = fetch_word(tp + 1);
348 #else
349  tos = *((cell_t*) (tp + 1));
350 #endif
351  NEXT();
352 
353  // (param) ( xn..x0 -- xn..x0 xi )
354  // Duplicate inline index stack element to top of stack.
355  OP(PARAM)
356  *++sp = tos;
357  ir = fetch_byte(ip++);
358  tos = *(sp - ir);
359  NEXT();
360 
361  // (slit) ( -- addr )
362  // Push pointer to literal and branch.
363  OP(SLIT)
364  *++sp = tos;
365  tos = (cell_t) ip + 1;
366 
367  // (branch) ( -- )
368  // Branch always (8-bit offset, -128..127).
369  OP(BRANCH)
370  ir = fetch_byte(ip);
371  ip += ir;
372  NEXT();
373 
374  // (0branch) ( flag -- )
375  // Branch zero equal/false (8-bit offset, -128..127).
376  OP(ZERO_BRANCH)
377  ir = fetch_byte(ip);
378  ip += (tos == 0) ? ir : 1;
379  tos = *sp--;
380  NEXT();
381 
382  // (do) ( n1|u1 n2|u2 -- ) ( R: -- loop-sys )
383  // Set up loop control parameters with index n2|u2 and limit
384  // n1|u1. An ambiguous condition exists if n1|u1 and n2|u2 are not
385  // both the same type. Anything already on the return stack becomes
386  // unavailable until the loop-control parameters are discarded.
387  OP(DO)
388  tmp = *sp--;
389  if (tos < tmp) {
390  *++rp = (code_t*) tmp;
391  *++rp = (code_t*) tos;
392  ip += 1;
393  }
394  else {
395  ir = fetch_byte(ip);
396  ip += ir;
397  }
398  tos = *sp--;
399  NEXT();
400 
401  // j ( -- n|u ) ( R: loop-sys1 loop-sys2 -- loop-sys1 loop-sys2 )
402  // n|u is a copy of the next-outer loop index. An ambiguous
403  // condition exists if the loop control parameters of the next-outer
404  // loop, loop-sys1, are unavailable.
405  OP(J)
406  *++sp = tos;
407  tos = (cell_t) *(rp - 2);
408  NEXT();
409 
410  // leave ( -- rp: high high )
411  // Mark loop block as completed.
412  OP(LEAVE)
413  *rp = *(rp - 1);
414  NEXT();
415 
416  // (loop) ( -- ) ( R: loop-sys1 -- | loop-sys2 )
417  // An ambiguous condition exists if the loop control parameters are
418  // unavailable. Add one to the loop index. If the loop index is then
419  // equal to the loop limit, discard the loop parameters and continue
420  // execution immediately following the loop. Otherwise continue
421  // execution at the beginning of the loop.
422  OP(LOOP)
423  *rp += 1;
424  if (*rp < *(rp - 1)) {
425  ir = fetch_byte(ip);
426  ip += ir;
427  }
428  else {
429  rp -= 2;
430  ip += 1;
431  }
432  NEXT();
433 
434  // (+loop) ( n -- )
435  // Add n to the loop index. If the loop index did not cross the
436  // boundary between the loop limit minus one and the loop limit,
437  // continue execution at the beginning of the loop. Otherwise,
438  // discard the current loop control parameters and continue
439  // execution immediately following the loop.
440  OP(PLUS_LOOP)
441  *rp += tos;
442  if (*rp < *(rp - 1)) {
443  ir = fetch_byte(ip);
444  ip += ir;
445  }
446  else {
447  rp -= 2;
448  ip += 1;
449  }
450  tos = *sp--;
451  FALLTHROUGH();
452 
453  // noop ( -- )
454  // No operation.
455  OP(NOOP)
456  NEXT();
457 
458  // execute ( i*x xt -- j*x )
459  // Remove xt from the stack and perform the semantics identified by
460  // it. Other stack effects are due to the semantics of the token.
461  OP(EXECUTE)
462  if (tos < KERNEL_MAX) {
463  ir = tos;
464  tos = *sp--;
465  goto DISPATCH;
466  }
467  else if (tos < APPLICATION_MAX) {
468  *++rp = ip;
469  ip = FNTAB(tos-KERNEL_MAX);
470  tos = *sp--;
471  }
472  else {
473  *++rp = ip;
474  ip = (code_P) m_body[tos - APPLICATION_MAX];
475  tos = *sp--;
476  }
477  NEXT();
478 
479  // halt ( -- )
480  // Halt virtual machine. Do not proceed on resume.
481  OP(HALT)
482  rp = task.m_rp0;
483  ip -= 1;
484  FALLTHROUGH();
485 
486  // yield ( -- )
487  // Yield virtual machine. Proceed on resume.
488  OP(YIELD)
489  *++sp = tos;
490  *++rp = ip;
491  task.m_sp = sp;
492  task.m_rp = rp;
493  return (ir == OP_YIELD);
494 
495  // (syscall) ( -- )
496  // System call token (0..255); compiled code.
497  OP(SYSCALL)
498  ir = fetch_byte(ip++);
499  goto DISPATCH;
500 
501  // (call) ( -- )
502  // Call application token in dynamic dictionary; 384..255
503  // are mapped to 0..127.
504  OP(CALL)
505  tmp = (uint8_t) fetch_byte(ip++);
506 #if (FVM_KERNEL_OPT == 1)
507  if (fetch_byte(ip)) *++rp = ip;
508 #else
509  *++rp = ip;
510 #endif
511  ip = (code_P) m_body[tmp];
512  NEXT();
513 
514  // trace ( flag -- )
515  // Set trace mode.
516  OP(TRACE)
517  task.m_trace = tos;
518  tos = *sp--;
519  NEXT();
520 
521  // room ( -- n bytes )
522  // Number of free dictionary entries and bytes.
523  OP(ROOM)
524  *++sp = tos;
525  *++sp = WORD_MAX - m_next;
526  tos = DICT_MAX - (m_dp - (uint8_t*) m_body);
527  NEXT();
528 
529  // c@ ( c-addr -- char )
530  // Fetch the character stored at c-addr. When the cell size is
531  // greater than character size, the unused high-order bits are all
532  // zeroes.
533  OP(C_FETCH)
534  tos = *((uint8_t*) tos);
535  NEXT();
536 
537  // c! ( char c-addr -- )
538  // Store char at c-addr. When character size is smaller than cell
539  // size, only the number of low-order bits corresponding to
540  // character size are transferred.
541  OP(C_STORE)
542  *((uint8_t*) tos) = *sp--;
543  tos = *sp--;
544  NEXT();
545 
546  // @ ( a-addr -- x )
547  // x is the value stored at a-addr.
548  OP(FETCH)
549  tos = *((cell_t*) tos);
550  NEXT();
551 
552  // ! ( x a-addr -- )
553  // Store x at a-addr.
554  OP(STORE)
555  *((cell_t*) tos) = *sp--;
556  tos = *sp--;
557  NEXT();
558 
559  // +! ( n|u a-addr -- )
560  // Add n|u to the single-cell number at a-addr.
561  OP(PLUS_STORE)
562 #if 0
563  *((cell_t*) tos) += *sp--;
564  tos = *sp--;
565  NEXT();
566 #else
567  // : +! ( n|u a-addr -- ) dup >r @ + r> ! ;
568  static const code_t PLUS_STORE_CODE[] PROGMEM = {
569  FVM_OP(DUP),
570  FVM_OP(TO_R),
571  FVM_OP(FETCH),
572  FVM_OP(PLUS),
573  FVM_OP(R_FROM),
574  FVM_OP(STORE),
575  FVM_OP(EXIT)
576  };
577  CALL(PLUS_STORE_CODE);
578 #endif
579 
580  // dp ( -- a-addr )
581  // Push address to data-space pointer.
582  OP(DP)
583  *++sp = tos;
584  tos = (cell_t) &m_dp;
585  NEXT();
586 
587  // here ( -- a-addr )
588  // a-addr is the data-space pointer.
589  OP(HERE)
590 #if 0
591  *++sp = tos;
592  tos = (cell_t) m_dp;
593  NEXT();
594 #else
595  // : here ( -- addr ) dp @ ;
596  static const code_t HERE_CODE[] PROGMEM = {
597  FVM_OP(DP),
598  FVM_OP(FETCH),
599  FVM_OP(EXIT)
600  };
601  CALL(HERE_CODE);
602 #endif
603 
604  // allot ( n -- )
605  // If n is greater than zero, reserve n address units of data
606  // space. If n is less than zero, release |n| address units of data
607  // space. If n is zero, leave the data-space pointer unchanged.
608  OP(ALLOT)
609 #if 0
610  m_dp += tos;
611  tos = *sp--;
612  NEXT();
613 #else
614  // : allot ( n -- ) dp +! ;
615  static const code_t ALLOT_CODE[] PROGMEM = {
616  FVM_OP(DP),
617  FVM_OP(PLUS_STORE),
618  FVM_OP(EXIT)
619  };
620  CALL(ALLOT_CODE);
621 #endif
622 
623  // , ( x -- )
624  // Reserve one cell of data space and store x in the cell.
625  OP(COMMA)
626 #if 0
627  *((cell_t*) m_dp) = tos;
628  m_dp += sizeof(cell_t);
629  tos = *sp--;
630  NEXT();
631 #else
632  // : , ( x -- ) here ! cell allot ;
633  static const code_t COMMA_CODE[] PROGMEM = {
634  FVM_OP(HERE),
635  FVM_OP(STORE),
636  FVM_OP(CELL),
637  FVM_OP(ALLOT),
638  FVM_OP(EXIT)
639  };
640  CALL(COMMA_CODE);
641 #endif
642 
643  // c, ( char -- )
644  // Reserve space for one character in the data space and store char
645  // in the space.
646  OP(C_COMMA)
647 #if 0
648  *m_dp++ = tos;
649  tos = *sp--;
650  NEXT();
651 #else
652  // : c, ( x -- ) here c! 1 allot ;
653  static const code_t C_COMMA_CODE[] PROGMEM = {
654  FVM_OP(HERE),
655  FVM_OP(C_STORE),
656  FVM_OP(ONE),
657  FVM_OP(ALLOT),
658  FVM_OP(EXIT)
659  };
660  CALL(C_COMMA_CODE);
661 #endif
662 
663  // (compile) ( -- )
664  // Add inline token (0..255) to compile stream.
665  OP(COMPILE)
666  *m_dp++ = fetch_byte(ip++);
667  NEXT();
668 
669  // >r ( x -- ) ( R: -- x )
670  // Move x to the return stack.
671  OP(TO_R)
672  *++rp = (code_t*) tos;
673  tos = *sp--;
674  NEXT();
675 
676  // r> ( -- x ) ( R: x -- )
677  // Move x from the return stack to the data stack.
678  OP(R_FROM)
679  *++sp = tos;
680  tos = (cell_t) *rp--;
681  NEXT();
682 
683  // i ( -- n|u ) ( R: loop-sys -- loop-sys )
684  // n|u is a copy of the current (innermost) loop index. An ambiguous
685  // condition exists if the loop control parameters are unavailable.
686  OP(I)
687  FALLTHROUGH();
688 
689  // r@ ( -- x ) ( R: x -- x )
690  // Copy x from the return stack to the data stack.
691  OP(R_FETCH)
692  *++sp = tos;
693  tos = (cell_t) *rp;
694  NEXT();
695 
696  // sp ( -- addr )
697  // Push stack pointer.
698  OP(SP)
699  *++sp = tos;
700  tos = (cell_t) sp;
701  NEXT();
702 
703  // depth ( -- +n )
704  // +n is the number of single-cell values contained in the data
705  // stack before +n was placed on the stack.
706  OP(DEPTH)
707  tmp = (sp - task.m_sp0);
708  *++sp = tos;
709  tos = tmp;
710  NEXT();
711 
712  // drop ( x -- )
713  // Remove x from the stack.
714  OP(DROP)
715  tos = *sp--;
716  NEXT();
717 
718  // nip ( x1 x2 -- x2 )
719  // Drop the first item below the top of stack.
720  OP(NIP)
721 #if 1
722  sp -= 1;
723  NEXT();
724 #else
725  // : nip ( x1 x2 -- x2 ) swap drop ;
726  static const code_t NIP_CODE[] PROGMEM = {
727  FVM_OP(SWAP),
728  FVM_OP(DROP),
729  FVM_OP(EXIT)
730  };
731  CALL(NIP_CODE);
732 #endif
733 
734  // empty ( xn...x0 -- )
735  // Empty data stack.
736  OP(EMPTY)
737  sp = task.m_sp0;
738  NEXT();
739 
740  // dup ( x -- x x )
741  // Duplicate x.
742  OP(DUP)
743 #if 1
744  *++sp = tos;
745  NEXT();
746 #else
747  // : dup ( x -- x x ) param: 0 ;
748  static const code_t DUP_CODE[] PROGMEM = {
749  FVM_OP(PARAM), 0,
750  FVM_OP(EXIT)
751  };
752  CALL(DUP_CODE);
753 #endif
754 
755  // ?dup ( x -- 0 | x x )
756  // Duplicate x if it is non-zero.
757  OP(QUESTION_DUP)
758 #if 1
759  if (tos != 0) *++sp = tos;
760  NEXT();
761 #else
762  // : ?dup ( x -- 0 | x x ) dup ?exit dup ;
763  static const code_t QUESTION_DUP_CODE[] PROGMEM = {
764  FVM_OP(DUP),
765  FVM_OP(ZERO_EXIT),
766  FVM_OP(DUP),
767  FVM_OP(EXIT)
768  };
769  CALL(QUESTION_DUP_CODE);
770 #endif
771 
772  // over ( x1 x2 -- x1 x2 x1 )
773  // Place a copy of x 1 on top of the stack.
774  OP(OVER)
775 #if 1
776  tmp = *sp;
777  *++sp = tos;
778  tos = tmp;
779  NEXT();
780 #else
781  // : over ( x1 x2 -- x1 x2 x1 ) param: 1 ;
782  static const code_t OVER_CODE[] PROGMEM = {
783  FVM_OP(PARAM), 1,
784  FVM_OP(EXIT)
785  };
786  CALL(OVER_CODE);
787 #endif
788 
789  // tuck ( x1 x2 -- x2 x1 x2 )
790  // Copy the first (top) stack item below the second stack item.
791  OP(TUCK)
792 #if 0
793  tmp = *sp;
794  *sp = tos;
795  *++sp = tmp;
796  NEXT();
797 #else
798  // : tuck ( x1 x2 -- x2 x1 x2 ) swap over ;
799  static const code_t TUCK_CODE[] PROGMEM = {
800  FVM_OP(SWAP),
801  FVM_OP(OVER),
802  FVM_OP(EXIT)
803  };
804  CALL(TUCK_CODE);
805 #endif
806 
807  // pick ( xn..x0 i -- xn..x0 xi )
808  // Duplicate index stack element to top of stack.
809  OP(PICK)
810  tos = *(sp - tos);
811  NEXT();
812 
813  // swap ( x1 x2 -- x2 x1 )
814  // Exchange the top two stack items.
815  OP(SWAP)
816 #if 1
817  tmp = tos;
818  tos = *sp;
819  *sp = tmp;
820  NEXT();
821 #else
822  // : swap ( x1 x2 -- x2 x1 ) 1 roll ;
823  static const code_t SWAP_CODE[] PROGMEM = {
824  FVM_OP(ONE),
825  FVM_OP(ROLL),
826  FVM_OP(EXIT)
827  };
828  CALL(SWAP_CODE);
829 #endif
830 
831  // rot ( x1 x2 x3 -- x2 x3 x1 )
832  // Rotate the top three stack entries.
833  OP(ROT)
834 #if 1
835  tmp = tos;
836  tos = *(sp - 1);
837  *(sp - 1) = *sp;
838  *sp = tmp;
839  NEXT();
840 #else
841  // : rot ( x1 x2 x3 -- x2 x3 x1 ) 2 roll ;
842  static const code_t ROT_CODE[] PROGMEM = {
843  FVM_OP(TWO),
844  FVM_OP(ROLL),
845  FVM_OP(EXIT)
846  };
847  CALL(ROT_CODE);
848 #endif
849 
850  // -rot ( x1 x2 x3 -- x3 x1 x2 )
851  // Rotate down top three stack elements.
852  OP(MINUS_ROT)
853 #if 0
854  tmp = tos;
855  tos = *sp;
856  *sp = *(sp - 1);
857  *(sp - 1) = tmp;
858  NEXT();
859 #else
860  // : -rot ( x1 x2 x3 -- x3 x1 x2 ) rot rot ;
861  static const code_t MINUS_ROT_CODE[] PROGMEM = {
862  FVM_OP(ROT),
863  FVM_OP(ROT),
864  FVM_OP(EXIT)
865  };
866  CALL(MINUS_ROT_CODE);
867 #endif
868 
869  // roll ( xn..x0 n -- xn-1..x0 xn )
870  // Rotate up n+1 stack elements.
871  OP(ROLL)
872  tmp = tos;
873  tos = sp[-tmp];
874  for (; tmp > 0; tmp--)
875  sp[-tmp] = sp[-tmp + 1];
876  sp -= 1;
877  NEXT();
878 
879  // 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
880  // Exchange the top two cell pairs.
881  OP(TWO_SWAP)
882  // : 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 ) rot >r rot r> ;
883  static const code_t TWO_SWAP_CODE[] PROGMEM = {
884  FVM_OP(ROT),
885  FVM_OP(TO_R),
886  FVM_OP(ROT),
887  FVM_OP(R_FROM),
888  FVM_OP(EXIT)
889  };
890  CALL(TWO_SWAP_CODE);
891 
892  // 2dup ( x1 x2 -- x1 x2 x1 x2)
893  // Duplicate cell pair x1 x2.
894  OP(TWO_DUP)
895  // : 2dup ( x1 x2 -- x1 x2 x1 x2) over over ;
896  static const code_t TWO_DUP_CODE[] PROGMEM = {
897  FVM_OP(OVER),
898  FVM_OP(OVER),
899  FVM_OP(EXIT)
900  };
901  CALL(TWO_DUP_CODE);
902 
903  // 2over ( x1 x2 y1 y2 -- x1 y1 y1 y2 x1 x2 )
904  // Copy cell pair x1 x2 to the top of the stack.
905  OP(TWO_OVER)
906  // : 2over ( x1 x2 y1 y2 -- x1 y1 y1 y2 x1 x2 ) param: 3 param: 3 ;
907  static const code_t TWO_OVER_CODE[] PROGMEM = {
908  FVM_OP(PARAM), 3,
909  FVM_OP(PARAM), 3,
910  FVM_OP(EXIT)
911  };
912  CALL(TWO_OVER_CODE);
913 
914  // 2drop ( x1 x2 -- )
915  // Drop cell pair x1 x2 from the stack.
916  OP(TWO_DROP)
917  // : 2drop ( x1 x2 -- ) drop drop ;
918  static const code_t TWO_DROP_CODE[] PROGMEM = {
919  FVM_OP(DROP),
920  FVM_OP(DROP),
921  FVM_OP(EXIT)
922  };
923  CALL(TWO_DROP_CODE);
924 
925  // -2 ( -- -2 )
926  // Constant -2.
927  OP(MINUS_TWO)
928  *++sp = tos;
929  tos = -2;
930  NEXT();
931 
932  // -1 ( -- -1 )
933  // Constant -1.
934  OP(MINUS_ONE)
935  FALLTHROUGH();
936 
937  // TRUE ( -- -1 )
938  // Constant true (alias -1).
939  OP(TRUE)
940  *++sp = tos;
941  tos = -1;
942  NEXT();
943 
944  // 0 ( -- 0 )
945  // Constant 0.
946  OP(ZERO)
947  FALLTHROUGH();
948 
949  // FALSE ( -- 0 )
950  // Constant false.
951  OP(FALSE)
952  *++sp = tos;
953  tos = 0;
954  NEXT();
955 
956  // 1 ( -- 1 )
957  // Constant 1.
958  OP(ONE)
959  *++sp = tos;
960  tos = 1;
961  NEXT();
962 
963  // 2 ( -- 2 )
964  // Constant 2.
965  OP(TWO)
966  *++sp = tos;
967  tos = 2;
968  NEXT();
969 
970  // cell ( -- n )
971  // Size of data element in bytes.
972  OP(CELL)
973  *++sp = tos;
974  tos = sizeof(cell_t);
975  NEXT();
976 
977  // cells ( x -- y )
978  // Convert cells to bytes for allot.
979  OP(CELLS)
980 #if 1
981  tos *= sizeof(cell_t);
982  NEXT();
983 #else
984  // : cells ( x -- y ) cell * ;
985  static const code_t CELLS_CODE[] PROGMEM = {
986  FVM_OP(CELL),
987  FVM_OP(STAR),
988  FVM_OP(EXIT)
989  };
990  CALL(CELLS_CODE);
991 #endif
992 
993  // invert ( x1 -- x2 )
994  // Invert all bits of x1, giving its logical inverse x2.
995  OP(INVERT)
996  tos = ~tos;
997  NEXT();
998 
999  // and ( x1 x2 -- x3 )
1000  // x3 is the bit-by-bit logical “and” of x1 with x2.
1001  OP(AND)
1002  tos = *sp-- & tos;
1003  NEXT();
1004 
1005  // or ( x1 x2 -- x3 )
1006  // x3 is the bit-by-bit inclusive-or of x1 with x2.
1007  OP(OR)
1008  tos = *sp-- | tos;
1009  NEXT();
1010 
1011  // xor ( x1 x2 -- x3 )
1012  // x3 is the bit-by-bit exclusive-or of x1 with x2.
1013  OP(XOR)
1014  tos = *sp-- ^ tos;
1015  NEXT();
1016 
1017  // negate ( n1 -- n2 )
1018  // Negate n1, giving its arithmetic inverse n2.
1019  OP(NEGATE)
1020 #if 1
1021  tos = -tos;
1022  NEXT();
1023 #else
1024  // : negate ( n1 -- n2 ) invert 1+ ;
1025  static const code_t NEGATE_CODE[] PROGMEM = {
1026  FVM_OP(INVERT),
1027  FVM_OP(ONE_PLUS),
1028  FVM_OP(EXIT)
1029  };
1030  CALL(NEGATE_CODE);
1031 #endif
1032 
1033  // 1+ ( n1|u1 -- n2|u2 )
1034  // Add one (1) to n1|u1 giving the sum n2|u2.
1035  OP(ONE_PLUS)
1036  tos += 1;
1037  NEXT();
1038 
1039  // 1- ( n1|u1 -- n2|u2 )
1040  // Subtract one (1) from n1|u1 giving the difference n2|u2.
1041  OP(ONE_MINUS)
1042  tos -= 1;
1043  NEXT();
1044 
1045  // 2+ ( n1|u1 -- n2|u2 )
1046  // Add two (2) to n1|u1 giving the sum n2|u2.
1047  OP(TWO_PLUS)
1048  tos += 2;
1049  NEXT();
1050 
1051  // 2- ( n1|u1 -- n2|u2 )
1052  // Subtract two (2) from n1|u1 giving the difference n2|u2.
1053  OP(TWO_MINUS)
1054  tos -= 2;
1055  NEXT();
1056 
1057  // 2* ( x1 -- x2 )
1058  // x2 is the result of shifting x1 one bit toward the most-
1059  // significant bit, filling the vacated least-significant bit
1060  // with zero.
1061  OP(TWO_STAR)
1062  tos <<= 1;
1063  NEXT();
1064 
1065  // 2/ ( x1 -- x2 )
1066  // x2 is the result of shifting x1 one bit toward the
1067  // least-significant bit, leaving the most-significant bit
1068  // unchanged.
1069  OP(TWO_SLASH)
1070  tos >>= 1;
1071  NEXT();
1072 
1073  // + ( n1|u1 n2|u2 -- n3|u3 )
1074  // Add n2|u2 to n1|u1, giving the sum n3|u3.
1075  OP(PLUS)
1076  tos = *sp-- + tos;
1077  NEXT();
1078 
1079  // - ( n1|u1 n2|u2 -- n3|u3 )
1080  // Subtract n2|u2 from n1|u1, giving the difference n3|u3.
1081  OP(MINUS)
1082  tos = *sp-- - tos;
1083  NEXT();
1084 
1085  // * ( n1|u1 n2|u2 -- n3|u3 )
1086  // Multiply n1|u1 by n2|u2 giving the product n3|u3.
1087  OP(STAR)
1088  tos = *sp-- * tos;
1089  NEXT();
1090 
1091  // */ ( n1 n2 n3 -- n4 )
1092  // Multiply n1 by n2 producing the intermediate double-cell result
1093  // d. Divide d by n3 giving the single-cell quotient n4. An
1094  // ambiguous condition exists if n3 is zero or if the quotient n4
1095  // lies outside the range of a signed number.
1096  OP(STAR_SLASH)
1097  tmp = *sp--;
1098  tos = (((cell2_t) tmp) * (*sp--)) / tos;
1099  NEXT();
1100 
1101  // / ( n1 n2 -- n3 )
1102  // Divide n1 by n2, giving the single-cell quotient n3. An
1103  // ambiguous condition exists if n2 is zero.
1104  OP(SLASH)
1105  tos = *sp-- / tos;
1106  NEXT();
1107 
1108  // mod ( n1 n2 -- n3 )
1109  // Divide n1 by n2, giving the single-cell remainder n3. An
1110  // ambiguous condition exists if n2 is zero.
1111  OP(MOD)
1112  tos = *sp-- % tos;
1113  NEXT();
1114 
1115  // /mod ( n1 n2 -- n3 n4 )
1116  // Divide n1 by n2, giving the single-cell remainder n3 and the
1117  // single-cell quotient n4. An ambiguous condition exists if n2 is
1118  // zero.
1119  OP(SLASH_MOD)
1120  tmp = *sp / tos;
1121  tos = *sp % tos;
1122  *sp = tmp;
1123  NEXT();
1124 
1125  // lshift ( x1 u -- x2 )
1126  // Perform a logical left shift of u bit-places on x1, giving
1127  // x2. Put zeroes into the least significant bits vacated by the
1128  // shift. An ambiguous condition exists if u is greater than or
1129  // equal to the number of bits in a cell.
1130  OP(LSHIFT)
1131  tos = *sp-- << tos;
1132  NEXT();
1133 
1134  // rshift ( x1 u -- x2 )
1135  // Perform a logical right shift of u bit-places on x1, giving x2.
1136  // Put zeroes into the most significant bits vacated by the
1137  // shift. An ambiguous condition exists if u is greater than or
1138  // equal to the number of bits in a cell.
1139  OP(RSHIFT)
1140  tos = *sp-- >> tos;
1141  NEXT();
1142 
1143  // within ( n1|u1 n2|u2 n3|u3 -- flag )
1144  // Perform a comparison of a test value n1|u 1 with a lower limit
1145  // n2|u2 and an upper limit n3|u3, returning true if either (n2|u2 <
1146  // n3|u3 and (n2|u2 <= n1|u1 and n1|u1 < n3|u3)) or (n2|u2 > n3|u3
1147  // and (n2|u2 <= n1|u1 or n1|u1 < n3|u3)) is true, returning false
1148  // otherwise.
1149  OP(WITHIN)
1150 #if 0
1151  tmp = *sp--;
1152  tos = ((*sp <= tos) & (*sp >= tmp)) ? -1 : 0;
1153  sp--;
1154  NEXT();
1155 #else
1156  // : within ( n1|u1 n2|u2 n3|u3 -- flag ) >r over swap < swap r> > or not ;
1157  static const code_t WITHIN_CODE[] PROGMEM = {
1158  FVM_OP(TO_R),
1159  FVM_OP(OVER),
1160  FVM_OP(SWAP),
1161  FVM_OP(LESS),
1162  FVM_OP(SWAP),
1163  FVM_OP(R_FROM),
1164  FVM_OP(GREATER),
1165  FVM_OP(OR),
1166  FVM_OP(NOT),
1167  FVM_OP(EXIT)
1168  };
1169  CALL(WITHIN_CODE);
1170 #endif
1171 
1172  // abs ( n -- u )
1173  // u is the absolute value of n.
1174  OP(ABS)
1175 #if 0
1176  if (tos < 0) tos = -tos;
1177  NEXT();
1178 #elif 1
1179  // : abs ( n -- u ) dup 0< ?exit negate ;
1180  static const code_t ABS_CODE[] PROGMEM = {
1181  FVM_OP(DUP),
1182  FVM_OP(ZERO_LESS),
1183  FVM_OP(ZERO_EXIT),
1184  FVM_OP(NEGATE),
1185  FVM_OP(EXIT)
1186  };
1187  CALL(ABS_CODE);
1188 #else
1189  // : abs ( n -- u ) dup 0< swap over + xor ;
1190  static const code_t ABS_CODE[] PROGMEM = {
1191  FVM_OP(DUP),
1192  FVM_OP(ZERO_LESS),
1193  FVM_OP(SWAP),
1194  FVM_OP(OVER),
1195  FVM_OP(PLUS),
1196  FVM_OP(XOR),
1197  FVM_OP(EXIT)
1198  };
1199  CALL(ABS_CODE);
1200 #endif
1201 
1202  // min ( n1 n2 -- n3 )
1203  // n3 is the lesser of n1 and n2.
1204  OP(MIN)
1205 #if 0
1206  tmp = *sp--;
1207  if (tmp < tos) tos = tmp;
1208  NEXT();
1209 #elif 0
1210  // : min ( n1 n2 -- n3 ) 2dup > if swap then drop ;
1211  static const code_t MIN_CODE[] PROGMEM = {
1212  FVM_OP(TWO_DUP),
1213  FVM_OP(GREATER),
1214  FVM_OP(ZERO_BRANCH), 2,
1215  FVM_OP(SWAP),
1216  FVM_OP(DROP),
1217  FVM_OP(EXIT)
1218  };
1219  CALL(MIN_CODE);
1220 #else
1221  // : min ( n1 n2 -- n3 ) over - dup 0< and + ;
1222  static const code_t MIN_CODE[] PROGMEM = {
1223  FVM_OP(OVER),
1224  FVM_OP(MINUS),
1225  FVM_OP(DUP),
1226  FVM_OP(ZERO_LESS),
1227  FVM_OP(AND),
1228  FVM_OP(PLUS),
1229  FVM_OP(EXIT)
1230  };
1231  CALL(MIN_CODE);
1232 #endif
1233 
1234  // max ( n1 n2 -- n3 )
1235  // n3 is the greater of n1 and n2.
1236  OP(MAX)
1237 #if 0
1238  tmp = *sp--;
1239  if (tmp > tos) tos = tmp;
1240  NEXT();
1241 #elif 0
1242  // : max ( n1 n2 -- n3 ) 2dup < if swap then drop ;
1243  static const code_t MAX_CODE[] PROGMEM = {
1244  FVM_OP(TWO_DUP),
1245  FVM_OP(LESS),
1246  FVM_OP(ZERO_BRANCH), 2,
1247  FVM_OP(SWAP),
1248  FVM_OP(DROP),
1249  FVM_OP(EXIT)
1250  };
1251  CALL(MAX_CODE);
1252 #else
1253  // : max ( n1 n2 -- n3 ) over swap - dup 0< and - ;
1254  static const code_t MAX_CODE[] PROGMEM = {
1255  FVM_OP(OVER),
1256  FVM_OP(SWAP),
1257  FVM_OP(MINUS),
1258  FVM_OP(DUP),
1259  FVM_OP(ZERO_LESS),
1260  FVM_OP(AND),
1261  FVM_OP(MINUS),
1262  FVM_OP(EXIT)
1263  };
1264  CALL(MAX_CODE);
1265 #endif
1266 
1267  // bool ( x -- flag )
1268  // flag is true if and only if x is not equal to zero.
1269  OP(BOOL)
1270  FALLTHROUGH();
1271 
1272  // 0<> ( x -- flag )
1273  // flag is true if and only if x is not equal to zero.
1274  OP(ZERO_NOT_EQUALS)
1275 #if 1
1276  tos = (tos != 0) ? -1 : 0;
1277  NEXT();
1278 #else
1279  // : 0<> ( x -- flag ) 0= not ;
1280  static const code_t ZERO_NOT_EQUALS_CODE[] PROGMEM = {
1281  FVM_OP(ZERO_EQUALS),
1282  FVM_OP(NOT),
1283  FVM_OP(EXIT)
1284  };
1285  CALL(ZERO_NOT_EQUALS_CODE);
1286 #endif
1287 
1288  // 0< ( n -- flag )
1289  // flag is true if and only if n is less than zero.
1290  OP(ZERO_LESS)
1291 #if 1
1292  tos = (tos < 0) ? -1 : 0;
1293  NEXT();
1294 #else
1295  // : 0< ( n -- flag ) 15 rshift ;
1296  static const code_t ZERO_LESS_CODE[] PROGMEM = {
1297  FVM_CLIT(15),
1298  FVM_OP(RSHIFT),
1299  FVM_OP(EXIT)
1300  };
1301  CALL(ZERO_LESS_CODE);
1302 #endif
1303 
1304  // not ( x -- flag )
1305  // flag is true if and only if x is equal to zero.
1306  OP(NOT)
1307  FALLTHROUGH();
1308 
1309  // 0= ( x -- flag )
1310  // flag is true if and only if x is equal to zero.
1311  OP(ZERO_EQUALS)
1312  tos = (tos == 0) ? -1 : 0;
1313  NEXT();
1314 
1315  // 0> ( n -- flag )
1316  // flag is true if and only if n is greater than zero.
1317  OP(ZERO_GREATER)
1318  tos = (tos > 0) ? -1 : 0;
1319  NEXT();
1320 
1321  // <> ( x1 x2 -- flag )
1322  // flag is true if and only if x1 is not bit-for-bit the same as x2.
1323  OP(NOT_EQUALS)
1324 #if 0
1325  tos = (*sp-- != tos) ? -1 : 0;
1326  NEXT();
1327 #else
1328  // : <> ( x1 x2 -- flag ) - bool ;
1329  static const code_t NOT_EQUALS_CODE[] PROGMEM = {
1330  FVM_OP(MINUS),
1331  FVM_OP(BOOL),
1332  FVM_OP(EXIT)
1333  };
1334  CALL(NOT_EQUALS_CODE);
1335 #endif
1336 
1337  // < ( n1 n2 -- flag )
1338  // flag is true if and only if n1 is less than n2.
1339  OP(LESS)
1340 #if 0
1341  tos = (*sp-- < tos) ? -1 : 0;
1342  NEXT();
1343 #else
1344  // : < ( n1 n2 -- flag ) - 0< ;
1345  static const code_t LESS_CODE[] PROGMEM = {
1346  FVM_OP(MINUS),
1347  FVM_OP(ZERO_LESS),
1348  FVM_OP(EXIT)
1349  };
1350  CALL(LESS_CODE);
1351 #endif
1352 
1353  // = ( x1 x2 -- flag )
1354  // flag is true if and only if x1 is bit-for-bit the same as x2.
1355  OP(EQUALS)
1356 #if 0
1357  tos = (*sp-- == tos) ? -1 : 0;
1358  NEXT();
1359 #else
1360  // : = ( x1 x2 -- flag ) - 0= ;
1361  static const code_t EQUALS_CODE[] PROGMEM = {
1362  FVM_OP(MINUS),
1363  FVM_OP(ZERO_EQUALS),
1364  FVM_OP(EXIT)
1365  };
1366  CALL(EQUALS_CODE);
1367 #endif
1368 
1369  // > ( n1 n2 -- flag )
1370  // flag is true if and only if n1 is greater than n2.
1371  OP(GREATER)
1372 #if 0
1373  tos = (*sp-- > tos) ? -1 : 0;
1374  NEXT();
1375 #else
1376  // : > ( n1 n2 -- flag ) - 0> ;
1377  static const code_t GREATER_CODE[] PROGMEM = {
1378  FVM_OP(MINUS),
1379  FVM_OP(ZERO_GREATER),
1380  FVM_OP(EXIT)
1381  };
1382  CALL(GREATER_CODE);
1383 #endif
1384 
1385  // u< ( u1 u2 -- flag )
1386  // flag is true if and only if u1 is less than u2.
1387  OP(U_LESS)
1388  tos = ((ucell_t) *sp-- < (ucell_t) tos) ? -1 : 0;
1389  NEXT();
1390 
1391  // lookup ( str -- n )
1392  // Lookup string in dictionary.
1393  OP(LOOKUP)
1394  tos = lookup((const char*) tos);
1395  NEXT();
1396 
1397  // >body ( xt -- a-addr )
1398  // a-addr is the data-field address corresponding to xt. An
1399  // ambiguous condition exists if xt is not for a defined word.
1400  OP(TO_BODY)
1401  tp = FNTAB(tos-KERNEL_MAX);
1402  tos = fetch_word(tp+1);
1403  NEXT();
1404 
1405  // words ( -- )
1406  // Print words in dictionary.
1407  OP(WORDS)
1408 #if 0
1409  {
1410  const char* s;
1411  int len;
1412  int nr = 0;
1413  for (int i = 0; (s = (const char*) OPSTR(i)) != 0; i++) {
1414  len = ios.print((const __FlashStringHelper*) s);
1415  if (++nr % 5 == 0)
1416  ios.println();
1417  else {
1418  for (;len < 16; len++) ios.print(' ');
1419  }
1420  }
1421  for (int i = 0; (s = (const char*) FNSTR(i)) != 0; i++) {
1422  len = ios.print((const __FlashStringHelper*) s);
1423  if (++nr % 5 == 0)
1424  ios.println();
1425  else {
1426  for (;len < 16; len++) ios.print(' ');
1427  }
1428  }
1429  }
1430  NEXT();
1431 #else
1432  // : words ( -- )
1433  // 0 begin
1434  // begin
1435  // dup .name ?dup
1436  // while
1437  // >r 1+ dup 5 mod
1438  // if 16 r> - spaces
1439  // else cr r> drop
1440  // then
1441  // repeat
1442  // cr
1443  // 255 > if exit then
1444  // 256
1445  // again ;
1446  static const code_t WORDS_CODE[] PROGMEM = {
1447  FVM_OP(ZERO),
1448  FVM_OP(DUP),
1449  FVM_OP(DOT_NAME),
1450  FVM_OP(QUESTION_DUP),
1451  FVM_OP(ZERO_BRANCH), 21,
1452  FVM_OP(TO_R),
1453  FVM_OP(ONE_PLUS),
1454  FVM_OP(DUP),
1455  FVM_CLIT(5),
1456  FVM_OP(MOD),
1457  FVM_OP(ZERO_BRANCH), 8,
1458  FVM_CLIT(16),
1459  FVM_OP(R_FROM),
1460  FVM_OP(MINUS),
1461  FVM_OP(SPACES),
1462  FVM_OP(BRANCH), -19,
1463  FVM_OP(CR),
1464  FVM_OP(R_FROM),
1465  FVM_OP(DROP),
1466  FVM_OP(BRANCH), -24,
1467  FVM_OP(CR),
1468  FVM_LIT(255),
1469  FVM_OP(GREATER),
1470  FVM_OP(ZERO_BRANCH), 2,
1471  FVM_OP(EXIT),
1472  FVM_CLIT(16),
1473  FVM_OP(SPACES),
1474  FVM_LIT(256),
1475  FVM_OP(BRANCH), -40
1476  };
1477  CALL(WORDS_CODE);
1478 #endif
1479 
1480  // base ( -- a-addr )
1481  // a-addr is the address of a cell containing the current
1482  // number-conversion radix.
1483  OP(BASE)
1484  *++sp = tos;
1485  tos = (cell_t) &task.m_base;
1486  NEXT();
1487 
1488  // hex ( -- )
1489  // Set the numeric conversion radix to sixteen (hexa-decimal).
1490  OP(HEX)
1491 #if 0
1492  task.m_base = 16;
1493  NEXT();
1494 #else
1495  // : hex ( -- ) 16 base ! ;
1496  static const code_t HEX_CODE[] PROGMEM = {
1497  FVM_CLIT(16),
1498  FVM_OP(BASE),
1499  FVM_OP(STORE),
1500  FVM_OP(EXIT)
1501  };
1502  CALL(HEX_CODE);
1503 #endif
1504 
1505  // decimal ( -- )
1506  // Set the numeric conversion radix to ten (decimal).
1507  OP(DECIMAL)
1508 #if 0
1509  task.m_base = 10;
1510  NEXT();
1511 #else
1512  // : decimal ( -- ) 10 base ! ;
1513  static const code_t DECIMAL_CODE[] PROGMEM = {
1514  FVM_CLIT(10),
1515  FVM_OP(BASE),
1516  FVM_OP(STORE),
1517  FVM_OP(EXIT)
1518  };
1519  CALL(DECIMAL_CODE);
1520 #endif
1521 
1522  // ?key ( -- c true | false )
1523  // Read character if available.
1524  OP(QUESTION_KEY)
1525  *++sp = tos;
1526  if (ios.available()) {
1527  *++sp = ios.read();
1528  tos = -1;
1529  }
1530  else {
1531  tos = 0;
1532  }
1533  NEXT();
1534 
1535  // key ( -- char )
1536  // Receive one character char, a member of the implementation-
1537  // defined character set. Keyboard events that do not correspond to
1538  // such characters are discarded until a valid character is
1539  // received, and those events are subsequently unavailable. All
1540  // standard characters can be received. Characters
1541  // received are not displayed.
1542  OP(KEY)
1543  // : key ( -- char ) begin ?key ?exit yield again ;
1544  static const code_t KEY_CODE[] PROGMEM = {
1545  FVM_OP(QUESTION_KEY),
1546  FVM_OP(NOT),
1547  FVM_OP(ZERO_EXIT),
1548  FVM_OP(YIELD),
1549  FVM_OP(BRANCH), -5,
1550  };
1551  CALL(KEY_CODE);
1552 
1553  // emit ( x -- )
1554  // If x is a graphic character in the implementation-defined
1555  // character set, display x. The effect for all other values
1556  // of x is implementation-defined.
1557  OP(EMIT)
1558  ios.print((char) tos);
1559  tos = *sp--;
1560  NEXT();
1561 
1562  // cr ( -- )
1563  // Cause subsequent output to appear at the beginning of the next
1564  // line.
1565  OP(CR)
1566 #if 1
1567  ios.println();
1568  NEXT();
1569 #else
1570  // : cr ( -- ) '\n' emit ;
1571  static const code_t CR_CODE[] PROGMEM = {
1572  FVM_CLIT('\n'),
1573  FVM_OP(EMIT),
1574  FVM_OP(EXIT)
1575  };
1576  CALL(CR_CODE);
1577 #endif
1578 
1579  // space ( -- )
1580  // Display one space.
1581  OP(SPACE)
1582 #if 1
1583  ios.print(' ');
1584  NEXT();
1585 #else
1586  // : space ( -- ) ' ' emit ;
1587  static const code_t SPACE_CODE[] PROGMEM = {
1588  FVM_CLIT(' '),
1589  FVM_OP(EMIT),
1590  FVM_OP(EXIT)
1591  };
1592  CALL(SPACE_CODE);
1593 #endif
1594 
1595  // spaces ( n -- )
1596  // If n is greater than zero, display n spaces.
1597  OP(SPACES)
1598 #if 0
1599  while (tos-- > 0) ios.print(' ');
1600  tos = *sp--;
1601  NEXT();
1602 #else
1603  // : spaces ( n -- ) 0 do space loop ;
1604  static const code_t SPACES_CODE[] PROGMEM = {
1605  FVM_OP(ZERO),
1606  FVM_OP(DO), 4,
1607  FVM_OP(SPACE),
1608  FVM_OP(LOOP), -2,
1609  FVM_OP(EXIT)
1610  };
1611  CALL(SPACES_CODE);
1612 #endif
1613 
1614  // u. ( u -- )
1615  // Display u in free field format.
1616  OP(U_DOT)
1617  ios.print((ucell_t) tos, task.m_base);
1618  tos = *sp--;
1619  NEXT();
1620 
1621  // . ( n -- )
1622  // Display n in free field format.
1623  OP(DOT)
1624 #if 0
1625  ios.print(tos, task.m_base);
1626  ios.print(' ');
1627  tos = *sp--;
1628  NEXT();
1629 #else
1630  // : . ( n -- )
1631  // base @ 10 = if dup 0< if '-' emit negate then then u. space ;
1632  static const code_t DOT_CODE[] PROGMEM = {
1633  FVM_OP(BASE),
1634  FVM_OP(FETCH),
1635  FVM_CLIT(10),
1636  FVM_OP(EQUALS),
1637  FVM_OP(ZERO_BRANCH), 9,
1638  FVM_OP(DUP),
1639  FVM_OP(ZERO_LESS),
1640  FVM_OP(ZERO_BRANCH), 5,
1641  FVM_CLIT('-'),
1642  FVM_OP(EMIT),
1643  FVM_OP(NEGATE),
1644  FVM_OP(U_DOT),
1645  FVM_OP(SPACE),
1646  FVM_OP(EXIT)
1647  };
1648  CALL(DOT_CODE);
1649 #endif
1650 
1651  // .s ( -- )
1652  // Display stack contents.
1653  OP(DOT_S)
1654 #if 0
1655  tmp = (sp - task.m_sp0);
1656  ios.print('[');
1657  ios.print(tmp);
1658  ios.print(F("]: "));
1659  if (tmp > 0) {
1660  cell_t* tp = task.m_sp0 + 1;
1661  while (--tmp) {
1662  ios.print(*++tp, task.m_base);
1663  ios.print(' ');
1664  }
1665  ios.print(tos);
1666  }
1667  ios.println();
1668  NEXT();
1669 #else
1670  // : .s ( -- )
1671  // depth dup '[' emit u. ']' emit ':' emit space
1672  // begin ?dup while dup pick . 1- repeat
1673  // cr ;
1674  static const code_t DOT_S_CODE[] PROGMEM = {
1675  FVM_OP(DEPTH),
1676  FVM_OP(DUP),
1677  FVM_CLIT('['),
1678  FVM_OP(EMIT),
1679  FVM_OP(U_DOT),
1680  FVM_CLIT(']'),
1681  FVM_OP(EMIT),
1682  FVM_CLIT(':'),
1683  FVM_OP(EMIT),
1684  FVM_OP(SPACE),
1685  FVM_OP(QUESTION_DUP),
1686  FVM_OP(ZERO_BRANCH), 7,
1687  FVM_OP(DUP),
1688  FVM_OP(PICK),
1689  FVM_OP(DOT),
1690  FVM_OP(ONE_MINUS),
1691  FVM_OP(BRANCH), -8,
1692  FVM_OP(CR),
1693  FVM_OP(EXIT)
1694  };
1695  CALL(DOT_S_CODE);
1696 #endif
1697 
1698  // ." string" ( -- )
1699  // Display literal data or program memory string.
1700  OP(DOT_QUOTE)
1701 #if defined(ARDUINO_ARCH_AVR)
1702  if (ip < (code_P) CODE_P_MAX)
1703  ip += ios.print((const __FlashStringHelper*) ip) + 1;
1704  else
1705  ip += ios.print((const char*) ip - CODE_P_MAX) + 1;
1706 #else
1707  ip += ios.print((const __FlashStringHelper*) ip) + 1;
1708 #endif
1709 
1710  NEXT();
1711 
1712  // type ( a-addr -- )
1713  // Display data memory string.
1714  OP(TYPE)
1715  ios.print((const char*) tos);
1716  tos = *sp--;
1717  NEXT();
1718 
1719  // .name ( xt -- length | 0 )
1720  // Display name of word (token from lookup) and return length.
1721  OP(DOT_NAME)
1722  {
1723  const __FlashStringHelper* s = NULL;
1724  if (tos < KERNEL_MAX)
1725  s = (const __FlashStringHelper*) OPSTR(tos);
1726  else if (tos < APPLICATION_MAX)
1727  s = (const __FlashStringHelper*) FNSTR(tos-KERNEL_MAX);
1728  tos = (s != NULL) ? ios.print(s) : 0;
1729  }
1730  NEXT();
1731 
1732  // ? ( a-addr -- ) @ . ;
1733  // Display value of cell at a-addr.
1734  OP(QUESTION)
1735  static const code_t QUESTION_CODE[] PROGMEM = {
1736  FVM_OP(FETCH),
1737  FVM_OP(DOT),
1738  FVM_OP(EXIT)
1739  };
1740  CALL(QUESTION_CODE);
1741 
1742  // delay ( ms -- )
1743  // Yield while waiting given number of milli-seconds.
1744  OP(DELAY)
1745  // : delay ( ms -- )
1746  // millis >r
1747  // begin millis r@ - over u< while yield repeat
1748  // r> 2drop ;
1749  static const code_t DELAY_CODE[] PROGMEM = {
1750  FVM_OP(MILLIS),
1751  FVM_OP(TO_R),
1752  FVM_OP(MILLIS),
1753  FVM_OP(R_FETCH),
1754  FVM_OP(MINUS),
1755  FVM_OP(OVER),
1756  FVM_OP(U_LESS),
1757  FVM_OP(ZERO_BRANCH), 4,
1758  FVM_OP(YIELD),
1759  FVM_OP(BRANCH), -9,
1760  FVM_OP(R_FROM),
1761  FVM_OP(TWO_DROP),
1762  FVM_OP(EXIT)
1763  };
1764  CALL(DELAY_CODE);
1765 
1766  // micros ( -- us )
1767  // Micro-seconds.
1768  OP(MICROS)
1769  *++sp = tos;
1770  tos = micros();
1771  NEXT();
1772 
1773  // millis ( -- ms )
1774  // Milli-seconds.
1775  OP(MILLIS)
1776  *++sp = tos;
1777  tos = millis();
1778  NEXT();
1779 
1780  // pinmode ( mode pin -- )
1781  // Set digital pin mode.
1782  OP(PINMODE)
1783  pinMode(tos, *sp--);
1784  tos = *sp--;
1785  NEXT();
1786 
1787  // digitalread ( pin -- state )
1788  // Read digital pin.
1789  OP(DIGITALREAD)
1790  tos = digitalRead(tos);
1791  NEXT();
1792 
1793  // digitalwrite ( state pin -- )
1794  // Write digital pin.
1795  OP(DIGITALWRITE)
1796  digitalWrite(tos, *sp--);
1797  tos = *sp--;
1798  NEXT();
1799 
1800  // digitaltoggle ( pin -- )
1801  // Toggle digital pin.
1802  OP(DIGITALTOGGLE)
1803  digitalWrite(tos, !digitalRead(tos));
1804  tos = *sp--;
1805  NEXT();
1806 
1807  // analogread ( pin -- sample )
1808  // Read analog pin.
1809  OP(ANALOGREAD)
1810  tos = analogRead(tos & 0xf);
1811  NEXT();
1812 
1813  // analogwrite ( n pin -- )
1814  // Write pwm pin.
1815  OP(ANALOGWRITE)
1816  analogWrite(tos, *sp--);
1817  tos = *sp--;
1818  NEXT();
1819 
1820  // fncall ( -- )
1821  // Internal threaded code call.
1822  FNCALL:
1823 #if (FVM_KERNEL_OPT == 1)
1824  if (fetch_byte(ip)) *++rp = ip;
1825 #else
1826  *++rp = ip;
1827 #endif
1828  ip = tp;
1829  NEXT();
1830 
1831  default:
1832  ;
1833  }
1834  return (-1);
1835 }
1836 
1837 int FVM::execute(int op, task_t& task)
1838 {
1839  if (op < 0 || op > TOKEN_MAX) return (-1);
1840  static const code_t EXECUTE_CODE[] PROGMEM = {
1841  FVM_OP(EXECUTE),
1842  FVM_OP(HALT)
1843  };
1844  task.push(op);
1845  return (execute(EXECUTE_CODE, task));
1846 }
1847 
1849 {
1850  char buffer[32];
1851  char c = scan(buffer, task);
1852  int res = execute(buffer, task);
1853  if (res == 1) {
1854  while ((res = resume(task)) > 0);
1855  }
1856  else if (res == -1) {
1857  char* endptr;
1858  int value = strtol(buffer, &endptr, task.m_base == 10 ? 0 : task.m_base);
1859  if (*endptr != 0) {
1860  task.m_ios.print(buffer);
1861  task.m_ios.println(F(" ??"));
1862  return (res);
1863  }
1864  task.push(value);
1865  res = execute(OP_NOOP, task);
1866  }
1867  if (c == '\n' && !task.trace())
1868  execute(FVM::OP_DOT_S, task);
1869  return (res);
1870 }
1871 
1872 #if (FVM_KERNEL_DICT == 1)
1873 static const char EXIT_PSTR[] PROGMEM = "exit";
1874 static const char ZERO_EXIT_PSTR[] PROGMEM = "?exit";
1875 static const char LIT_PSTR[] PROGMEM = "(lit)";
1876 static const char CLIT_PSTR[] PROGMEM = "(clit)";
1877 static const char SLIT_PSTR[] PROGMEM = "(slit)";
1878 static const char VAR_PSTR[] PROGMEM = "(var)";
1879 static const char CONST_PSTR[] PROGMEM = "(const)";
1880 static const char FUNC_PSTR[] PROGMEM = "(func)";
1881 static const char DOES_PSTR[] PROGMEM = "(does)";
1882 static const char PARAM_PSTR[] PROGMEM = "(param)";
1883 static const char BRANCH_PSTR[] PROGMEM = "(branch)";
1884 static const char ZERO_BRANCH_PSTR[] PROGMEM = "(0branch)";
1885 static const char DO_PSTR[] PROGMEM = "(do)";
1886 static const char I_PSTR[] PROGMEM = "i";
1887 static const char J_PSTR[] PROGMEM = "j";
1888 static const char LEAVE_PSTR[] PROGMEM = "leave";
1889 static const char LOOP_PSTR[] PROGMEM = "(loop)";
1890 static const char PLUS_LOOP_PSTR[] PROGMEM = "(+loop)";
1891 static const char NOOP_PSTR[] PROGMEM = "noop";
1892 static const char EXECUTE_PSTR[] PROGMEM = "execute";
1893 static const char YIELD_PSTR[] PROGMEM = "yield";
1894 static const char HALT_PSTR[] PROGMEM = "halt";
1895 static const char SYSCALL_PSTR[] PROGMEM = "(syscall)";
1896 static const char CALL_PSTR[] PROGMEM = "(call)";
1897 static const char TRACE_PSTR[] PROGMEM = "trace";
1898 static const char ROOM_PSTR[] PROGMEM = "room";
1899 
1900 static const char C_FETCH_PSTR[] PROGMEM = "c@";
1901 static const char C_STORE_PSTR[] PROGMEM = "c!";
1902 static const char FETCH_PSTR[] PROGMEM = "@";
1903 static const char STORE_PSTR[] PROGMEM = "!";
1904 static const char PLUS_STORE_PSTR[] PROGMEM = "+!";
1905 static const char DP_PSTR[] PROGMEM = "dp";
1906 static const char HERE_PSTR[] PROGMEM = "here";
1907 static const char ALLOT_PSTR[] PROGMEM = "allot";
1908 static const char COMMA_PSTR[] PROGMEM = ",";
1909 static const char C_COMMA_PSTR[] PROGMEM = "c,";
1910 static const char COMPILE_PSTR[] PROGMEM = "(compile)";
1911 
1912 static const char TO_R_PSTR[] PROGMEM = ">r";
1913 static const char R_FROM_PSTR[] PROGMEM = "r>";
1914 static const char R_FETCH_PSTR[] PROGMEM = "r@";
1915 
1916 static const char SP_PSTR[] PROGMEM = "sp";
1917 static const char DEPTH_PSTR[] PROGMEM = "depth";
1918 static const char DROP_PSTR[] PROGMEM = "drop";
1919 static const char NIP_PSTR[] PROGMEM = "nip";
1920 static const char EMPTY_PSTR[] PROGMEM = "empty";
1921 static const char DUP_PSTR[] PROGMEM = "dup";
1922 static const char QUESTION_DUP_PSTR[] PROGMEM = "?dup";
1923 static const char OVER_PSTR[] PROGMEM = "over";
1924 static const char TUCK_PSTR[] PROGMEM = "tuck";
1925 static const char PICK_PSTR[] PROGMEM = "pick";
1926 static const char SWAP_PSTR[] PROGMEM = "swap";
1927 static const char ROT_PSTR[] PROGMEM = "rot";
1928 static const char MINUS_ROT_PSTR[] PROGMEM = "-rot";
1929 static const char ROLL_PSTR[] PROGMEM = "roll";
1930 static const char TWO_SWAP_PSTR[] PROGMEM = "2swap";
1931 static const char TWO_DUP_PSTR[] PROGMEM = "2dup";
1932 static const char TWO_OVER_PSTR[] PROGMEM = "2over";
1933 static const char TWO_DROP_PSTR[] PROGMEM = "2drop";
1934 
1935 static const char MINUS_TWO_PSTR[] PROGMEM = "-2";
1936 static const char MINUS_ONE_PSTR[] PROGMEM = "-1";
1937 static const char ZERO_PSTR[] PROGMEM = "0";
1938 static const char ONE_PSTR[] PROGMEM = "1";
1939 static const char TWO_PSTR[] PROGMEM = "2";
1940 static const char CELL_PSTR[] PROGMEM = "cell";
1941 static const char CELLS_PSTR[] PROGMEM = "cells";
1942 
1943 static const char BOOL_PSTR[] PROGMEM = "bool";
1944 static const char NOT_PSTR[] PROGMEM = "not";
1945 static const char TRUE_PSTR[] PROGMEM = "true";
1946 static const char FALSE_PSTR[] PROGMEM = "false";
1947 static const char INVERT_PSTR[] PROGMEM = "invert";
1948 static const char AND_PSTR[] PROGMEM = "and";
1949 static const char OR_PSTR[] PROGMEM = "or";
1950 static const char XOR_PSTR[] PROGMEM = "xor";
1951 
1952 static const char NEGATE_PSTR[] PROGMEM = "negate";
1953 static const char ONE_PLUS_PSTR[] PROGMEM = "1+";
1954 static const char ONE_MINUS_PSTR[] PROGMEM = "1-";
1955 static const char TWO_PLUS_PSTR[] PROGMEM = "2+";
1956 static const char TWO_MINUS_PSTR[] PROGMEM = "2-";
1957 static const char TWO_STAR_PSTR[] PROGMEM = "2*";
1958 static const char TWO_SLASH_PSTR[] PROGMEM = "2/";
1959 static const char PLUS_PSTR[] PROGMEM = "+";
1960 static const char MINUS_PSTR[] PROGMEM = "-";
1961 static const char STAR_PSTR[] PROGMEM = "*";
1962 static const char STAR_SLASH_PSTR[] PROGMEM = "*/";
1963 static const char SLASH_PSTR[] PROGMEM = "/";
1964 static const char MOD_PSTR[] PROGMEM = "mod";
1965 static const char SLASH_MODE_PSTR[] PROGMEM = "/mod";
1966 static const char LSHIFT_PSTR[] PROGMEM = "lshift";
1967 static const char RSHIFT_PSTR[] PROGMEM = "rshift";
1968 
1969 
1970 static const char WITHIN_PSTR[] PROGMEM = "within";
1971 static const char ABS_PSTR[] PROGMEM = "abs";
1972 static const char MIN_PSTR[] PROGMEM = "min";
1973 static const char MAX_PSTR[] PROGMEM = "max";
1974 
1975 static const char ZERO_NOT_EQUALS_PSTR[] PROGMEM = "0<>";
1976 static const char ZERO_LESS_PSTR[] PROGMEM = "0<";
1977 static const char ZERO_EQUALS_PSTR[] PROGMEM = "0=";
1978 static const char ZERO_GREATER_PSTR[] PROGMEM = "0>";
1979 static const char NOT_EQUALS_PSTR[] PROGMEM = "<>";
1980 static const char LESS_PSTR[] PROGMEM = "<";
1981 static const char EQUALS_PSTR[] PROGMEM = "=";
1982 static const char GREATER_PSTR[] PROGMEM = ">";
1983 static const char U_LESS_PSTR[] PROGMEM = "u<";
1984 
1985 static const char LOOKUP_PSTR[] PROGMEM = "lookup";
1986 static const char TO_BODY_PSTR[] PROGMEM = ">body";
1987 static const char WORDS_PSTR[] PROGMEM = "words";
1988 
1989 static const char BASE_PSTR[] PROGMEM = "base";
1990 static const char HEX_PSTR[] PROGMEM = "hex";
1991 static const char DECIMAL_PSTR[] PROGMEM = "decimal";
1992 static const char QUESTION_KEY_PSTR[] PROGMEM = "?key";
1993 static const char KEY_PSTR[] PROGMEM = "key";
1994 static const char EMIT_PSTR[] PROGMEM = "emit";
1995 static const char CR_PSTR[] PROGMEM = "cr";
1996 static const char SPACE_PSTR[] PROGMEM = "space";
1997 static const char SPACES_PSTR[] PROGMEM = "spaces";
1998 static const char U_DOT_PSTR[] PROGMEM = "u.";
1999 static const char DOT_PSTR[] PROGMEM = ".";
2000 static const char DOT_S_PSTR[] PROGMEM = ".s";
2001 static const char DOT_QUOTE_PSTR[] PROGMEM = "(.\")";
2002 static const char TYPE_PSTR[] PROGMEM = "type";
2003 static const char DOT_NAME_PSTR[] PROGMEM = ".name";
2004 static const char QUESTION_PSTR[] PROGMEM = "?";
2005 
2006 static const char MICROS_PSTR[] PROGMEM = "micros";
2007 static const char MILLIS_PSTR[] PROGMEM = "millis";
2008 static const char DELAY_PSTR[] PROGMEM = "delay";
2009 static const char PINMODE_PSTR[] PROGMEM = "pinmode";
2010 static const char DIGITALREAD_PSTR[] PROGMEM = "digitalread";
2011 static const char DIGITALWRITE_PSTR[] PROGMEM = "digitalwrite";
2012 static const char DIGITALTOGGLE_PSTR[] PROGMEM = "digitaltoggle";
2013 static const char ANALOGREAD_PSTR[] PROGMEM = "analogread";
2014 static const char ANALOGWRITE_PSTR[] PROGMEM = "analogwrite";
2015 #endif
2016 
2017 const str_P FVM::opstr[] PROGMEM = {
2018 #if (FVM_KERNEL_DICT == 1)
2019  (str_P) EXIT_PSTR,
2021  (str_P) LIT_PSTR,
2022  (str_P) CLIT_PSTR,
2023  (str_P) SLIT_PSTR,
2024  (str_P) VAR_PSTR,
2025  (str_P) CONST_PSTR,
2026  (str_P) FUNC_PSTR,
2027  (str_P) DOES_PSTR,
2028  (str_P) PARAM_PSTR,
2029  (str_P) BRANCH_PSTR,
2031  (str_P) DO_PSTR,
2032  (str_P) I_PSTR,
2033  (str_P) J_PSTR,
2034  (str_P) LEAVE_PSTR,
2035  (str_P) LOOP_PSTR,
2037  (str_P) NOOP_PSTR,
2038  (str_P) EXECUTE_PSTR,
2039  (str_P) HALT_PSTR,
2040  (str_P) YIELD_PSTR,
2041  (str_P) SYSCALL_PSTR,
2042  (str_P) CALL_PSTR,
2043  (str_P) TRACE_PSTR,
2044  (str_P) ROOM_PSTR,
2045 
2046  (str_P) C_FETCH_PSTR,
2047  (str_P) C_STORE_PSTR,
2048  (str_P) FETCH_PSTR,
2049  (str_P) STORE_PSTR,
2051  (str_P) DP_PSTR,
2052  (str_P) HERE_PSTR,
2053  (str_P) ALLOT_PSTR,
2054  (str_P) COMMA_PSTR,
2055  (str_P) C_COMMA_PSTR,
2056  (str_P) COMPILE_PSTR,
2057 
2058  (str_P) TO_R_PSTR,
2059  (str_P) R_FROM_PSTR,
2060  (str_P) R_FETCH_PSTR,
2061 
2062  (str_P) SP_PSTR,
2063  (str_P) DEPTH_PSTR,
2064  (str_P) DROP_PSTR,
2065  (str_P) NIP_PSTR,
2066  (str_P) EMPTY_PSTR,
2067  (str_P) DUP_PSTR,
2069  (str_P) OVER_PSTR,
2070  (str_P) TUCK_PSTR,
2071  (str_P) PICK_PSTR,
2072  (str_P) SWAP_PSTR,
2073  (str_P) ROT_PSTR,
2075  (str_P) ROLL_PSTR,
2076  (str_P) TWO_SWAP_PSTR,
2077  (str_P) TWO_DUP_PSTR,
2078  (str_P) TWO_OVER_PSTR,
2079  (str_P) TWO_DROP_PSTR,
2080 
2083  (str_P) ZERO_PSTR,
2084  (str_P) ONE_PSTR,
2085  (str_P) TWO_PSTR,
2086  (str_P) CELL_PSTR,
2087  (str_P) CELLS_PSTR,
2088 
2089  (str_P) BOOL_PSTR,
2090  (str_P) NOT_PSTR,
2091  (str_P) TRUE_PSTR,
2092  (str_P) FALSE_PSTR,
2093  (str_P) INVERT_PSTR,
2094  (str_P) AND_PSTR,
2095  (str_P) OR_PSTR,
2096  (str_P) XOR_PSTR,
2097  (str_P) NEGATE_PSTR,
2098  (str_P) ONE_PLUS_PSTR,
2100  (str_P) TWO_PLUS_PSTR,
2102  (str_P) TWO_STAR_PSTR,
2104  (str_P) PLUS_PSTR,
2105  (str_P) MINUS_PSTR,
2106  (str_P) STAR_PSTR,
2108  (str_P) SLASH_PSTR,
2109  (str_P) MOD_PSTR,
2111  (str_P) LSHIFT_PSTR,
2112  (str_P) RSHIFT_PSTR,
2113 
2114  (str_P) WITHIN_PSTR,
2115  (str_P) ABS_PSTR,
2116  (str_P) MIN_PSTR,
2117  (str_P) MAX_PSTR,
2118 
2124  (str_P) LESS_PSTR,
2125  (str_P) EQUALS_PSTR,
2126  (str_P) GREATER_PSTR,
2127  (str_P) U_LESS_PSTR,
2128 
2129  (str_P) LOOKUP_PSTR,
2130  (str_P) TO_BODY_PSTR,
2131  (str_P) WORDS_PSTR,
2132 
2133  (str_P) BASE_PSTR,
2134  (str_P) HEX_PSTR,
2135  (str_P) DECIMAL_PSTR,
2137  (str_P) KEY_PSTR,
2138  (str_P) EMIT_PSTR,
2139  (str_P) CR_PSTR,
2140  (str_P) SPACE_PSTR,
2141  (str_P) SPACES_PSTR,
2142  (str_P) U_DOT_PSTR,
2143  (str_P) DOT_PSTR,
2144  (str_P) DOT_S_PSTR,
2146  (str_P) TYPE_PSTR,
2147  (str_P) DOT_NAME_PSTR,
2148  (str_P) QUESTION_PSTR,
2149 
2150  (str_P) MICROS_PSTR,
2151  (str_P) MILLIS_PSTR,
2152  (str_P) DELAY_PSTR,
2153  (str_P) PINMODE_PSTR,
2159 #endif
2160  0
2161 };
static const char C_COMMA_PSTR[]
Definition: FVM.cpp:1909
static const char SLASH_MODE_PSTR[]
Definition: FVM.cpp:1965
static const char SLIT_PSTR[]
Definition: FVM.cpp:1877
static const char LSHIFT_PSTR[]
Definition: FVM.cpp:1966
static const char WORDS_PSTR[]
Definition: FVM.cpp:1987
static const char LIT_PSTR[]
Definition: FVM.cpp:1875
Yield virtual machine.
Definition: FVM.h:61
#define FNTAB(ix)
Definition: FVM.cpp:69
static const char DOT_QUOTE_PSTR[]
Definition: FVM.cpp:2001
static const char FUNC_PSTR[]
Definition: FVM.cpp:1880
static const char DOT_S_PSTR[]
Definition: FVM.cpp:2000
static const char DOES_PSTR[]
Definition: FVM.cpp:1881
static const char OVER_PSTR[]
Definition: FVM.cpp:1923
static const char PARAM_PSTR[]
Definition: FVM.cpp:1882
static const char TWO_DUP_PSTR[]
Definition: FVM.cpp:1931
static const char NEGATE_PSTR[]
Definition: FVM.cpp:1952
static const char YIELD_PSTR[]
Definition: FVM.cpp:1893
static const char QUESTION_KEY_PSTR[]
Definition: FVM.cpp:1992
static const char CALL_PSTR[]
Definition: FVM.cpp:1896
static const char FALSE_PSTR[]
Definition: FVM.cpp:1946
static const char PLUS_PSTR[]
Definition: FVM.cpp:1959
static const char TUCK_PSTR[]
Definition: FVM.cpp:1924
#define fetch_word(ip)
Definition: FVM.cpp:81
static const char NOOP_PSTR[]
Definition: FVM.cpp:1891
static const char COMPILE_PSTR[]
Definition: FVM.cpp:1910
static const char TWO_PSTR[]
Definition: FVM.cpp:1939
static const char TWO_OVER_PSTR[]
Definition: FVM.cpp:1932
#define CALL(fn)
Definition: FVM.cpp:61
static const char HERE_PSTR[]
Definition: FVM.cpp:1906
static const char ALLOT_PSTR[]
Definition: FVM.cpp:1907
static const char EXIT_PSTR[]
Definition: FVM.cpp:1873
static const char CELLS_PSTR[]
Definition: FVM.cpp:1941
static const str_P opstr[]
Definition: FVM.h:636
static const char DROP_PSTR[]
Definition: FVM.cpp:1918
static const char MINUS_ROT_PSTR[]
Definition: FVM.cpp:1928
static const char TWO_DROP_PSTR[]
Definition: FVM.cpp:1933
static const char SLASH_PSTR[]
Definition: FVM.cpp:1963
int resume(task_t &task)
Definition: FVM.cpp:143
static const char DIGITALTOGGLE_PSTR[]
Definition: FVM.cpp:2012
static const char ZERO_GREATER_PSTR[]
Definition: FVM.cpp:1978
static const char MINUS_ONE_PSTR[]
Definition: FVM.cpp:1936
static const char ROOM_PSTR[]
Definition: FVM.cpp:1898
static const char R_FETCH_PSTR[]
Definition: FVM.cpp:1914
#define FVM_CLIT(n)
Definition: FVM.h:667
static const char ZERO_EXIT_PSTR[]
Definition: FVM.cpp:1874
static const char TYPE_PSTR[]
Definition: FVM.cpp:2002
Call application token.
Definition: FVM.h:63
static const char PINMODE_PSTR[]
Definition: FVM.cpp:2009
static const char LOOP_PSTR[]
Definition: FVM.cpp:1889
void(* fn_t)(task_t &task, void *env)
Definition: FVM.h:383
static const char MILLIS_PSTR[]
Definition: FVM.cpp:2007
static const char DIGITALREAD_PSTR[]
Definition: FVM.cpp:2010
static const char I_PSTR[]
Definition: FVM.cpp:1886
static const char ZERO_PSTR[]
Definition: FVM.cpp:1937
static const char CLIT_PSTR[]
Definition: FVM.cpp:1876
static const uint16_t CODE_P_MAX
Definition: FVM.h:632
#define OPSTR(ix)
Definition: FVM.cpp:71
static const char STAR_PSTR[]
Definition: FVM.cpp:1961
static const char NOT_PSTR[]
Definition: FVM.cpp:1944
code_P * m_rp
Return stack pointer.
Definition: FVM.h:255
static const char TWO_MINUS_PSTR[]
Definition: FVM.cpp:1956
uint8_t * m_dp
Definition: FVM.h:642
Call system token.
Definition: FVM.h:62
static const char TWO_PLUS_PSTR[]
Definition: FVM.cpp:1955
static const char EMPTY_PSTR[]
Definition: FVM.cpp:1920
static const char J_PSTR[]
Definition: FVM.cpp:1887
static const char R_FROM_PSTR[]
Definition: FVM.cpp:1913
static const char ONE_MINUS_PSTR[]
Definition: FVM.cpp:1954
#define OP(n)
Definition: FVM.cpp:58
static const char TWO_STAR_PSTR[]
Definition: FVM.cpp:1957
static const char U_LESS_PSTR[]
Definition: FVM.cpp:1983
#define fetch_byte(ip)
Definition: FVM.cpp:80
static const char LOOKUP_PSTR[]
Definition: FVM.cpp:1985
const char * str_P
Definition: FVM.h:32
static const char C_STORE_PSTR[]
Definition: FVM.cpp:1901
cell_t m_base
Number conversion base.
Definition: FVM.h:253
static const char TWO_SLASH_PSTR[]
Definition: FVM.cpp:1958
static const char SYSCALL_PSTR[]
Definition: FVM.cpp:1895
static const char ABS_PSTR[]
Definition: FVM.cpp:1971
static const char SWAP_PSTR[]
Definition: FVM.cpp:1926
const code_t * code_P
Definition: FVM.h:249
static const char MICROS_PSTR[]
Definition: FVM.cpp:2006
static const char MINUS_TWO_PSTR[]
Definition: FVM.cpp:1935
static const char HEX_PSTR[]
Definition: FVM.cpp:1990
static const char MAX_PSTR[]
Definition: FVM.cpp:1973
static const char ONE_PSTR[]
Definition: FVM.cpp:1938
static const char COMMA_PSTR[]
Definition: FVM.cpp:1908
static const char DEPTH_PSTR[]
Definition: FVM.cpp:1917
static const char STORE_PSTR[]
Definition: FVM.cpp:1903
static const char ANALOGREAD_PSTR[]
Definition: FVM.cpp:2013
static const char DP_PSTR[]
Definition: FVM.cpp:1905
static const char DIGITALWRITE_PSTR[]
Definition: FVM.cpp:2011
static const char DECIMAL_PSTR[]
Definition: FVM.cpp:1991
static const char PLUS_LOOP_PSTR[]
Definition: FVM.cpp:1890
char ** m_name
Definition: FVM.h:645
bool trace()
Definition: FVM.h:312
static const char CR_PSTR[]
Definition: FVM.cpp:1995
static const char MIN_PSTR[]
Definition: FVM.cpp:1972
#define FNSTR(ix)
Definition: FVM.cpp:70
bool m_trace
Trace mode.
Definition: FVM.h:254
static const char MINUS_PSTR[]
Definition: FVM.cpp:1960
static const char DUP_PSTR[]
Definition: FVM.cpp:1921
static const char ROT_PSTR[]
Definition: FVM.cpp:1927
static const char PICK_PSTR[]
Definition: FVM.cpp:1925
int execute(int op, task_t &task)
Definition: FVM.cpp:1837
static const char DOT_NAME_PSTR[]
Definition: FVM.cpp:2003
static const char GREATER_PSTR[]
Definition: FVM.cpp:1982
static const char QUESTION_PSTR[]
Definition: FVM.cpp:2004
static const char ZERO_LESS_PSTR[]
Definition: FVM.cpp:1976
static const char BASE_PSTR[]
Definition: FVM.cpp:1989
cell_t * m_sp
Parameter stack pointer.
Definition: FVM.h:257
static const char ANALOGWRITE_PSTR[]
Definition: FVM.cpp:2014
code_P * m_rp0
Return stack bottom pointer.
Definition: FVM.h:256
static const char ZERO_EQUALS_PSTR[]
Definition: FVM.cpp:1977
static const char EXECUTE_PSTR[]
Definition: FVM.cpp:1892
static const char LEAVE_PSTR[]
Definition: FVM.cpp:1888
static const char PLUS_STORE_PSTR[]
Definition: FVM.cpp:1904
cell_t * m_sp0
Parameter stack bottom pointer.
Definition: FVM.h:258
#define MAP(if)
Definition: FVM.cpp:62
static const char NOT_EQUALS_PSTR[]
Definition: FVM.cpp:1979
static const char BRANCH_PSTR[]
Definition: FVM.cpp:1883
int interpret(task_t &task)
Definition: FVM.cpp:1848
static const char KEY_PSTR[]
Definition: FVM.cpp:1993
static const char ONE_PLUS_PSTR[]
Definition: FVM.cpp:1953
static const char ZERO_NOT_EQUALS_PSTR[]
Definition: FVM.cpp:1975
static const char DOT_PSTR[]
Definition: FVM.cpp:1999
code_t ** m_body
Definition: FVM.h:644
static const char XOR_PSTR[]
Definition: FVM.cpp:1950
int lookup(const char *name)
Definition: FVM.cpp:101
static const char AND_PSTR[]
Definition: FVM.cpp:1948
static const char WITHIN_PSTR[]
Definition: FVM.cpp:1970
int64_t cell2_t
Definition: FVM.h:237
static const char SP_PSTR[]
Definition: FVM.cpp:1916
uint32_t ucell_t
Definition: FVM.h:236
static const char CELL_PSTR[]
Definition: FVM.cpp:1940
static const char VAR_PSTR[]
Definition: FVM.cpp:1878
int8_t code_t
Definition: FVM.h:248
static const char QUESTION_DUP_PSTR[]
Definition: FVM.cpp:1922
#define FALLTHROUGH()
Definition: FVM.cpp:60
static const char INVERT_PSTR[]
Definition: FVM.cpp:1947
static const char MOD_PSTR[]
Definition: FVM.cpp:1964
static const char DELAY_PSTR[]
Definition: FVM.cpp:2008
static const char FETCH_PSTR[]
Definition: FVM.cpp:1902
static const char C_FETCH_PSTR[]
Definition: FVM.cpp:1900
static const char ZERO_BRANCH_PSTR[]
Definition: FVM.cpp:1884
static const char DO_PSTR[]
Definition: FVM.cpp:1885
static const char EQUALS_PSTR[]
Definition: FVM.cpp:1981
#define FVM_OP(code)
Definition: FVM.h:652
static const char TO_R_PSTR[]
Definition: FVM.cpp:1912
static const char EMIT_PSTR[]
Definition: FVM.cpp:1994
void push(cell_t value)
Definition: FVM.h:285
static const char BOOL_PSTR[]
Definition: FVM.cpp:1943
#define FVM_LIT(n)
Definition: FVM.h:658
No operation.
Definition: FVM.h:58
static const char LESS_PSTR[]
Definition: FVM.cpp:1980
static const char RSHIFT_PSTR[]
Definition: FVM.cpp:1967
static const char SPACE_PSTR[]
Definition: FVM.cpp:1996
static const char ROLL_PSTR[]
Definition: FVM.cpp:1929
static const char TRACE_PSTR[]
Definition: FVM.cpp:1897
#define NEXT()
Definition: FVM.cpp:59
const uint8_t WORD_MAX
Definition: FVM.h:640
static const char STAR_SLASH_PSTR[]
Definition: FVM.cpp:1962
static const char HALT_PSTR[]
Definition: FVM.cpp:1894
Print contents of parameter stack.
Definition: FVM.h:196
static const char NIP_PSTR[]
Definition: FVM.cpp:1919
int32_t cell_t
Definition: FVM.h:235
int scan(char *bp, task_t &task)
Definition: FVM.cpp:121
uint8_t m_next
Definition: FVM.h:641
static const char TO_BODY_PSTR[]
Definition: FVM.cpp:1986
static const char TRUE_PSTR[]
Definition: FVM.cpp:1945
static const char SPACES_PSTR[]
Definition: FVM.cpp:1997
const size_t DICT_MAX
Definition: FVM.h:639
static const char OR_PSTR[]
Definition: FVM.cpp:1949
static const char CONST_PSTR[]
Definition: FVM.cpp:1879
static const char U_DOT_PSTR[]
Definition: FVM.cpp:1998
Stream & m_ios
Input/Output stream.
Definition: FVM.h:252
static const char TWO_SWAP_PSTR[]
Definition: FVM.cpp:1930