fork(1) download
  1. //ABC.c A minimal interpreted human readable bytecode language
  2. //http://t...content-available-to-author-only...d.org/techref/idea/minimalcontroller.htm
  3.  
  4. #include <stdio.h>
  5.  
  6. #define NUM_PORTS 3
  7. //number of IO ports to support.
  8. #define VAR_SIZE 4
  9. //bytes of storage in each variable
  10.  
  11. #define STACK_SIZE 10
  12. #define NUM_VARS ( (VAR_SIZE*('z'-'a')) + STACK_SIZE + 2 )
  13. //number of memory spaces needed for variables.
  14. //some number of bytes per variable address (a-z) plus stack size after that.
  15. #define START_STACK ( NUM_VARS - STACK_SIZE + 1 )
  16. //stack starts inside the variable sapce, but at the end, after 'z'
  17. #define NUM_LCDS 40
  18.  
  19. #define START_PORTS ( NUM_VARS + 1 )
  20. //memory reserved to shadow IO ports
  21. #define START_LCD ( START_PORTS + NUM_PORTS + 1 )
  22. //memory reserved to shadow local display
  23. #define NUM_MEMS ( START_LCD + NUM_LCDS )
  24. //amount of RAM memory required.
  25. //TODO: add a check to verify this uC has that much available.
  26.  
  27. #define NUM_FLASH 2048
  28. //amount of FLASH or EEPROM memory
  29.  
  30. //use the first line for debug output, the second to remove it from any optimizing compiler
  31. #define DEBUG if(1)
  32. //#define DEBUG if(0)
  33.  
  34. char abc; //the incomming character
  35. int skip_lines=0; //count of the number of lines to skip in branches.
  36. unsigned char dst,src;
  37. /* SRC and DST reference up to 128 8 bit "registers" or, when the high bit is set,
  38. one of the devices (LCD/Keys, Serial, EEPROM, IO). Defaults to LCD/Keys. */
  39. bool src_dst=false; //set when the SRC register is to be loaded, clear for DST
  40. /* The DST is set first, and the SRC/DST flag toggled so that SRC is loaded next at
  41. which point the current operation and comparison are performed. */
  42. int num=0; //numeric accumulator. Hex digits (0-9, A-F) are added into this
  43. /* If SRC is not loaded (zero), NUM is the SRC. */
  44. unsigned char op=0; //Operation
  45. /* OP stores the operation to perform once we have a SRC (we should already have
  46. a DST) or when the line ends. After each operation SRC is cleared.
  47. At the end of each line, SRC/DST and DST is cleared. Since there is only one SRC
  48. at a time, binary operations like addition always accumulate into DST. i.e. DST
  49. is the implied second source in binary operations. The default operation, when
  50. no other is specified, is copy. i.e. if only a DST, then a SRC are specified,
  51. the value of the SRC is simply written to the DST. OP is not cleared so that "
  52. can escape ". In other words, so that quote can escape quote. */
  53. bool true_flag; //set when the comparison finds truth, clear when false.
  54. unsigned char vars[NUM_MEMS];
  55. unsigned char flash[NUM_FLASH];
  56. int flashptr=1;
  57. //can't start at address 0 in flash because a call to that address looks like console
  58. int pcptr=0; //just a temp var to hold the current PC pointer
  59.  
  60. unsigned char pcp=START_STACK;
  61. //program counter pointer starts at TOS, in var space, after 'z'
  62.  
  63. void doop() {
  64. if (dst && op && (src || num) ) { //got enough to work with
  65. if ('"'==op) { //Quote? but don't update vars[dst] if it's a variable.
  66. if (NUM_VARS>dst) { //'cause it's a value quoted to a variable ptr
  67. flash[flashptr]=src; //so actually write it to flash instead
  68. DEBUG printf("\nflash[%i]=%c",flashptr,src);
  69. flashptr++; //and move to next space in flash
  70. return; //and that's it.
  71. }
  72. }
  73. else if (src>=START_PORTS) {
  74. //on a real uC, we would update vars[src] with the value of the port
  75. //so add code here to actually read the port.
  76. DEBUG printf(" reading %i from port %i",vars[src],src-NUM_VARS);
  77. };
  78. num += vars[src];
  79. switch(op) {
  80. case ':': vars[dst]=num; break;
  81. case '+': vars[dst]+=num; break;
  82. case '-': vars[dst]-=num; break;
  83. case '*': vars[dst]*=num; break;
  84. case '/': vars[dst]/=num; break;
  85. case '=': true_flag=(vars[dst]==num); break;
  86. case '<': true_flag=(vars[dst]<num); break;
  87. case '>': true_flag=(vars[dst]>num); break;
  88. case '{': true_flag=(vars[dst]<=num); break;
  89. case '}': true_flag=(vars[dst]>=num); break;
  90. case '|': true_flag=(vars[dst]|=num); break;
  91. case '&': true_flag=(vars[dst]&=num); break;
  92. case '`': true_flag=(vars[dst]!=num); break;
  93. }
  94. DEBUG {
  95. switch(op) {
  96. case ':': case '+': case '-': case '*': case '/':
  97. printf("\n vars\t[dst]\t%c=\tvars\t[src]\t+num;",op);
  98. printf("\n \\\\%i\t[%i]\t%c=\t%i\t[%i]\t+%i",vars[dst],dst,op,vars[src],src,num);
  99. break;
  100. case '"':
  101. break;
  102. default:
  103. printf("\n flag=\t(vars\t[dst]\t%c=\tvars\t[src]\t+num);",op);
  104. printf("\n \\\\%c\t %i\t[%i]\t%c=\t%i\t[%i]\t+%i",true_flag?'Y':'N',vars[dst],dst,op,vars[src],src,num);
  105. break;
  106. }
  107. }
  108. if (dst>=NUM_VARS && dst<NUM_LCDS) {
  109. DEBUG printf(" writing %i to port %i",src,dst-START_PORTS);
  110. //on a real uC, we would update the port with the value of vars[dst]
  111. //so add code here to actually write to the port.
  112. };
  113. if (dst>=NUM_LCDS) {
  114. DEBUG printf(" writing %c to LCD @ %i",src,dst-START_LCD);
  115. //on a real uC, we would actually write the character to the LCD
  116. dst++; //move to the next character on the LCD.
  117. };
  118. num=0;
  119. DEBUG printf("\n num=0;src=0;");
  120. src = 0; //clear source leave dst and op.
  121. }
  122. }
  123.  
  124. int main () {
  125. printf("Ready %i\n", NUM_MEMS);
  126. vars[pcp+0] = 0;
  127. vars[pcp+1] = 0;
  128. vars[pcp+2] = 0;
  129. //initialize the current PC to zero...
  130. pcptr = 0;
  131. //which flags that we are executing from the console
  132. while ( (pcptr=((vars[pcp+2]<<16) + (vars[pcp+1]<<8) + (vars[pcp+0]<<0))) //Not executing from FLASH?
  133. || EOF != (abc=getchar()) //get a character from the console, until EOF
  134. ) {
  135. //DEBUG printf("pcptr=%u, abc=%c",pcptr,abc);
  136. if (!abc) { //we didn't get a character from the console
  137. abc = flash[pcptr];
  138. //get abc from flash at PC, and increment PC
  139. //DEBUG printf("GOT %c from %u via pcp %u",abc,vars[pcp],pcp);
  140. if(!(++vars[pcp+0])) if (!(++vars[pcp+1])) if (!(++vars[pcp+2]));
  141. //increment must roll over to pcp+1, etc... Note: pcptr updated next time around
  142. }
  143. //can we process a ready operation here first? Helps with quote. TODO: test.
  144. if (src) doop(); // if we already had a source, process it first
  145. if ('\n'==abc) {
  146. // DEBUG printf("\n ");
  147. doop();
  148. src_dst=false; //reset back to looking for destinations at EOL
  149. num=op=0;
  150. if (skip_lines) {
  151. skip_lines--;
  152. DEBUG printf("\n----------------");
  153. continue;
  154. }
  155. }
  156. else printf("\n%c ",abc);
  157. if (skip_lines) {
  158. DEBUG printf("skipped");
  159. continue;
  160. }
  161. if ('\"'==abc) {
  162. DEBUG printf("quote, op==%c",op);
  163. if ('\"'==op) {//ending quote?
  164. op=' '; //secret op means we were quoting.
  165. abc=' ';
  166. DEBUG printf(" ending quote");
  167. }
  168. else if (' '==op) { //double quote
  169. op='"'; //just pickup where we left off
  170. DEBUG printf(" double quote");
  171. }
  172. else if (NUM_VARS>dst && ':'==op) {
  173. vars[dst+0]=flashptr>> 0 & 0xFF;
  174. vars[dst+1]=flashptr>> 8 & 0xFF;
  175. vars[dst+2]=flashptr>>16 & 0xFF;
  176. //This may be a 3 or 4 byte value. Could be more efficient.
  177. DEBUG printf("vars[%i]=%i //assign variable to flashptr", dst, flashptr);
  178. }
  179. //continue;
  180. } //done with input was a quote
  181. if ('"'==op) { //If we are quoting
  182. src=abc; //value of input in source, just pass it on
  183. DEBUG printf(" src=%i;",src);
  184. }
  185. else if ((abc>='A' && abc<='F') || (abc>='0' && abc<='9')) { //number
  186. num *= 16;
  187. num += (abc>'9' ? abc-'A'+10 : abc-'0');
  188. DEBUG printf(" num=%i;",num);
  189. }
  190. else if (('a'<=abc && 'z'>=abc) || (abc>='G' && abc<='Z')) { //variable or function
  191. switch(abc) {
  192. case 'P': //Port and pin.
  193. num+=START_PORTS; //correct P to past the last variable
  194. DEBUG printf(" port=%i;",num);
  195. break;
  196. case 'L': //Local display
  197. DEBUG printf("local display @%i",num);
  198. num+=START_LCD;
  199. break;
  200. default: //it's a variable
  201. num += ((abc-'a')*VAR_SIZE)+1; //spread out in var space by VAR_SIZE
  202. break;
  203. }
  204. //variables or functions can be sources or destinations.
  205. if (!src_dst) { //looking for a destination
  206. dst = num;
  207. DEBUG printf(" dst=%i;vars[dst]=%i",dst,vars[dst]);
  208. src_dst=true;
  209. }
  210. else { //looking for a source
  211. src = num;
  212. DEBUG printf(" src=%i;",src);
  213. //src_dst=true; //stay on sources until EOL.
  214. }
  215. num = 0;
  216. }
  217. else switch(abc) { //must be an operator
  218. case '@':
  219. if (src) { //if we have a source
  220. num+=vars[src];
  221. src=0;
  222. DEBUG printf(" num=%i;src=0;",num);
  223. }
  224. else {
  225. num+=vars[dst];
  226. dst=0;
  227. DEBUG printf(" num=%i;dst=0;",num);
  228. src_dst=false;//look for another destination.
  229. };
  230. break;
  231. case '?':
  232. doop();
  233. if (!true_flag) {
  234. skip_lines=1;
  235. DEBUG printf(" FALSE! (skip the line)");
  236. }
  237. else {
  238. DEBUG printf(" TRUE! {continue}");
  239. };
  240. src_dst=false; //reset back to looking for destinations at EOL
  241. break;
  242. case ')': //call. PCP++, (DST)->var(PCP)
  243. //Check if dst is a variable.
  244. if (NUM_VARS < dst) {
  245. DEBUG printf("ERROR: Call to other than variable address!");
  246. return 1;
  247. }
  248. pcp+=VAR_SIZE; //increment PCP to the next variable space
  249. // check if PCP > NUM_MEMS. Stack overflow
  250. if (NUM_VARS < pcp) {
  251. DEBUG printf("ERROR: Stack Overflow!");
  252. return 1;
  253. }
  254. //copy the value of dst to the new pcp
  255. vars[pcp+0]=vars[dst+0];
  256. vars[pcp+1]=vars[dst+1];
  257. vars[pcp+2]=vars[dst+2];
  258. src_dst=false;
  259. DEBUG printf(" CALL %c at %u, via pcp %u", dst+'a'-1, ((vars[pcp+2]<<16)+(vars[pcp+1]<<8)+(vars[pcp+0]<<0)), pcp);
  260. break;
  261. case '.': //return. 0!=var(PCP)? PCP--
  262. //TODO: check if we are already on the console
  263. //Check if PCP >= VAR_SIZE
  264. DEBUG printf(" RETURN to %u, via pcp %u",vars[pcp],pcp);
  265. if (START_STACK >= pcp) {
  266. DEBUG printf("ERROR: Return stack underflow. Return while not in subroutine?");
  267. break;
  268. }
  269. doop(); //finish up whatever was done in the subroutine
  270. pcp-=VAR_SIZE; //decrement PCP to the prior variable space
  271. break;
  272. case '\n':
  273. DEBUG printf("\n----------------");
  274. break;
  275. default:
  276. doop(); //in case we already have a destination, operation and source.
  277. if ('='==abc && op) { // an equal might come after < or >
  278. abc=op+('{'-'<');
  279. // add 123 - 60 or 63. This maps <, =, > to {, |, }
  280. // <= is {, == is |, >= is }, ?= is ~, != is ` (back single quote)
  281. // so don't use {} in the future! () and [] are ok.
  282. }
  283.  
  284. op=abc;
  285. DEBUG printf(" op=\'%c\';",op);
  286. break;
  287. }
  288. //putchar(abc);
  289. abc=0; //done with this character.
  290. }
  291. }
Success #stdin #stdout 0s 15240KB
stdin
a:"c:1F."
a)
c=1F?b:1
b!=1?b:2
z:a+1/2
P:4y
a@b:2P
b:a|0F
c:a&0F
L"abc""def"
d:"b=1?P:P&1."
stdout
Ready 157

a   dst=1;vars[dst]=0
:   op=':';
"  quote, op==:vars[1]=1 //assign variable to flashptr op='"';
c   src=99;
flash[1]=c
:   src=58;
flash[2]=:
1   src=49;
flash[3]=1
F   src=70;
flash[4]=F
.   src=46;
flash[5]=.
"  quote, op==" ending quote
  flag=	(vars	[dst]	 =	vars	[src]	+num);
 \\N	 1	[1]	 =	0	[46]	+0
   num=0;src=0; op=' ';
----------------
a   dst=1;vars[dst]=1
)   CALL a at 1, via pcp 107
c   dst=9;vars[dst]=0
:   op=':';
1   num=1;
F   num=31;
.   RETURN to 6, via pcp 107
   vars	[dst]	:=	vars	[src]	+num;
 \\31	[9]	:=	0	[0]	+31
   num=0;src=0;
----------------
c   dst=9;vars[dst]=31
=   op='=';
1   num=1;
F   num=31;
?  
  flag=	(vars	[dst]	==	vars	[src]	+num);
 \\Y	 31	[9]	==	0	[0]	+31
   num=0;src=0; TRUE! {continue}
b   dst=5;vars[dst]=0
:   op=':';
1   num=1;
   vars	[dst]	:=	vars	[src]	+num;
 \\1	[5]	:=	0	[0]	+1
   num=0;src=0;
----------------
b   dst=5;vars[dst]=1
!   op='!';
=   op='`';
1   num=1;
?  
  flag=	(vars	[dst]	`=	vars	[src]	+num);
 \\N	 1	[5]	`=	0	[0]	+1
   num=0;src=0; FALSE! (skip the line)
b  skipped
:  skipped
2  skipped
----------------
z   dst=101;vars[dst]=0
:   op=':';
a   src=1;
   vars	[dst]	:=	vars	[src]	+num;
 \\1	[101]	:=	1	[1]	+1   writing  to LCD @ -16
   num=0;src=0;
+   op='+';
1   num=1;
/  
   vars	[dst]	+=	vars	[src]	+num;
 \\1	[102]	+=	0	[0]	+1   writing  to LCD @ -15
   num=0;src=0; op='/';
2   num=2;
   vars	[dst]	/=	vars	[src]	+num;
 \\0	[103]	/=	0	[0]	+2   writing  to LCD @ -14
   num=0;src=0;
----------------
P   port=113; dst=113;vars[dst]=0
:   op=':';
4   num=4;
y   src=101;
   vars	[dst]	:=	vars	[src]	+num;
 \\1	[113]	:=	1	[101]	+1   writing e to LCD @ -4
   num=0;src=0;
----------------
a   dst=1;vars[dst]=1
@   num=1;dst=0;
b   dst=6;vars[dst]=0
:   op=':';
2   num=2;
P   port=115; src=115;   reading 0 from port 3
   vars	[dst]	:=	vars	[src]	+num;
 \\0	[6]	:=	0	[115]	+0
   num=0;src=0;
----------------
b   dst=5;vars[dst]=1
:   op=':';
a   src=1;
   vars	[dst]	:=	vars	[src]	+num;
 \\1	[5]	:=	1	[1]	+1
   num=0;src=0;
|   op='|';
0   num=0;
F   num=15;
  flag=	(vars	[dst]	|=	vars	[src]	+num);
 \\Y	 15	[5]	|=	0	[0]	+15
   num=0;src=0;
----------------
c   dst=9;vars[dst]=31
:   op=':';
a   src=1;
   vars	[dst]	:=	vars	[src]	+num;
 \\1	[9]	:=	1	[1]	+1
   num=0;src=0;
&   op='&';
0   num=0;
F   num=15;
  flag=	(vars	[dst]	&=	vars	[src]	+num);
 \\Y	 1	[9]	&=	0	[0]	+15
   num=0;src=0;
----------------
L  local display @0 dst=117;vars[dst]=0
"  quote, op== op='"';
a   src=97;   writing a to LCD @ 0
   num=0;src=0;
b   src=98;   writing b to LCD @ 1
   num=0;src=0;
c   src=99;   writing c to LCD @ 2
   num=0;src=0;
"  quote, op==" ending quote op=' ';
"  quote, op==  double quote src=34;   writing " to LCD @ 3
   num=0;src=0;
d   src=100;   writing d to LCD @ 4
   num=0;src=0;
e   src=101;   writing e to LCD @ 5
   num=0;src=0;
f   src=102;   writing f to LCD @ 6
   num=0;src=0;
"  quote, op==" ending quote op=' ';
----------------
d   dst=13;vars[dst]=0
:   op=':';
"  quote, op==:vars[13]=6 //assign variable to flashptr op='"';
b   src=98;
flash[6]=b
=   src=61;
flash[7]==
1   src=49;
flash[8]=1
?   src=63;
flash[9]=?
P   src=80;
flash[10]=P
:   src=58;
flash[11]=:
P   src=80;
flash[12]=P
&   src=38;
flash[13]=&
1   src=49;
flash[14]=1
.   src=46;
flash[15]=.
"  quote, op==" ending quote
  flag=	(vars	[dst]	 =	vars	[src]	+num);
 \\Y	 6	[13]	 =	0	[46]	+0
   num=0;src=0; op=' ';
----------------