カテゴリー
最近更新したページ
最新コメント
KEMURI生成プログラム by check it out
java アルゴリズム 第1回 by stunning seo guys
FrontPage by check it out
にせScheme (07/02/01版) by awesome things!
Brainfu*k置き場 by awesome things!
sawa::memo by Cheap Canada Goose Jackets clearance sale & Winter Parka outlet shop
java GUI 第3回 by tips about seo
sawa::memo by watch for this

にせScheme (07/02/01版)

//////////////////////////////////////////////////////////
// ** nise-scheme **                                    //
// コマンドプロンプトから実行できます                   //
// cscript scheme.js で対話的実行                       //
// cscript scheme.js filename でスクリプト実行          //
// 適切なIOクラスを設定すればブラウザからも実行可能です //
//////////////////////////////////////////////////////////


///////////////////////////////////////
// スクリプトインタプリタの切り分け ///
///////////////////////////////////////
var browser;
try{
	WScript.Echo("WSH mode");

	// JScriptから実行
	browser = false;
}catch(e){
	// ブラウザから実行
	browser = true;
}



//////////////////
/// エラー関数 ///
//////////////////
function raise(msg){
	throw new Error(msg);
}



////////////////////////
/// 入出力関数の宣言 ///
////////////////////////
var p = null;
var putc = null;
var getc = null;



//////////////////
/// 数値クラス ///
//////////////////
function Num(v){
	this.val = v;
}
Num.prototype.toString = function (){
	return this.val.toString();
};
Num.prototype.eq = function(other){
	return (other.constructor == Num
		&& this.val == other.val) ? T: NIL;
};
Num.prototype.add = function(other){
	return num(this.val + other.val);
};
Num.prototype.sub = function(other){
	return num(this.val - other.val);
};
Num.prototype.cmp = function(other){
	var x = this.val - other.val;
	var ret = (x<0)  ?	-1:
		  	  (x==0) ?	 0:
						 1;
	return num(ret);
};
Num.prototype.car = function(){
	return num(this.val & 1);
};
Num.prototype.cdr = function(){
	return num(this.val >> 1);
};

function num(val){return new Num(val);}


////////////////////
/// 文字列クラス ///
////////////////////
function Str(v){
	this.val = v;
}
Str.prototype.toString = function(){
	return "\""+this.val+"\"";
};
Str.prototype.eq = function(other){
	return (other.constructor == Str && 
		this.val == other.val) ? T: NIL;
};
Str.prototype.add = function(other){
	return str(this.val + other.val);
};
Str.prototype.cmp = function(other){
	var ret;
	var x =0;
	var len = this.val.length<other.val.length?
		this.val.length: other.val.length;
	for(var i=0;i<len;i++){
		x = this.val.charCode(i) - other.val.charCodeAt(i);
		if(x!=0){
			if(x<0) ret = -1;
			else if(x==0) ret = 0;
			else ret = 1;
			return num(ret);
		}
	}
	var a = this.val.length<other.val.length;
	if(a<0) ret = -1;
	else if(a==0) ret = 0;
	else ret = 1;
	return num(ret);
};
Str.prototype.car = function(){
	if(this.val == "") return NIL;
	else return num(this.val.charCodeAt(0));
};
Str.prototype.cdr = function(){
	var len = this.val.length;
	if( len <= 1) return NIL;
	else return str(this.val.substring(1, len));
};

function str(val){return new Str(val);}



//////////////////////
/// シンボルクラス ///
//////////////////////
function Sym(v){
	this.val = v;
}
Sym.prototype.toString = function(){return this.val;};
Sym.prototype.eq = function(other){
	return (other.constructor == Sym && 
			this.val == other.val) ? T: NIL;
};
function sym(val){return new Sym(val);}



////////////////////
/// 真偽値クラス ///
////////////////////
function Bool(x){
	this.type = x;
}
Bool.prototype.toString = function(){return this.type;};
Bool.prototype.eq = function(other){
	return (this.constructor == other.constructor &&
			this.type == other.type)  ? T: NIL;
};
NIL = new Bool("NIL");
T = new Bool("T");
NIL.car = NIL.cdr = function(){return NIL;};




////////////////////////////////
/// 合成データ構造構築クラス ///
////////////////////////////////
// javaで書くとこんな
// class Cons{
//   private Object a,b;
//   Cons(Object _a, Object _b){a=_a;b=_b;}
//   Object car(){return a;}
//   Object cdr(){return b;}
// }
// //1,2,3,4,nullの線形リスト
// new Cons(1, new Cons(2, new Cons(3, new Cons(4, null))));  

function Cons(a, d){
	this._car = a;
	this._cdr = d;
}
Cons.prototype.eq = function(other){
	return	(other.constructor == Cons &&
			this._car.eq(other._car) == T &&
			this._cdr.eq(other._cdr) == T) ? T: NIL;
};
Cons.prototype.isList = function(){
	var temp = this;
	while(true){
		if(temp == NIL){
			return true;
		}else if(temp.constructor == Cons){
			temp = temp._cdr;
		}else{
			return false;
		}
	}
};
Cons.prototype.toString = function(){
	var temp = this;
	if(this.isList()){
		var str = "(";
		var temp = this;
		while(temp != NIL){
			str += temp._car.toString() + " ";
			temp = temp._cdr;
		}
		str = str.substring(0,str.length-1);
		return str + ")";
	}else{
		return "(" + this._car + "." + this._cdr + ")";
	}
};
Cons.prototype.car = function(){
	return this._car;
};
Cons.prototype.cdr = function(){
	return this._cdr;
};

function cons(a,b){return new Cons(a,b);}


/////////////////////////////////////////
/// Javascriptの配列に機能を追加      ///
/// (nise-schemeの配列に変換する機能) ///
/////////////////////////////////////////
Array.prototype.toList = function(){
	var foo = function (list,index){
		if(list.length == index){
			return NIL;
		}else{
			var e = list[index];
			if(e.constructor == Array) e = e.toList();
			return new Cons(e, foo(list, index+1));
		}
	};
	return foo(this, 0);
};

//////////////////
/// 字句解析器 ///
//////////////////
function Parser(){
	function Reader(_str){
		this.str = _str;
		this.index = 0;
		this.next = function (){
			var ret = this.str.charAt(this.index);
			this.index++;
			return ret;
		};
		this.back = function (){
			this.index--;
		};
		this.hasNext = function (){
			return 0<=this.index && this.index<this.str.length;
		};
	}

	function parse_int(reader){
		var str_int = "";
		while(reader.hasNext()){
			var ch = reader.next();
			if( !ch.match(/\d/ )){
				reader.back();
				break;
			}
			str_int += ch;
		}
		return num(str_int-0);
	}

	function parse_str(reader){
		var s = "";
		while(reader.hasNext()){
			var ch = reader.next();
			if( ch=="\"" ) break;
			s += ch;
		}
		return str(s);	
	}

	function parse_sym(reader){
		var s = "";
		while(reader.hasNext()){
			var ch = reader.next();
			if( ch.match(/[\s()#]/) ){
				reader.back();
				break;
			}
			s += ch;
		}
		return sym(s);	
	}

	function parse_ws(reader){
		while(reader.hasNext()){
			var ch = reader.next();
			if( !ch.match(/\s/) ){
				reader.back();
				break;
			}
		}
		return null;
	}

	function parse_comment(reader){
		while(reader.hasNext()){
			var ch = reader.next();
			if( ch == "\n"){
				break;
			}
		}
		return null;
	}

	function parse_quote(reader){
		var foo = _parse(reader);
		var first = foo.shift();
		p(""+first+"<==>"+foo);
		return [[sym("quote"), first], foo];
	}

	function _parse(reader){
		var ch = " ";
		var tree = new Array();
		while(reader.hasNext()){
			ch = reader.next();
			if(ch.match(/\s/)){
				parse_ws(reader);
			}else if(ch == "\""){
				tree.push(parse_str(reader));
			}else if(ch.match(/\d/)){
				reader.back();
				tree.push(parse_int(reader));
			}else if(ch == "("){
				tree.push(_parse(reader));
			}else if(ch == ")"){
				return tree;
			}else if(ch == "#"){
				parse_comment(reader);
			}else if(ch == "'"){
				return parse_quote(reader);
			}else{//symbol
				reader.back();
				tree.push(parse_sym(reader));
			}
		}
		return tree;
	}

	function parse(_str){
		return _parse(new Reader(_str)).toList();
	}
	Parser.prototype.parse = parse;
}

//////////////////////////////////////
/// 変数のスコープを管理するクラス ///
//////////////////////////////////////
function Scope(upper){
	this.db = new Array();
	this.superScope = upper;
}
Scope.prototype.define = function(sym_str, val){
	if(this.db["@"+sym_str]) raise(sym_str+" is already defined.");
	this.db["@"+sym_str] = val;
};
Scope.prototype.get = function(sym_str){
	var x = this.db["@"+sym_str];
	if(x) return x;
	
	if(this.superScope){
		return this.superScope.get(sym_str);
	}else{
		raise("Scope::get() symbol not found:["+sym_str+"]");
	}
};
Scope.prototype.update = function(sym_str, val){
	if( this.db["@"+sym_str] ){
		return this.db["@"+sym_str] = val;
	}else if(this.superScope){
		return this.superScope.update(sym_str, val);
	}else{
		raise("Scope::update() symbol not found:["+sym_str+"]");
	}
};
Scope.prototype.subScope =  function(){
	return new Scope(this);
};



//////////////////
/// 関数クラス ///
//////////////////
function Lambda(scope, args, body){
	this.args = args;
	this.body = body;
	this.scope = scope;
}
Lambda.prototype.toTree = function (){
	return cons(sym("lambda"),
			cons(this.args,
				cons(this.body, 
					NIL)));
};
Lambda.prototype.toString = function (){
	return this.toTree().toString();
};

Lambda.prototype._mapeval = function(scope, xs){
	if(xs == NIL) return NIL;
	return cons(_eval(scope, xs.car()), 
					this._mapeval(scope, xs.cdr()));
}
Lambda.prototype.call = function(scope, args){
	var evaled_args = this._mapeval(scope, args);
	var local_scope = this.scope.subScope();
	var names = this.args;
	var values = evaled_args;
	while(names != NIL && values != NIL){
		var name = names.car().val
		if(name.charAt(0) == "*"){
			local_scope.define(
				sym(name.substring(1,name.length)), values);
			break;
		}else{
			local_scope.define(names.car(), values.car());
			names = names.cdr();
			values = values.cdr();
		}
	}
	var ret;
	var b = this.body;

	while( b != NIL ){
		ret = _eval(local_scope, b.car());
		b = b.cdr();
	}
	return ret;
};



////////////////////
/// マクロクラス ///
////////////////////
function Macro(args, body){
	this.args = args;
	this.body = body;
}
Macro.prototype.toTree = function (){
	return cons(sym("macro"),
			cons(this.args,
				cons(this.body, 
					NIL)));
};
Macro.prototype.toString = function (){
	return this.toTree().toString();
};
Macro.prototype.call = function(scope, args){
	var local_scope = scope.subScope();
	var names = this.args;
	var bodys = args;
	
	while(bodys != NIL){
		var name = names.car().val
		if(name.charAt(0) == "*"){
			local_scope.define(
				sym(name.substring(1,name.length)), bodys);
			break;
		}else{
			local_scope.define(names.car(), bodys.car());
			bodys = bodys.cdr();
			names = names.cdr();
		}
	}
	var e = NIL;
	var bodies = this.body;

	while (bodies != NIL){
		e = _eval(local_scope, bodies.car());
		bodies = bodies.cdr();
	}
	p(e);
	return _eval(local_scope, e);
}

//////////////////////
/// 基本構文クラス ///
//////////////////////
function Syntax(name, proc){
	this.name = name;
	this.call = proc;
}
Syntax.prototype.toString = function (){return this.name;};
function syntax(name,proc){return new Syntax(name,proc);}




////////////////////
/// 組み込み関数 ///
////////////////////
function eval_eval(scope, args){
	return _eval(scope, _eval(scope, args.car()));
}

function eval_define(scope, args){
	var s = args.car();
	var v = _eval(scope, args.cdr().car());
	scope.define(s.val, v);
	return s;
}

function eval_update(scope, args){	
	var evaled = _eval(scope, args.cdr().car());
	scope.update(args.car().val, evaled);
	return evaled;
}

function eval_if(scope, args){
	var cond = args.car();
	var tcase = args.cdr().car();
	var fcase = args.cdr().cdr().car();
	if(_eval(scope, cond) != NIL){
		return _eval(scope,tcase);
	}else{
		return _eval(scope, fcase);
	}
}

function eval_lambda(scope, args){
	var f_args = args.car();
	var f_body = args.cdr();
	return new Lambda(scope.subScope(), f_args, f_body);
}

function eval_macro(scope, args){
	var f_args = args.car();
	var f_body = args.cdr();
	return new Macro(f_args, f_body);
}

function eval_cons(scope, args){
	return cons(_eval(scope, args.car()), 
		_eval(scope, args.cdr().car()));
}

function eval_car(scope, args){
	return _eval(scope, args.car()).car();
}

function eval_cdr(scope, args){
	return _eval(scope, args.car()).cdr();
}

function eval_eq(scope, args){
	var a1 = _eval(scope, args.car());
	var a2 = _eval(scope, args.cdr().car());
	var ret = a1.eq(a2);
	return ret;
}

function eval_cmp(scope, args){
	var a1 = _eval(scope, args.car());
	var a2 = _eval(scope, args.cdr().car());
	var x = a1.cmp(a2);
	return x;
}

function eval_add(scope, args){
	var a1 = _eval(scope, args.car());
	var a2 = _eval(scope, args.cdr().car());
	return a1.add(a2);
}

function eval_sub(scope, args){
	var a1 = _eval(scope, args.car());
	var a2 = _eval(scope, args.cdr().car());
	return a1.sub(a2);
}

function eval_quote(scope, args){
	return args.car();
}

function eval_typeof(scope, args){
	var e = _eval(scope, args.car()).constructor;
	switch(e){
	case Num: return str("num");
	case Str: return str("str");
	case Sym: return str("sym");
	case Lambda: return str("lambda");
	case Macro: return str("macro");
	case Bool: return str(e==NIL ? "NIL":"T");
	case Cons: return str("cons");
	case Syntax: return str("syntax");
	default: raise("typeof");
	}
}

function eval_while(scope, args){
	var cond = args.car();
	var bodies = args.cdr();
	var ret = NIL;
	while(_eval(scope, cond) != NIL){
		var ptr = bodies;
		while(ptr != NIL){
			ret = _eval(scope, ptr.car());
			ptr = ptr.cdr();
		}
	}
	return ret;
}

function eval_catch(scope, args){
	var ret = null;
	try{
		ret = _eval(scope, args.car());
	}catch(x){
		ret = x.ret_val;
	}
	return ret;
}
function eval_throw(scope, args){
	var e = new Error("<<throw object>>");
	e.ret_val = _eval(scope, args.car());
	throw e;
}
function eval_parse(scope, args){
	var src = _eval(scope, args.car());
	var ret = (new Parser()).parse(src.val);
	return ret;
}
function eval_setcar(scope, args){
	var c = _eval(scope, args.car());
	var x = _eval(scope, args.cdr().car());
	c._car = x;
	return x;
}

function eval_setcdr(scope, args){
	var c = _eval(scope, args.car());
	var x = _eval(scope, args.cdr().car());
	c._cdr = x;
	return x;
}
function eval_conv(scope, args){
	var val = _eval(scope, args.car());
	if ( val.constructor == Num)
		return String.fromCharCode(val.val);
	if ( val.constructor == Str)
		return val.val.charCodeAt(0);
	return NIL;
}

function eval_p(scope, args){
	var evaled = _eval(scope, args.car());
	p(evaled.toString());
	return evaled;
}
function eval_putc(scope, args){
	var evaled = _eval(scope, args.car());
	putc(evaled.val);
	return evaled;
}
function eval_getc(scope, args){
	var x = getc();
	return x==-1? NIL: num(x);
}


function _eval(scope, code){
	//p("EVAL::"+code);
	switch(code.constructor){
	case Num:	return code;
	case Str:	return code;
	case Bool:	return code;
	case Sym:	return scope.get(code.val);
	case Cons:
	{
		var func = code.car();
		var args = code.cdr();

		if (func.constructor == Sym){
			func = scope.get(func);
		}else if(func.constructor == Cons){
			func = _eval(scope, func);
		}
		
		switch(func.constructor) {
		case Lambda:
		case Macro:
		case Syntax:
			return func.call(scope, args);
		default:
			raise("not function:"+func+":"+func.constructor);
		}
	}
	default: 
		raise("_eval unknown object");
	}
}






////////////////////
/// 評価器クラス ///
////////////////////
function Evaluator(){
	var root = new Scope();
	this.root = root;
	root.define("T", T);
	root.define("NIL", NIL);
	root.define("eval",syntax("eval", eval_eval));
	root.define("define",syntax("define", eval_define));
	root.define("update",syntax("update", eval_update));
	root.define("if",syntax("if", eval_if));
	root.define("cons",syntax("cons", eval_cons));
	root.define("car",syntax("car", eval_car));
	root.define("cdr",syntax("cdr", eval_cdr));
	root.define("lambda",syntax("lambda", eval_lambda));
	root.define("macro",syntax("macro", eval_macro));
	root.define("eq",syntax("eq", eval_eq));
	root.define("cmp",syntax("cmp", eval_cmp));
	root.define("typeof",syntax("typeof", eval_typeof));
	root.define("p",syntax("p", eval_p));
	root.define("+",syntax("+", eval_add));
	root.define("-",syntax("-", eval_sub));
	root.define("quote",syntax("quote", eval_quote));
	root.define("getc",syntax("getc", eval_getc));
	root.define("putc",syntax("putc", eval_putc));
	root.define("while",syntax("while", eval_while));
	root.define("catch",syntax("catch", eval_catch));
	root.define("throw",syntax("throw", eval_throw));
	root.define("parse",syntax("parse", eval_parse));
	root.define("conv",syntax("conv", eval_conv));
	root.define("setcar",syntax("setcar", eval_setcar));
	root.define("setcdr",syntax("setcdr", eval_setcdr));

	this.eval = function(tree){
		return _eval(this.root, tree);
	};
}



////////////////////////
/// インタプリタ本体 ///
////////////////////////
function Interpriter(io){
	this.show_flag = false;
	if(!io) {
		this.io = new NOPIO();
	}
	this.set_io(io);

	this.parser = new Parser();
	this.evaluator = new Evaluator();
}

Interpriter.prototype.set_io = function(_io){
	this.io = _io;
	p = this.io.p;
	putc = this.io.putc;
	getc = this.io.getc;
};
Interpriter.prototype.eval_str = function(code){
	var src = this.parser.parse(code);
	var s;
	while(src != NIL){
		s = src.car();
		if(this.show_flag) p(">>>"+s);
		var v = this.evaluator.eval(s);
		p(v);
		src = src.cdr();
	}
};
//////////////////////////////
/// 標準ライブラリ PoorLib ///
//////////////////////////////
Interpriter.prototype.poor_lib = ""
	+"(define not (lambda (b) (if b NIL T)))\n"
	+"(define ne (lambda(a b) (not (eq a b))))\n"
	+"(define lt (lambda(a b) (eq (cmp a b) (- 0 1))))\n"
	+"(define gt (lambda(a b) (eq (cmp a b) 1)))\n"
	+"(define le (lambda(a b) (not (gt a b))))\n"
	+"(define ge (lambda(a b) (not (lt a b))))\n"

	+"(define *(lambda(a b)(if(eq a 0)0(+ b(*(- a 1)b)))))\n"
	+"(define /(lambda(a b)"
	+"	(if (lt a b) 0"
	+"		(+ 1 (/ (- a b) b)))))\n"
	+"(define % (lambda(a b)"
	+"	(if (lt a b) a"
	+"		(% (- a b) b))))\n"

	+"(define list (lambda (*args) args))\n"

	+"(define map (lambda (xs proc)\n"
	+"	(if (eq xs NIL) NIL\n"
	+"		(cons (proc (car xs))\n"
	+"			(map (cdr xs) proc)))))\n"

	+"(define let (macro (pairs body)\n"
	+"	(p (cons\n"
	+"		(list\n"
	+"			(quote lambda)\n"
	+"			(map pairs (lambda (e) (car e)))\n"
	+"			body)\n"
	+"		(map pairs (lambda (e) (car (cdr e)))))\n"
	+")))\n"

	+"(define reduce (lambda (xs init proc)\n"
	+"	(define loop (lambda (xs val)\n"
	+"		(if (eq xs NIL) val\n"
	+"			(loop (cdr xs) (proc val (car xs))))))\n"
	+"	(loop xs init)))\n"

	+"(define and (macro(a b)\n"
	+"	(list "
	+"		(quote if) a b NIL)))"

	+"(define or (macro (a b)\n"
	+"	(list "
	+"		(quote if) a T b)))"

	+"(define cond (macro (cs)\n"
	+"	(define loop (lambda (xs)\n"
	+"		(if (eq xs NIL) NIL\n"
	+"			(list \n" 
	+"				(quote if)\n"
	+"				(car (car xs))\n"
	+"				(car (cdr (car xs)))\n"
	+"				(loop (cdr xs))))))\n"
	+"	(loop cs)))\n"

	+"(define case (macro (val *branch)\n"
	+"	(define loop (lambda (bs)\n"
	+"		(if (not (eq (typeof (car bs)) \"cons\"))\n"
	+"			(car bs)\n"
	+"			(list \n"
	+"				(quote if)\n"
	+"				(list (quote eq) val (car (car bs)))\n"
	+"			(car (cdr (car bs)))\n"
	+"			(loop (cdr bs))))))\n"
	+"	(loop branch)))\n"

	+"(define reverse (lambda (foo)\n"
	+"	(define loop (lambda (xs val)\n"
	+"		(if (eq xs NIL) val\n"
	+"			(loop (cdr xs) (cons (car xs) val)))))\n"
	+"	(loop foo NIL)))\n"

	+"(define begin (macro (*args)\n"
	+"	(list (cons (quote lambda) (cons NIL args)))))\n"

	+"(define sort (lambda (xs)\n"
	+"	(define ins (lambda (xs x)\n"
	+"		(if (eq xs NIL) (cons x NIL)\n"
	+"			(if (lt x (car xs)) (cons x xs)\n"
	+"				(cons (car xs) (ins (cdr xs) x))))))\n"
	+"	(define _sort (lambda (xs val)\n"
	+"		(if (eq xs NIL) val\n"
	+"			(_sort (cdr xs) (ins val (car xs))))))\n"
	+"	(_sort xs NIL)))\n"

	+"	(define find (lambda (xs proc)\n"
	+"		(if (eq xs NIL) NIL\n"
	+"			(if (proc (car xs)) (cons (car xs) (find (cdr xs) proc))\n"
	+"				(find (cdr xs) proc)))))\n"

	;

////////////////////////////////
/// 何も入出力しないIOクラス ///
////////////////////////////////
function NOPIO(){
	this.putc = this.p = function (x){return x;};
	this.getc = function (){return -1;};
}

//////////////////////////
/// JScript用 IOクラス ///
//////////////////////////
function WScriptIO(){
	WScriptIO.prototype.p = function(x){
		WScript.StdOut.Write(x+"\n");
		return x;
	};
	WScriptIO.prototype.putc = function(n){
		WScript.StdOut.Write(String.fromCharCode(n));
		return n;
	};
	WScriptIO.prototype.getc = function(){
		if(WScript.StdIn.AtEndOfStream) return -1;
		return WScript.StdIn.Read(1).charCodeAt(0);
	};		
}
/////////////////////////
/// JScript用main関数 ///
/////////////////////////
function jscript_main(){
	// インタプリタ生成
	var interpriter = new Interpriter(new NOPIO());

	// 標準ライブラリ "PoorLib"の読み込み
	interpriter.eval_str(interpriter.poor_lib);

	// 入出力設定
	interpriter.set_io(new WScriptIO());

	// ファイルシステム
	var fso = WScript.CreateObject("Scripting.FileSystemObject");

	
	if(WScript.Arguments.Length == 0){
		// 対話的実行
		interpriter.show_flag = false;
		while(!WScript.AtEndOfLine){
			WScript.StdOut.Write(">>> ");
			var src = WScript.StdIn.ReadLine();
			var result = interpriter.eval_str(src);
		}
	}else{
		// ソースコードを一気に実行
		interpriter.show_flag = true;
		var fin = fso.GetFile(WScript.Arguments.Item(0)).OpenAsTextStream(1);
		var src = fin.ReadAll();
		interpriter.eval_str(src);
	}

}

if(!browser){
	jscript_main();
}

2007年02月01日(木) 23:10:24 Modified by mahalkita




スマートフォン版で見る