underload.html 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <HTML>
  2. <HEAD>
  3. <TITLE>Underload</TITLE>
  4. <SCRIPT>
  5. // Released to the public domain.
  6. function pop(s)
  7. {
  8. if(s.value.indexOf("<>")==-1) {throw("ERROR: Empty stack");}
  9. var t=s.value.substr(0,s.value.indexOf("<>"));
  10. s.value=s.value.substr(s.value.indexOf("<>")+2);
  11. return t;
  12. }
  13. function push(s,t)
  14. {
  15. s.value=t+"<>"+s.value;
  16. }
  17. function step(lp)
  18. {
  19. try
  20. {
  21. if(lp)
  22. {
  23. document.getElementById('startrun').style.display="none";
  24. document.getElementById('stoprun').style.display="block";
  25. }
  26. var s=document.getElementById('stack');
  27. var p=document.getElementById('prog');
  28. var o=document.getElementById('op');
  29. var c=p.value.substr(0,1);
  30. if(p.value=="") throw("Program terminated normally.");
  31. p.value=p.value.substr(1);
  32. if(c=='S') o.value+=pop(s);
  33. else if(c=='~') {var t1, t2; t1=pop(s); t2=pop(s); push(s,t1); push(s,t2);}
  34. else if(c==':') {var t1; t1=pop(s); push(s,t1); push(s,t1);}
  35. else if(c=='!') pop(s);
  36. else if(c=='*') {var t1, t2; t1=pop(s); t2=pop(s); push(s,t2+t1);}
  37. else if(c=='a') {var t1; t1=pop(s); push(s,"("+t1+")");}
  38. else if(c=='^') p.value=pop(s)+p.value;
  39. else if(c==')') throw("ERROR: Unmatched )");
  40. else if(c=='(')
  41. {
  42. var t1,i,n;
  43. i=0; n=1;
  44. while(n)
  45. {
  46. if(p.value.substr(i,1)==')') n--;
  47. if(p.value.substr(i,1)=='(') n++;
  48. i++;
  49. if(i>p.value.length) throw("ERROR: Unmatched (");
  50. }
  51. t1=p.value.substr(0,i-1);
  52. p.value=p.value.substr(i);
  53. push(s,t1);
  54. }
  55. else if(c=='<') throw("Program stopped by user."); // abort of program
  56. else throw("ERROR: Unrecognized command");
  57. if(lp) window.setTimeout("step("+lp+")",lp);
  58. }
  59. catch(s)
  60. {
  61. alert(s);
  62. document.getElementById('startrun').style.display="block";
  63. document.getElementById('stoprun').style.display="none";
  64. }
  65. }
  66. function abortrun()
  67. {
  68. var p=document.getElementById('prog');
  69. p.value='<'+p.value;
  70. }
  71. function unl2ul()
  72. {
  73. var p=document.getElementById('prog');
  74. var v=new Array();
  75. var vi=0;
  76. var o="";
  77. var c;
  78. while(p.value!="")
  79. {
  80. c=p.value.substr(0,1);
  81. p.value=p.value.substr(1);
  82. if(c=='`') v[vi++]=0;
  83. if(c=='.') {o+='.'; c=p.value.substr(0,1); p.value=p.value.substr(1);}
  84. else if(c=='`') continue;
  85. o+=c;
  86. while(1)
  87. {
  88. if(v[vi-1]) {o+='`'; vi--;}
  89. else {v[vi-1]=1; break;}
  90. }
  91. }
  92. while(vi>0) {o+='`'; vi--;}
  93. while(o!="")
  94. {
  95. c=o.substr(0,1);
  96. o=o.substr(1);
  97. if(c=='`') p.value+='~^';
  98. if(c=='s') p.value+='((:)~*(~)*a(~*(~^)*)*)';
  99. if(c=='k') p.value+='(a(!)~*)';
  100. if(c=='i') p.value+='()';
  101. if(c=='.')
  102. {
  103. c=o.substr(0,1);
  104. o=o.substr(1);
  105. p.value+='(('+c+')S)';
  106. }
  107. }
  108. }
  109. </SCRIPT>
  110. <STYLE>
  111. TT.examplett
  112. {
  113. cursor:hand;
  114. color:blue;
  115. }
  116. </STYLE>
  117. </HEAD>
  118. <BODY>
  119. <H1>Underload</H1>
  120. <H2>Basics</H2>
  121. Underload is a stack-based programming language that works along similar lines to
  122. Muriel. Although not technically speaking a functional language, its evaluation
  123. operator <TT>^</TT> (which is the only form of flow control) makes programming in
  124. it functional in practice.
  125. <H2>Reserved characters</H2>
  126. The bracket and angle bracket characters <TT>[]&lt;&gt;</TT> are reserved; if these are
  127. to appear anywhere in the program, they must be quoted by placing <TT>"</TT> before them.
  128. This also applies to the <TT>"</TT> character itself. Other characters must <I>not</I> be
  129. quoted with <TT>"</TT> (in particular, this means that Underload programs cannot output
  130. strings containing unmatched parentheses). Parentheses are moderately reserved, in that
  131. any Underload program must have matched parentheses to be legal.
  132. <H2>Commands</H2>
  133. <UL>
  134. <LI><TT>~</TT>&nbsp;Swap the top two elements of the stack.</LI>
  135. <LI><TT>:</TT>&nbsp;Duplicate the top element of the stack.</LI>
  136. <LI><TT>!</TT>&nbsp;Discard the top element of the stack.</LI>
  137. <LI><TT>*</TT>&nbsp;Concatenate the top element of the stack to the end of
  138. the second element of the stack.</LI>
  139. <LI><TT>(</TT>&nbsp;Push everything between the <TT>(</TT> and the matching
  140. <TT>)</TT> on top of the stack.</LI>
  141. <LI><TT>)</TT>&nbsp;Closes a <TT>(</TT> command.</LI>
  142. <LI><TT>a</TT>&nbsp;Encloses the top element of the stack in a pair of
  143. parentheses.</LI>
  144. <LI><TT>^</TT>&nbsp;When the <TT>^</TT> command is called, it includes the top element
  145. of the stack into the program, immediately after the <TT>^</TT> command, ready to be run
  146. next.</LI>
  147. <LI><TT>S</TT>&nbsp;Output the top element of the stack, popping it.</LI>
  148. </UL>
  149. <H2>Exceptional circumstances</H2>
  150. Pretty much anything whose behaviour isn't specifically given here (for instance, running
  151. <TT>*</TT> on an empty stack) is an error.
  152. <H2>Unlambda to Underload</H2>
  153. The <TT>s</TT>, <TT>k</TT>, and <TT>i</TT> characters in Unlambda can all be
  154. translated directly into Underload. Also, the <TT>`</TT> character can be
  155. translated, but it has to be moved to a postfix rather than prefix position, and
  156. <TT>.<I>x</I></TT> can be translated for most values of <I>x</I>.
  157. <UL>
  158. <LI><TT>s</TT> translates to <TT>((:)~*(~)*a(~*(~^)*))</TT>:
  159. <DL><DD>
  160. <TT>sx`y`z`&nbsp;=&nbsp;xz`yz``</TT> (postfix notation)<BR />
  161. <TT>sx`y`&nbsp;&nbsp;&nbsp;=&nbsp;(:x~y~^)</TT><BR />
  162. <TT>sx`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;((:x~)~*(~^)*)</TT><BR />
  163. <TT>s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;((:)~*(~)*a(~*(~^)*)*)</TT>
  164. </DD></DL></LI>
  165. <LI><TT>k</TT> translates to <TT>(a(!)~*)</TT></LI>
  166. <LI><TT>i</TT> translates to <TT>()</TT></LI>
  167. <LI><TT>`</TT> translates to <TT>~^</TT></LI>
  168. <LI><TT>.<I>x</I></TT> translates to <TT>((<I>x</I>)S)</TT></LI>
  169. </UL>
  170. These translations prove that Underload is Turing-complete, because it can be compiled into
  171. from the Turing-complete `sk Unlambda.
  172. <H2>Example programs</H2>
  173. Click on any of these programs to load them in the interpreter below.
  174. <H3>Hello, world!</H3>
  175. <TT CLASS="examplett" ONCLICK="document.getElementById('prog').value=
  176. '(Hello, world!)S';void(0);">
  177. (Hello, world!)S</TT>
  178. <H3>Fibonacci sequence</H3>
  179. <TT CLASS="examplett" ONCLICK="document.getElementById('prog').value=
  180. '(()(*))(~:^:S*a~^a~!~*~:(/)S^):^';void(0);">
  181. (()(*))(~:^:S*a~^a~!~*~:(/)S^):^</TT><BR/>
  182. (An ski`. Unlambda version is
  183. <TT CLASS="examplett" ONCLICK="document.getElementById('prog').value=
  184. '```s``s``sii`ki`k.*``s``s`ks``s`k`s`ks``s``s`ks``s`k`s`k./``s`k`sikk`k``s`ksk';void(0);">
  185. ```s``s``sii`ki`k.*``s``s`ks``s`k`s`ks``s``s`ks``s`k`s`k./``s`k`sikk`k``s`ksk</TT>,
  186. which can also be loaded up in the interpreter below by clicking on it; you can automatically
  187. convert it to Underload if you wish to run it.)
  188. <H3>Infinite loop</H3>
  189. <TT CLASS="examplett" ONCLICK="document.getElementById('prog').value=
  190. '(:^):^';void(0);">
  191. (:^):^</TT><BR/>
  192. (This is exactly equivalent to the ski`. Unlambda program
  193. <TT CLASS="examplett" ONCLICK="document.getElementById('prog').value=
  194. '```sii``sii';void(0);">
  195. ```sii``sii</TT>;
  196. if the Unlambda program is converted to Underload using the compiler below and run for a while,
  197. it eventually ends up in the same state as the previous Underload program (the only difference
  198. being <TT>~~</TT>, which has no effect, in the code derived from the Unlambda).
  199. <H3>Quine</H3>
  200. <TT CLASS="examplett" ONCLICK="document.getElementById('prog').value=
  201. '(:aSS):aSS';void(0);">
  202. (:aSS):aSS</TT><BR/>
  203. (The null program is also a quine. This program is more stack-based than functional.)
  204. <H2>Online interpreter</H2>
  205. When using this interpreter, note that newlines and spaces in code will cause errors unless they
  206. are inside () quoting; also, avoid newlines in Unlambda input, as different browers
  207. will interpret them in different manners, and some may crash as a result. The ski`. Unlambda
  208. to Underload compiler only supports the s, k, i, `, and .<I>x</I> commands; it doesn't even
  209. allow comments or spaces.<BR />
  210. Program:<BR />
  211. <TEXTAREA ROWS=10 COLS=80 ID='prog'></TEXTAREA><BR />
  212. Stack:<BR />
  213. <TEXTAREA ROWS=10 COLS=80 ID='stack'></TEXTAREA><BR />
  214. Output:<BR />
  215. <TEXTAREA ROWS=10 COLS=80 ID='op'></TEXTAREA><BR />
  216. <DIV ID='startrun'>
  217. <A HREF="javascript:step(0)">Single-step through program</A><BR />
  218. <A HREF="javascript:step(500)">Run program (500ms delay)</A>
  219. <A HREF="javascript:step(100)">(100ms delay)</A>
  220. <A HREF="javascript:step(10)">(10ms delay)</A><BR />
  221. <A HREF="javascript:unl2ul()">Convert ski`. Unlambda to Underload</A>
  222. </DIV>
  223. <A ID='stoprun' STYLE='display:none' HREF="javascript:abortrun()">Stop running program</A>
  224. <I>This HTML file has been released to the public domain by its previous copyright holder.</I>
  225. </BODY>
  226. </HTML>