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