Advertisement
stuppid_bot

Недоделанный интерпретатор Lisp

Mar 21st, 2013
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <!DOCTYPE html>
  2. <html>
  3.     <head>
  4.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  5.         <title></title>
  6. <script type="text/javascript">                      
  7.  
  8. var globalEnvironment = {
  9.     't': true,
  10.     'nil': false,
  11.    
  12.     '+': function(vargs) {      
  13.         return op( function(left, right) {
  14.             return left + right;
  15.         }, vargs );
  16.     },
  17.    
  18.     '-': function(vargs) {      
  19.         return op( function(left, right) {
  20.             return left - right;
  21.         }, vargs );
  22.     },
  23.    
  24.     '*': function(vargs) {      
  25.         return op( function(left, right) {
  26.             return left * right;
  27.         }, vargs );
  28.     },
  29.    
  30.     '/': function(vargs) {      
  31.         return op( function(left, right) {
  32.             return left / right;
  33.         }, vargs );
  34.     }
  35. }
  36.  
  37. function op(cb, vargs) {
  38.     if (vargs.length < 2) {
  39.         throw 'требуется минимум 2 аргумента';
  40.     }
  41.  
  42.     var i = 0, result = vargs[0];
  43.    
  44.     while (1) {
  45.         if ( ++i == vargs.length ) {
  46.             break;
  47.         }
  48.        
  49.         result = cb( result, vargs[i] );
  50.     }
  51.  
  52.     return result;
  53. }
  54.  
  55. var parse = function(input) {
  56.     // в js нет просмотра назад хз как всё описать с помощью одной регулярки
  57.     var tokens = /;.*|"((?:[^"\\]|\\[\s\S])*)"|([^\s`();'",]{2,}|[^\s`();'",.])|(\S)/g,
  58.         tok,
  59.         expArr = [];
  60.    
  61.     function readToken() {
  62.         var tok, i;
  63.        
  64.         while ( tok = tokens.exec(input) ) {
  65.             for (i = 1; i < tok.length; ++i) {
  66.                 if ( tok[i] ) {
  67.                     return tok;
  68.                 }
  69.             }
  70.         }  
  71.     }  
  72.    
  73.     function parseToken(tok) {  
  74.         if ( tok[1] ) {
  75.             return [ 'string', tok[1].replace( /\\"/g, '"') ];
  76.         }
  77.  
  78.         if ( tok[2] ) {
  79.             if (tok[2] < 0 || tok[2] == 0 || tok[2] > 0) {
  80.                 return [ 'number', tok[2] * 1 ];
  81.             }  
  82.  
  83.             return [ 'word', tok[2].toLowerCase() ];
  84.         }
  85.  
  86.         if (tok[3] == '(') {
  87.             var arr = [ 'list', [] ];
  88.  
  89.             while ( tok = readToken() ) {
  90.                 if (tok[3] == ')') {
  91.                     return arr;
  92.                 }
  93.  
  94.                 arr[1].push( parseToken(tok) );
  95.             }
  96.  
  97.             throw 'Возможно, пропущена )';
  98.         }
  99.  
  100.         throw 'Неожиданный токен ' + tok[3] + ' на позиции ' + tok.index;
  101.     }
  102.    
  103.     while ( tok = readToken() ) {
  104.         expArr.push( parseToken(tok) );
  105.     }
  106.      
  107.     return expArr;
  108. }
  109.  
  110. // new Environment( B, new Environment( A ) )
  111. //
  112. // undefined
  113. //  \
  114. //   A - data
  115. //    \
  116. //     B - data
  117. //
  118. // Где A, B - узлы. B.parent содержит ссылку на A.
  119. function Environment(data, parent) {
  120.     this.data = data;
  121.     this.parent = parent;    
  122. }
  123.  
  124. Environment.prototype.lookup = function(id) {
  125.     var scope = this, data;
  126.    
  127.     while (scope) {
  128.         if (scope.data[id] !== undefined) {
  129.             return scope.data[id];
  130.         }
  131.        
  132.         // если в текущем scope переменную не нашли смотрим на уровень выше
  133.         scope = scope.parent;
  134.     }
  135.    
  136.     throw 'Обьект ' + id + ' не найден';
  137. }
  138.  
  139. function evaluate(exp, env) {  
  140.     switch ( exp[0] ) {
  141.         case 'word':
  142.             return env.lookup( exp[1] );
  143.            
  144.         case 'list':
  145.             var name;
  146.            
  147.             exp = exp[1];
  148.             name = exp[0][1];
  149.             exp[0] = evaluate( exp[0], env );
  150.            
  151.             if ( typeof exp[0] == 'function' ) {
  152.                
  153.                 for (var i = 1; i < exp.length; ++i) {
  154.                     exp[i] = evaluate( exp[i], env )
  155.                 }
  156.                
  157.                 try {
  158.                     return exp[0].call(null, exp.slice(1), env);
  159.                 }
  160.                 catch (err) {
  161.                     throw 'Ошибка в функции ' + name + ': ' + err;
  162.                 }
  163.             }
  164.            
  165.             throw '"' + name + '" не является функцией';
  166.            
  167.         default:
  168.             return exp[1];
  169.     }
  170. }
  171.  
  172. function execute(input) {
  173.     var expArr =  parse(input),
  174.         env = new Environment( {}, new Environment( globalEnvironment ) );
  175.      
  176.     alert( 'Подобие байт-кода:\n\n' +  JSON.stringify(expArr) );  
  177.    
  178.     for (var i = 0; i < expArr.length; ++i) {
  179.         alert( evaluate(expArr[i], env) );
  180.     }
  181. }
  182.  
  183. // Ссылки:
  184. //
  185. // http://ru.wikipedia.org/wiki/Лексический_анализ
  186. // http://ru.wikipedia.org/wiki/Интерпретатор_(шаблон_проектирования)
  187. // http://ru.wikipedia.org/wiki/Польская_нотация
  188. // http://en.wikibooks.org/wiki/Common_Lisp/First_steps/Beginner_tutorial
  189. // http://www.csci.csusb.edu/dick/samples/lisp.lexemes.html
  190.  
  191. var ge = function(id) {
  192.     return document.getElementById(id);
  193. }
  194.  
  195. window.addEventListener( 'load', function() {  
  196.     ge('execute').onclick = function() {
  197.         try {
  198.             execute( ge('input').value );
  199.         }
  200.         catch (err) {
  201.             alert(err);
  202.         }
  203.     }
  204. } );
  205.    
  206. </script>
  207.     </head>
  208.     <body>
  209.         <textarea id="input"></textarea> <button id="execute">Выполнить!</button>      
  210.     </body>
  211.     <script> // alert( document.getElementsByTagName('script')[0].innerText ); </script>
  212. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement