Arduino-FVM
Byte Token Threaded Forth Virtual Machine (FVM) for Arduino
Forth.ino
Go to the documentation of this file.
1 
71 #include "FVM.h"
72 
73 // : mark> ( -- addr ) here 0 c, ;
74 FVM_COLON(0, FORWARD_MARK, "mark>")
75  FVM_OP(HERE),
76  FVM_OP(ZERO),
77  FVM_OP(C_COMMA),
78  FVM_OP(EXIT)
79 };
80 
81 // : resolve> ( addr -- ) here over - swap c! ;
82 FVM_COLON(1, FORWARD_RESOLVE, "resolve>")
83  FVM_OP(HERE),
84  FVM_OP(OVER),
85  FVM_OP(MINUS),
86  FVM_OP(SWAP),
87  FVM_OP(C_STORE),
88  FVM_OP(EXIT)
89 };
90 
91 // : <mark ( -- addr ) here ;
92 FVM_COLON(2, BACKWARD_MARK, "<mark")
93  FVM_OP(HERE),
94  FVM_OP(EXIT)
95 };
96 
97 // : <resolve ( addr -- ) here - c, ;
98 FVM_COLON(3, BACKWARD_RESOLVE, "<resolve")
99  FVM_OP(HERE),
100  FVM_OP(MINUS),
101  FVM_OP(C_COMMA),
102  FVM_OP(EXIT)
103 };
104 
105 // : if ( -- addr ) compile (0branch) mark> ; immediate
106 FVM_COLON(4, IF, "if")
107  FVM_OP(COMPILE),
108  FVM_OP(ZERO_BRANCH),
109  FVM_CALL(FORWARD_MARK),
110  FVM_OP(EXIT)
111 };
112 
113 // : then ( addr -- ) resolve> ; immediate
114 const int THEN = 5;
115 const char THEN_PSTR[] PROGMEM = "then";
116 #define THEN_CODE FORWARD_RESOLVE_CODE
117 
118 // : else ( addr1 -- addr2 ) compile (branch) mark> swap resolve> ; immediate
119 FVM_COLON(6, ELSE, "else")
120  FVM_OP(COMPILE),
121  FVM_OP(BRANCH),
122  FVM_CALL(FORWARD_MARK),
123  FVM_OP(SWAP),
124  FVM_CALL(FORWARD_RESOLVE),
125  FVM_OP(EXIT)
126 };
127 
128 // : begin ( -- addr ) <mark ; immediate
129 const int BEGIN = 7;
130 const char BEGIN_PSTR[] PROGMEM = "begin";
131 #define BEGIN_CODE BACKWARD_MARK_CODE
132 
133 // : again ( addr -- ) compile (branch) <resolve ; immediate
134 FVM_COLON(8, AGAIN, "again")
135  FVM_OP(COMPILE),
136  FVM_OP(BRANCH),
137  FVM_CALL(BACKWARD_RESOLVE),
138  FVM_OP(EXIT)
139 };
140 
141 // : until ( addr -- ) compile (0branch) <resolve ; immediate
142 FVM_COLON(9, UNTIL, "until")
143  FVM_OP(COMPILE),
144  FVM_OP(ZERO_BRANCH),
145  FVM_CALL(BACKWARD_RESOLVE),
146  FVM_OP(EXIT)
147 };
148 
149 // : while ( addr1 -- addr1 addr2 ) compile (0branch) mark> ; immediate
150 const int WHILE = 10;
151 const char WHILE_PSTR[] PROGMEM = "while";
152 #define WHILE_CODE IF_CODE
153 
154 // : repeat ( addr1 addr2 -- ) swap [compile] again resolve> ; immediate
155 FVM_COLON(11, REPEAT, "repeat")
156  FVM_OP(SWAP),
157  FVM_CALL(AGAIN),
158  FVM_CALL(FORWARD_RESOLVE),
159  FVM_OP(EXIT)
160 };
161 
162 // : do ( -- addr1 addr2 ) compile (do) mark> <mark ; immediate
163 FVM_COLON(12, DO, "do")
164  FVM_OP(COMPILE),
165  FVM_OP(DO),
166  FVM_CALL(FORWARD_MARK),
167  FVM_CALL(BACKWARD_MARK),
168  FVM_OP(EXIT)
169 };
170 
171 // : loop ( addr1 addr2 -- ) compile (loop) <resolve resolve> ; immediate
172 FVM_COLON(13, LOOP, "loop")
173  FVM_OP(COMPILE),
174  FVM_OP(LOOP),
175  FVM_CALL(BACKWARD_RESOLVE),
176  FVM_CALL(FORWARD_RESOLVE),
177  FVM_OP(EXIT)
178 };
179 
180 // : +loop ( addr1 addr2 -- ) compile (+loop) <resolve resolve> ; immediate
181 FVM_COLON(14, PLUS_LOOP, "+loop")
182  FVM_OP(COMPILE),
183  FVM_OP(PLUS_LOOP),
184  FVM_CALL(BACKWARD_RESOLVE),
185  FVM_CALL(FORWARD_RESOLVE),
186  FVM_OP(EXIT)
187 };
188 
189 // Sketch dispatched symbols
190 FVM_SYMBOL(15, LEFT_BRACKET, "[");
191 FVM_SYMBOL(16, COMMENT, "(");
192 FVM_SYMBOL(17, DOT_QUOTE, ".\"");
193 FVM_SYMBOL(18, LITERAL, "literal");
194 FVM_SYMBOL(19, SEMICOLON, ";");
195 FVM_SYMBOL(20, RIGHT_BRACKET, "]");
196 FVM_SYMBOL(21, COLON, ":");
197 FVM_SYMBOL(22, CREATE, "create");
198 FVM_SYMBOL(23, VARIABLE, "variable");
199 FVM_SYMBOL(24, CONSTANT, "constant");
200 FVM_SYMBOL(25, WORDS, "words");
201 FVM_SYMBOL(26, FORGET, "forget");
202 FVM_SYMBOL(27, TICK, "\'");
203 
204 const FVM::code_P FVM::fntab[] PROGMEM = {
205  FORWARD_MARK_CODE,
206  FORWARD_RESOLVE_CODE,
207  BACKWARD_MARK_CODE,
208  BACKWARD_RESOLVE_CODE,
209  IF_CODE,
210  THEN_CODE,
211  ELSE_CODE,
212  BEGIN_CODE,
213  AGAIN_CODE,
214  UNTIL_CODE,
215  WHILE_CODE,
216  REPEAT_CODE,
217  DO_CODE,
218  LOOP_CODE,
219  PLUS_LOOP_CODE
220 };
221 
222 const str_P FVM::fnstr[] PROGMEM = {
223  (str_P) FORWARD_MARK_PSTR,
224  (str_P) FORWARD_RESOLVE_PSTR,
225  (str_P) BACKWARD_MARK_PSTR,
226  (str_P) BACKWARD_RESOLVE_PSTR,
227  (str_P) IF_PSTR,
228  (str_P) THEN_PSTR,
229  (str_P) ELSE_PSTR,
230  (str_P) BEGIN_PSTR,
231  (str_P) AGAIN_PSTR,
232  (str_P) UNTIL_PSTR,
233  (str_P) WHILE_PSTR,
234  (str_P) REPEAT_PSTR,
235  (str_P) DO_PSTR,
236  (str_P) LOOP_PSTR,
238  (str_P) LEFT_BRACKET_PSTR,
239  (str_P) COMMENT_PSTR,
241  (str_P) LITERAL_PSTR,
242  (str_P) SEMICOLON_PSTR,
243  (str_P) RIGHT_BRACKET_PSTR,
244  (str_P) COLON_PSTR,
245  (str_P) CREATE_PSTR,
246  (str_P) VARIABLE_PSTR,
247  (str_P) CONSTANT_PSTR,
248  (str_P) WORDS_PSTR,
249  (str_P) FORGET_PSTR,
250  (str_P) TICK_PSTR,
251  0
252 };
253 
254 // Size of data area and dynamic dictionary
255 #if defined(ARDUINO_ARCH_AVR)
256 const int DATA_MAX = (RAMEND - RAMSTART - 1024);
257 const int DICT_MAX = (RAMEND - RAMSTART) / 64;
258 #else
259 const int DATA_MAX = 32 * 1024;
260 const int DICT_MAX = 128;
261 #endif
262 
263 // Forth virtual machine, data area and task
264 uint8_t data[DATA_MAX];
265 FVM fvm(data, DATA_MAX, DICT_MAX);
266 FVM::Task<64,32> task(Serial);
267 
268 // Interpreter state
269 int compiling = false;
270 
271 void setup()
272 {
273  Serial.begin(57600);
274  while (!Serial);
275  Serial.println(F("FVM/Forth V1.1.0: started [Newline]"));
276 }
277 
278 void loop()
279 {
280  char buffer[32];
281  int op, val;
282  char c;
283 
284  // Scan and lookup word
285  c = fvm.scan(buffer, task);
286  op = fvm.lookup(buffer);
287 
288  // Check for literal value (word not found)
289  if (op < 0) {
290  char* endptr;
291  val = strtol(buffer, &endptr, task.m_base == 10 ? 0 : task.m_base);
292  if (*endptr != 0) goto error;
293  if (compiling)
294  fvm.literal(val);
295  else
296  task.push(val);
297  }
298 
299  // Check for kernel words; compile or execute
300  else if (op < FVM::KERNEL_MAX) {
301  if (compiling) {
302  fvm.compile(op);
303  }
304  else {
305  execute(op);
306  }
307  }
308 
309  // Skip comments
310  else if (op == COMMENT) {
311  while (Serial.read() != ')');
312  }
313 
314  // Check special forms; Interactive mode
315  else if (!compiling) {
316  switch (op) {
317  case RIGHT_BRACKET:
318  compiling = true;
319  break;
320  case COLON:
321  c = fvm.scan(buffer, task);
322  if (!fvm.create(buffer)) goto error;
323  compiling = true;
324  break;
325  case CREATE:
326  c = fvm.scan(buffer, task);
327  if (!fvm.create(buffer)) goto error;
329  break;
330  case VARIABLE:
331  c = fvm.scan(buffer, task);
332  if (!fvm.variable(buffer)) goto error;
333  break;
334  case CONSTANT:
335  val = task.pop();
336  c = fvm.scan(buffer, task);
337  if (!fvm.constant(buffer, val)) goto error;
338  break;
339  case WORDS:
340  {
341  Stream& ios = task.m_ios;
342  const char* s;
343  int nr = 0;
345  ios.println();
346  while ((s = fvm.name(nr)) != 0) {
347  int len = ios.print(s);
348  if (++nr % 5 == 0)
349  ios.println();
350  else {
351  for (;len < 16; len++) ios.print(' ');
352  }
353  }
354  if (nr % 5 != 0) ios.println();
355  }
356  break;
357  case FORGET:
358  c = fvm.scan(buffer, task);
359  op = fvm.lookup(buffer);
360  if (!fvm.forget(op)) goto error;
361  break;
362  case TICK:
363  c = fvm.scan(buffer, task);
364  op = fvm.lookup(buffer);
365  if (op >= LEFT_BRACKET && op <= TICK) goto error;
366  task.push(op);
367  break;
368  default:
369  if (op < FVM::APPLICATION_MAX) goto error;
370  execute(op);
371  }
372  }
373 
374  // Compile mode
375  else {
376  switch (op) {
377  case LEFT_BRACKET:
378  compiling = false;
379  break;
380  case DOT_QUOTE:
382  while (1) {
383  while (!Serial.available());
384  c = Serial.read();
385  if (c == '\"') break;
386  fvm.compile(c);
387  }
388  fvm.compile((FVM::code_t) 0);
389  break;
390  case LITERAL:
391  fvm.literal(task.pop());
392  break;
393  case SEMICOLON:
395  compiling = false;
396  break;
397  default:
398  if (op < SEMICOLON) {
399  execute(op);
400  }
401  else if (!fvm.compile(op)) goto error;
402  }
403  }
404 
405  // Prompt on end of line
406  if (c == '\n' && !compiling) {
407  if (task.trace())
408  Serial.println(F(" ok"));
409  else
411  }
412  return;
413 
414  error:
415  Serial.print(buffer);
416  Serial.println(F(" ??"));
417  compiling = false;
418 }
419 
420 void execute(int op)
421 {
422  if (fvm.execute(op, task) > 0)
423  while (fvm.resume(task) > 0);
424 }
static const char WORDS_PSTR[]
Definition: FVM.cpp:1987
#define THEN_CODE
Definition: Forth.ino:116
static const char DOT_QUOTE_PSTR[]
Definition: FVM.cpp:2001
const int DICT_MAX
Definition: Forth.ino:260
FVM_OP(HERE)
int resume(task_t &task)
Definition: FVM.cpp:143
FVM_SYMBOL(15, LEFT_BRACKET,"[")
uint8_t data[DATA_MAX]
Definition: Forth.ino:264
const int THEN
Definition: Forth.ino:114
bool create(const char *name)
Definition: FVM.h:475
bool forget(int op)
Definition: FVM.h:552
static const char LOOP_PSTR[]
Definition: FVM.cpp:1889
Definition: FVM.h:339
void execute(int op)
Definition: Forth.ino:420
FVM::Task< 64, 32 > task(Serial)
bool constant(const char *name, int val)
Definition: FVM.h:512
const char * str_P
Definition: FVM.h:32
const char * name(int op)
Definition: FVM.h:529
bool variable(const char *name)
Definition: FVM.h:494
void literal(int val)
Definition: FVM.h:457
static const char PLUS_LOOP_PSTR[]
Definition: FVM.cpp:1890
const char WHILE_PSTR[]
Definition: Forth.ino:151
Threaded code return.
Definition: FVM.h:40
void loop()
Definition: Forth.ino:278
static const str_P fnstr[]
Definition: FVM.h:629
#define WHILE_CODE
Definition: Forth.ino:152
#define BEGIN_CODE
Definition: Forth.ino:131
int execute(int op, task_t &task)
Definition: FVM.cpp:1837
const int DATA_MAX
Definition: Forth.ino:259
int compiling
Definition: Forth.ino:269
const int WHILE
Definition: Forth.ino:150
int lookup(const char *name)
Definition: FVM.cpp:101
bool compile(int op)
Definition: FVM.h:436
FVM_CALL(FORWARD_MARK)
int8_t code_t
Definition: FVM.h:248
Handle variable reference.
Definition: FVM.h:45
static const char DO_PSTR[]
Definition: FVM.cpp:1885
const int BEGIN
Definition: Forth.ino:129
#define FVM_COLON(id, var, name)
Definition: FVM.h:728
FVM fvm(data, DATA_MAX, DICT_MAX)
Print contents of parameter stack.
Definition: FVM.h:196
int scan(char *bp, task_t &task)
Definition: FVM.cpp:121
Definition: FVM.h:34
Print program memory string.
Definition: FVM.h:197
const char THEN_PSTR[]
Definition: Forth.ino:115
List dictionaries.
Definition: FVM.h:180
void setup()
Definition: Forth.ino:271
const char BEGIN_PSTR[]
Definition: Forth.ino:130