Giải pháp sau đây không chính xác những gì bạn đã yêu cầu nhưng tôi hy vọng rằng mặc dù không phải là câu trả lời C đơn giản, nó sẽ đáp ứng nhu cầu của bạn. Tái phát minh ra bánh xe không phải là một cách để đi vì vậy hãy sử dụng date.js trong C bằng cách chạy nó với SpiderMonkey, công cụ JavaScript của Mozilla.
Đây là cách tôi đã làm. Tôi đã bắt đầu tải xuống date.js và dịch nó thành một const char*
có tên là code
được xác định trong date.js.h
.
(\
echo 'const char *code =' ; \
curl https://datejs.googlecode.com/files/date.js | \
sed -e 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/\r\?$/\\n"/'; \
echo ';' \
) > date.js.h
Sau đó, tôi lấy JSAPI's Hello, World! làm điểm bắt đầu.
#include "jsapi.h"
#include "date.js.h"
static JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS };
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, const char *argv[]) {
JSRuntime *rt;
JSContext *cx;
JSObject *global;
rt = JS_NewRuntime(8L * 1024L * 1024L);
if (rt == NULL) return 1;
cx = JS_NewContext(rt, 8192);
if (cx == NULL) return 1;
JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
JS_SetVersion(cx, JSVERSION_LATEST);
JS_SetErrorReporter(cx, reportError);
global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
if (global == NULL) return 1;
if (!JS_InitStandardClasses(cx, global)) return 1;
/* Here's where the interesting stuff is starting to take place.
* Begin by evaluating sources of date.js */
jsval out;
if (!JS_EvaluateScript(cx, global, code, strlen(code), "code", 1, &out))
return 1;
/* Now create a call to Date.parse and evaluate it. The return value should
* be a timestamp of a given date. If no errors occur convert the timestamp
* to a double and print it. */
const int buflen = 1024;
char parse[buflen + 1];
snprintf(parse, buflen, "Date.parse(\"%s\").getTime();", argv[1]);
if (!JS_EvaluateScript(cx, global, parse, strlen(parse), "parse", 1, &out))
return 1;
double val;
JS_ValueToNumber(cx, out, &val);
printf("%i\n", (int) (val/1000));
/* Finally, clean everything up. */
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
JS_ShutDown();
return 0;
}
Đây là cách hoạt động trong thực tế.
$ time ./parse "week ago"
1331938800
0.01user 0.00system 0:00.02elapsed 92%CPU (0avgtext+0avgdata 6168maxresident)k
0inputs+0outputs (0major+1651minor)pagefaults 0swaps
$ time ./parse yesterday
1332457200
0.01user 0.00system 0:00.02elapsed 84%CPU (0avgtext+0avgdata 6168maxresident)k
0inputs+0outputs (0major+1653minor)pagefaults 0swaps
Như bạn có thể thấy nó khá nhanh và bạn có thể làm tăng đáng kể hiệu quả của nó bằng cách tái sử dụng bối cảnh ban đầu được tạo ra cho tất cả các cuộc gọi tiếp theo để Date.parse
.
Nói về các vấn đề cấp phép, date.js khả dụng theo các điều khoản của MIT và SpiderMonkey có sẵn theo MPL 1.1, GPL 2.0 hoặc LGPL 2.1. Việc liên kết nó tự động đáp ứng yêu cầu không phải GPL.
TL; DR:git clone https://gist.github.com/2180739.git && cd 2180739 && make && ./parse yesterday
Đối với những gì nó có giá trị, date.js được MIT cấp phép. Vì vậy, nếu mục tiêu ở đây là để có được một cái gì đó bạn có thể liên kết với mã độc quyền, bạn nên có thể sử dụng date.js như một điểm khởi đầu an toàn nếu bạn phải cuộn của riêng bạn. Mặc dù viết lại javascript-to-C có thể không phải là một bước đi trong công viên. –
Đó chính là lý do tại sao tôi hỏi câu hỏi này thay vì chỉ cần viết mã sau :-) –
Nếu bạn lo lắng về sự phức tạp của nguồn để viết trình phân tích cú pháp của riêng mình, bạn có thể sử dụng các công cụ lex/yacc không? – Jerry