fork download
  1. // ABC: A human readable byte-code language
  2. // http://t...content-available-to-author-only...d.org/techref/idea/minimalcontroller.htm
  3.  
  4. #include <stdio.h>
  5. //yeah I know. But I think these are cool, so:
  6. #define TRUE (1==1)
  7. #define FALSE (!TRUE)
  8. //registers are made up of bytes, so 1 is the default size, this is really the
  9. //spacing /between/ registers, so the maximum size each register can process.
  10. //A size of 4 means 32 bit operations will be possible. 8 would be 64.
  11. //This doesn't matter until the op width can be set.
  12. #define REG_SIZE 4
  13. //size of the program memory
  14. #define MEM_SIZE 1000
  15. //amount of memory to include after 'z' register. Stack grows here
  16. #define STACK_SIZE 100
  17. int num;
  18. char dst, src;
  19. unsigned char op;
  20. char flag;
  21. #define REG_SIZE_CHARS (1+'z'-'a')*REG_SIZE+STACK_SIZE
  22. #define REG_SIZE_INTS REG_SIZE_CHARS / sizeof(int)
  23. union reg_t { char c[REG_SIZE_CHARS]; int i[REG_SIZE_INTS]; } reg;
  24. //1 indexed array of registers. 0 is "no register found"
  25. //Code memory for programs. Could be FLASH or EEPROM
  26. char mem[MEM_SIZE];
  27. char *radix; //radix. "r" in the register array
  28. int *pc; //program counter pointer. "p" in the register array
  29. int *next; //pointer to free location in memory for the next instruction.
  30. char c; //hold the current character being processed
  31.  
  32. int is_white_space(char c) {
  33. if (' '==c) return TRUE; //spaces have no effect
  34. if ('\r'==c) return TRUE; //\n ends a line \r is extra, need to skip it
  35. return FALSE;
  36. }
  37. char get_inst() { //get the next byte code instruction
  38. if (*pc) {
  39. return c = mem[*pc++]; //pre-defined code from ram
  40. }
  41. while (is_white_space(c = getchar()));//printf("got %d\n", c);
  42. if (c == EOF) c = FALSE;
  43. return c; //wait for the console.
  44. }
  45. void skip_line() {
  46. printf(" skip ");
  47. get_inst();
  48. while( c != 0 //End of File
  49. && c != '\n' //End of Line
  50. && c != '!' //"else"
  51. ) {
  52. get_inst();
  53. }
  54. printf(" past %d\n", c);
  55. get_inst();
  56. }
  57. int if_number(char c) {
  58. if ((c>='0' && c<='9') || (c>='A' && c<='F')) return TRUE;
  59. return FALSE;
  60. }
  61. void number() {
  62. while (if_number(c) ) {
  63. char digit = c-'0';
  64. if (digit>9) digit -= 'A'-'9';
  65. if (digit > *radix) {
  66. printf("\nERR: #%d > r%d\n",digit,*radix);
  67. return;
  68. }
  69. num *= *radix;
  70. num += digit;
  71. printf("#%d.",num);
  72. get_inst(); //if you used it, replace it.
  73. }
  74. }
  75. int is_register(char c) {
  76. if (c>='a' && c<='z') return TRUE;
  77. return FALSE;
  78. }
  79. int is_src_dst_reg(char sd) {
  80. if (sd >= 1 && sd <=26) return TRUE;
  81. return FALSE;
  82. }
  83. int registers() {
  84. char r = FALSE;
  85. if (is_register(c)) {//register
  86. r = 1 + c-'a'; //1 to 26
  87. r = r * REG_SIZE; //allocate some space between each register
  88. r += num; //if a number was given, offset by that amount. 4a is a+4
  89. //TODO: 'a' will end up as zero, which flags no destination?
  90. num = 0;
  91. get_inst(); //if you used it, replace it.
  92. printf(" r:%d.",r);
  93. }
  94. return r;
  95.  
  96. }
  97. #define FIRST_DEVICE 128
  98. int devices() {
  99. char d = FALSE;
  100. if (c>='A' && c<='Z') {//device
  101. d = c - 'A';
  102. d += FIRST_DEVICE;
  103. get_inst(); //if you used it, replace it.
  104. printf(" D:%d.",d);
  105. }
  106. return d;
  107. }
  108. void destination() {
  109. dst = registers();
  110. if (!dst) dst = devices();
  111. printf(" dst:%d.", dst);
  112. }
  113. void operation() {
  114. if ((c>' ' && c<'0') //after ctrl codes, but before numbers
  115. || (c>'9' && c<'A') //after numbers, but before uppercase letters
  116. || (c>'Z' && c<'a') //after uppercase, but below lowercase letters
  117. || (c>'a') //after lowercase letters.
  118. ) { //we have an operation
  119. op = c;
  120. get_inst(); //if you used it, replace it.
  121. if (c == op) { op+=128; get_inst();} //duplicate? set high bit
  122. if ('=' == c && '<' == op) { op = 'L'; get_inst();} //less than or equal
  123. if ('=' == c && '>' == op) { op = 'G'; get_inst();} //greater than or equal
  124. if ('\"' == c) { //quote
  125. if (is_src_dst_reg(dst)) { //move source to destination until EOF or ending "
  126. mem[reg.i[(int)dst]] = *pc; //point register to memory
  127. while(!(*pc || '\"' == c || EOF == c)) {
  128. mem[*next++] = c;
  129. get_inst();
  130. }
  131. }
  132. }
  133. printf(" op:%d.c:%d",op,c);
  134. }
  135. }
  136. void source() {
  137. src = registers();
  138. if (!src) src = devices();
  139. printf(" src:%d.", src);
  140. }
  141. int read_device(int src) {
  142. //TODO read devices.
  143. return 0;
  144. }
  145. void do_it() {
  146. //convert src and dst into the values at thier addresses for width
  147. //TODO support widths
  148. int src_val = 0;
  149. if (src <= sizeof(reg.c)) { //register
  150. src_val = reg.c[(int)src] + num; printf("src:%d %c val:%d. ", src, src/REG_SIZE, src_val);
  151. } else { //otherwise it's a device
  152. src_val = read_device(src);
  153. }
  154. int dst_val = reg.c[(int)dst];
  155. //use num if no source
  156. switch(op) {
  157. case ':': dst_val = src_val; break;
  158. case '+': dst_val += src_val; break;
  159. case '-': dst_val -= src_val; break;
  160. case '*': dst_val *= src_val; break;
  161. case '/': dst_val /= src_val; break;
  162. case '|': dst_val |= src_val; break;
  163. case '&': dst_val &= src_val; break;
  164. case '>'+128: dst_val >>= src_val; break;
  165. case '<'+128: dst_val <<= src_val; break;
  166. case '=': flag = (dst_val == src_val); break;
  167. case '>': flag = (dst_val > src_val); break;
  168. case '<': flag = (dst_val < src_val); break;
  169. case 'G': flag = (dst_val >= src_val); break;
  170. case 'L': flag = (dst_val <= src_val); break;
  171. case '(': break; //parameter list (register indirection)
  172. case ')': break; //call
  173. }
  174. //TODO support widths
  175. if (dst <= sizeof(reg.c)) { //register
  176. reg.i[(int)dst] = dst_val;
  177. } else { //otherwise it's a device
  178. switch(dst-FIRST_DEVICE+'A') {
  179. case 'P': //Port/pin
  180. break;
  181. }
  182. }
  183. printf("dst:%d %c val:%d.\n", dst, dst/REG_SIZE, dst_val);
  184. //look ahead for conditionals //TODO should this be under operation?
  185. switch(c) {
  186. case '?':
  187. if (flag) get_inst(); //continue with next
  188. else skip_line(); //fail
  189. dst = op = src = num = 0;
  190. break;
  191. case '!':
  192. skip_line();
  193. break;
  194. case '.': c=0; return;//TODO up stack to top. For now, just return
  195. }
  196. }
  197.  
  198. int done() {
  199. if (dst && op && (src || num)) {
  200. printf("\nDO: %c+%d %c= %c %d +#: %d. c:%c %d\n", dst/REG_SIZE+'`', dst % REG_SIZE, op, src/REG_SIZE+'`', src % REG_SIZE, num, c, c);
  201. do_it();
  202. op = src = 0;
  203. }
  204. if ('\n' == c) { printf(" line end\n");
  205. get_inst(); //if you used it, replace it.
  206. num = dst = src = op = 0;
  207. return TRUE;
  208. }
  209. if (0 == c) { printf(" file end\n");
  210. return TRUE;
  211. }
  212. if (0 == dst) { printf(" lost dst ");
  213. return TRUE;
  214. }
  215. return FALSE;
  216.  
  217. }
  218.  
  219. //register letter to address in reg array. 1 based so 0 is false.
  220. #define REG(x) ((1+x-'a')*REG_SIZE)
  221.  
  222. int main(void) {
  223. radix = &reg.c[REG('r')]; //register 'r' stores the radix
  224. *radix = 10;
  225. printf("radix %d (%d)\n", *radix, reg.c[REG('r')]);
  226. pc = (int *)&reg.c[REG('p')]; //questionable. TODO Better way?
  227. *pc = 0; //start accepting bytcodes from console, not memory
  228. printf("program counter %d (%d)\n", *pc, reg.c[REG('p')]);
  229. next = (int *)&reg.c[REG('n')]; //TODO Better way?
  230. *next = mem;
  231. dst = src = op = 0;
  232. flag = FALSE;
  233. get_inst(); //prime the pump
  234. //return 0;
  235. while(c) {
  236. number(); //prefix numbers add to reg address. e.g. 4a is b, 2P is 2nd port
  237. destination(); //register or device to send data to.
  238. do {
  239. operation(); //operation to perform on source for dest
  240. number(); //offset for source
  241. source(); //source value
  242. } while(!done()); //do we have everything? do it! repeat op and source
  243. }
  244. return 0;
  245. }
  246.  
Success #stdin #stdout 0s 5436KB
stdin
a:1
b:a+1
c:a+b+10
d:0
c=14?d:1!d:2
stdout
radix 10 (10)
program counter 0 (0)
 r:4. dst:4. op:58.c:49#1. src:0.
DO: a+0 := ` 0 +#: 1. c:
 10
src:0  val:1. dst:4  val:1.
 line end
 r:8. dst:8. op:58.c:97 r:4. src:4.
DO: b+0 := a 0 +#: 0. c:+ 43
src:4  val:0. dst:8  val:0.
 op:43.c:49#1. src:0.
DO: b+0 += ` 0 +#: 1. c:
 10
src:0  val:1. dst:8  val:1.
 line end
 r:12. dst:12. op:58.c:97 r:4. src:4.
DO: c+0 := a 0 +#: 0. c:+ 43
src:4  val:0. dst:12  val:0.
 op:43.c:98 r:8. src:8.
DO: c+0 += b 0 +#: 0. c:+ 43
src:8  val:0. dst:12  val:0.
 op:43.c:49#1.#10. src:0.
DO: c+0 += ` 0 +#: 10. c:
 10
src:0  val:10. dst:12  val:10.
 line end
 r:16. dst:16. op:58.c:48#0. src:0. line end
 r:12. dst:12. op:61.c:49#1.#14. src:0.
DO: c+0 == ` 0 +#: 14. c:? 63
src:0  val:14. dst:12  val:0.
 skip  past 33
 lost dst  r:16. dst:16. op:58.c:50#2. src:0.
DO: d+0 := ` 0 +#: 2. c:
 10
src:0  val:2. dst:16  val:2.
 line end