iT邦幫忙

DAY 24
3

Javascript面面觀系列 第 24

Javascript面面觀:應用篇《SpiderMonkey》

  • 分享至 

  • xImage
  •  

SpiderMonkey是個歷史悠久的Javascript引擎,有不少應用的實例。以下就介紹一下一些應用,及簡單地使用C來嵌入SpiderMonkey。

應用列表
Mozilla網站上有提供一份應用的列表:

https://developer.mozilla.org/En/SpiderMonkey/FOSS

這裡面包涵了一些程式語言的支援例如C++、OCaml、Python等,還有一個可以C程式碼產生器,用來將javascript函數與C語言函數橋接。另外有一些應用及延伸的計畫,包括在GNOME及wxWidgets環境中使用Javascript,以及一些功能延伸。

Wikipedia也有一些介紹:

http://en.wikipedia.org/wiki/SpiderMonkey_(JavaScript_engine)#Usage

重要的應用像是在一些遊戲環境中作為模組開發語言、adobe用在acrobat reader、Flash Media Server、JSFL等。
JSLibs
在語言延伸中,我對這個比較有興趣:

http://code.google.com/p/jslibs/

JSLibs是一個已經非常成熟的專案,可以透過他在Console中執行Javascript,而且他提供了許多函數與模組的支援,例如:

* zlib 壓縮
* SQLite 資料庫
* FastCGI CGI介面,可以提供網頁程式處理的服務
* NSPR (Netscape Portable Runtime) 平台中立的函式庫
* ODE (Open Dynamics Engine) 動態模擬
* libpng, libjpeg, librsvg 圖形、影像處理轉換
* SDL 動畫函式庫(類似DirectDraw)
* libiconv 文字編碼轉換
* OpenGL, OpenAL 3D動畫、3D音效
* ogg vorbis 音樂
* libTomCrypt 加解密
* libffi 呼叫外部程式(例如dll中的函數)

另外,他也有處理binary格式、Buffer、執行緒、檔案及Socket I/O等等功能,非常強大,這應該是擴充SpiderMonkey的功能中最完整的方案了。

使用SpiderMonkey
接下來嘗試一下怎樣簡單地把SpiderMonkey整合到Console環境下執行的C語言程式,其實是以前作練習的例子,使用DEV-C++配合MINGW來編譯。在這之前,要先編譯好SpiderMonkey,並設定好include及lib目錄,並且設定好Linker要去Link的lib檔。(可以透過DEV-C++的Project設定來做)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jsapi.h"
 
JSClass global_class = {
    "global", 0,
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
};

JSBool js_print(JSContext *, JSObject *, uintN , jsval *, jsval *);

JSFunctionSpec myjs_global_functions[] = {
	JS_FS("print",js_print,1,0,0),
	JS_FS_END
};

globalfunc.h(定義了一個陽春的global物件結構,以及一個print函數,會加到global物件中)

#include "globalfunc.h"

JSBool js_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	if(argc>0) {
		JSString *msg;
		msg = JS_ValueToString(cx, argv[0]);
		printf("%s",JS_GetStringBytes(msg));
		return JS_TRUE;
	}else{
		return JS_FALSE;
	}
}

globalfunc.c(print函數實作)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jsapi.h"

extern JSClass global_class;

extern JSBool js_print(JSContext *, JSObject *, uintN, jsval *, jsval *);

extern JSFunctionSpec myjs_global_functions[];

main.h(宣告)

#include "main.h"

void reportError(JSContext *cx, const char *message, JSErrorReport *report)  
{  
    fprintf(stderr, "%s:%u:%s\n",  
            report->filename ? report->filename : "<no filename>",  
            (unsigned int) report->lineno,  
            message);  
}  

int main(int argc, char* argv[])
{
	if(argc<2) {
		fputs("you must pass script filename as 1st argument.", stderr);
		return 1;
	}
	JSRuntime *rt;
	JSContext *cx;
	JSObject *global;
	char *filename = (char*) argv[1];
	FILE *myFile;
	JSBool ok;
	myFile = fopen(filename, "r");
	if (myFile == NULL) {
		perror("Error!");
		return 1;
	}
	rt = JS_NewRuntime(8L * 1024L * 1024L);
	if (rt == NULL) {
		fputs("Error!: runtime starting failed.\n", stderr);
		return 1;
	}
	cx = JS_NewContext(rt, 8192);
	if (cx == NULL) {
		fputs("Error!: context starting failed.\n", stderr);
		return 1;
	}
	JS_SetOptions(cx, JSOPTION_VAROBJFIX);
	JS_SetVersion(cx, JSVERSION_1_5);
	JS_SetErrorReporter(cx, reportError);
	global = JS_NewObject(cx, &global_class, NULL, NULL);
	if (global == NULL) {
		fputs("Error!: global object creating failed.\n", stderr);
		return 1;
	}
	if (!JS_InitStandardClasses(cx, global)) {
		fputs("Error!: global object init failed.\n", stderr);
		return 1;
	}
	if (!JS_DefineFunctions(cx,global,myjs_global_functions)) {
		fputs("Error!: customized global functions loading failed.\n", stderr);
		return 1;
	}
	char* script;
	int iSize;
	size_t size_r;
	jsval rval;
	long lineno = 1;
	fseek(myFile,0,SEEK_END);
	iSize = ftell(myFile);
	rewind(myFile);
	script = (char*) malloc(sizeof(char)*iSize);
	if(script==NULL) {
		printf("Memory Error\n");
		fclose(myFile);
		JS_DestroyContext(cx);
		JS_DestroyRuntime(rt);
		JS_ShutDown();
		return 1;
	}
	size_r = fread(script,sizeof(char),iSize,myFile);
	ok = JS_EvaluateScript(cx, global, script, size_r, filename, lineno, &rval);
	fclose(myFile);
	free(script);
	JS_DestroyContext(cx);
	JS_DestroyRuntime(rt);
	JS_ShutDown();
	return 0;
}

main.c(主程式)

其實從main.c就可以看出,關鍵的幾個東西就是JSAPI的JSRuntime、JSContext、JSObject,先建立runtime環境,然後建立context,然後加入global物件,最後把print函數加到global物件中。接下來從程式參數讀入要執行的Javascript檔案名稱,讀取檔案內容字串,最後使用JS_EvaluateScript函數來執行這個程式。Javascript檔案裡面用到print()函數時,就會輸出訊息到console。基本的結構其實主要就是這幾個物件/函數做出來的。

接下來用javascript檔案測試一下:

function pyth(x,y) {
	return sqrt(x*x+y*y);
}
function sqrt(x) {
	return x*x;
}
print(pyth(2,3)+"\n");
print("我踏月色而來。\n");

執行完會顯示:

169
我踏月色而來。

更詳細的使用,還是要參考SpiderMonkey的文件,包括一些教學文件、指引、範例還有API文件等等,都可以在http://www.mozilla.org/js/spidermonkey/以及https://developer.mozilla.org/en/SpiderMonkey找到。


上一篇
Javascript面面觀:應用篇《Javascript引擎》
下一篇
Javascript面面觀:應用篇《Rhino》
系列文
Javascript面面觀30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
0
fillano
iT邦超人 1 級 ‧ 2009-11-05 09:54:56

因為貼程式,內文太長,把他移到前面去...:(

0
iverson2100
iT邦新手 5 級 ‧ 2012-02-12 22:27:55

您好,我目前正照著你的 source code 在 ubuntu 上 compile ,不過似乎一直無法成功?!我用的是 spidermonkey 1.8.5
不知道是否能請你幫我解惑!我卡在這一段一直錯誤!

JSBool js_print(JSContext *cx, uintN argc, jsval *argv)
{
if(argc>0) {
JSString *msg;
msg = JS_ValueToString(cx, argv[0]);
printf("%s",JS_EncodeString(cx, msg));
return JS_TRUE;
}else{
return JS_FALSE;
}
}

錯誤訊息是 Segmentation fault
然後錯誤一直卡在這一行:msg = JS_ValueToString(cx, argv[0]);
似乎是這個值有錯:argv[0]

fillano iT邦超人 1 級 ‧ 2012-02-13 09:35:12 檢舉

誒...這是三年多前的東西...我要再重建編譯環境才能模擬了XD

0
iverson2100
iT邦新手 5 級 ‧ 2012-02-13 10:49:26

我好像總是卡在某些api function 執行不正確!
例如:
if (!JS_EvaluateScript(context, JS_GetGlobalObject(context), script, strlen(script), "script", 1, &rval))
return EXIT_FAILURE;

cout << "JSVAL_IS_INT(rval): " << JSVAL_IS_INT(rval) << endl;
cout << "JSVAL_TO_INT(rval): " << JSVAL_TO_INT(rval) << endl;

script = "var x=10; x*x;"

那 JSVAL_TO_INT(rval) 應該要等於 100, 可是 output 是 201 ~"~

我要留言

立即登入留言