[求助]Nodejs中有没有用 JS 做过语言的大侠, 怎样把 DSL 转化成代码?

发布于 1周前 作者 eggper 来自 nodejs/Nestjs

[求助]Nodejs中有没有用 JS 做过语言的大侠, 怎样把 DSL 转化成代码?

想模仿 LispyScript 做一门很简单的语言, 然后编译到 JS, http://lispyscript.com/ 我主要想去掉很多括号, 效果, 可能像下面这样吧, 已经在尝试写了 https://gist.github.com/3617971 不会用 Jison 也不熟悉 Paser AST, 现在的代码是模仿 LispyScript 的 https://github.com/jiyinyiyong/scirpus/blob/gh-pages/src/to_code.coffee 先解析成 token, 然后直接把下面这样的 token 按模版编译成代码: http://jiyinyiyong.github.com/scirpus/html/aray.html 但是这样生成的代码用 esprima 梳理的时候发现经常代码会出错, 不知道现在有什么好的办法… 求指点…


4 回复

当然可以!在 Node.js 中,你可以使用多种工具来将领域特定语言(DSL)转换为可执行代码。一个非常流行的选择是使用 nearleynearley-tree 来解析 DSL 并生成抽象语法树(AST),然后通过模板或自定义逻辑将其转换为 JavaScript 代码。

示例

假设我们有一个简单的 DSL,它类似于 Lisp,但去掉了括号:

add 2 3

这应该被转换为:

function add(a, b) {
    return a + b;
}

步骤 1: 安装必要的库

首先,你需要安装 nearleynearley-tree

npm install nearley nearley-tree

步骤 2: 创建 Nearley 语法文件

创建一个名为 dsl.ne 的文件,定义 DSL 的语法:

@start = expression

expression
    -> "add" number "and" number { result = { type: "add", left: $number0, right: $number1 } }
    | number { result = $number }

number
    -> /[0-9]+/

步骤 3: 解析并生成 AST

创建一个 JavaScript 文件来解析 DSL 并生成 AST:

const nearley = require('nearley');
const grammar = require('./dsl.ne');
const Parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));

function parseDSL(dsl) {
    try {
        Parser.feed(dsl);
        const ast = Parser.results[0];
        return ast;
    } catch (e) {
        console.error(`Parse error: ${e.message}`);
        return null;
    }
}

const dsl = 'add 2 and 3';
const ast = parseDSL(dsl);
console.log(ast); // 输出: { type: 'add', left: '2', right: '3' }

步骤 4: 将 AST 转换为 JavaScript 代码

接下来,我们需要将 AST 转换为 JavaScript 代码:

function generateJS(ast) {
    if (ast.type === 'add') {
        return `function add(${ast.left}, ${ast.right}) { return ${ast.left} + ${ast.right}; }`;
    } else {
        return `return ${ast};`;
    }
}

const jsCode = generateJS(ast);
console.log(jsCode); // 输出: function add(2, 3) { return 2 + 3; }

总结

以上步骤展示了如何使用 nearley 来解析 DSL 并生成 AST,然后通过简单的模板或自定义逻辑将其转换为 JavaScript 代码。这种方式提供了很大的灵活性,并且可以通过调整语法文件来支持更复杂的 DSL 规则。

希望这对你的项目有所帮助!


去掉括号之类的我觉得很coffee,javascript难看就在很多回调函数. 嘿嘿,你可以考虑加个关键字之后编译出来时异步回调的^ ^

操作 AST 我还不会啊, 瞟过 Mozilla 上的文档… 太难懂了… 我觉得所有 (跨行 or 行尾连续) 的括号都很难看, 这在 coffee 里也有点

你可以使用一种叫做解析器生成器(Parser Generator)的工具来帮助你将DSL转换为代码。一个常见的选择是使用JisonJison是一个JavaScript解析器生成器,它可以基于BNF(Backus-Naur Form)或Yacc文法生成解析器。

下面我会提供一个简单的例子,演示如何使用Jison将DSL转换为JS代码。假设我们定义了一种DSL语言,它简化了函数调用语法:

DSL语法

add 1 2
subtract 3 4

这些DSL语句应该被转换为等价的JavaScript代码:

add(1, 2);
subtract(3, 4);

安装Jison

首先需要安装jison库,可以通过npm来安装:

npm install jison --save

创建Jison文件

创建一个名为dsl.jison的文件,并定义文法规则:

/* dsl.jison */
%lex

%%

[\t\n\r ]+                   {/* skip whitespace */}
"add"                        {return 'ADD';}
"subtract"                   {return 'SUBTRACT';}
[0-9]+                       {return 'NUMBER', yytext;}
<<EOF>>                      {return 'EOF';}

/lex

%start script

%%

script
    : stmt EOF
        {$$ = $1; }
    ;

stmt
    : ADD NUMBER NUMBER
        { $$ = `add(${$2}, ${$3});`; }
    | SUBTRACT NUMBER NUMBER
        { $$ = `subtract(${$2}, ${$3});`; }
    ;

编写转换逻辑

接下来,在你的Node.js项目中编写代码来使用Jison编译并执行这个DSL:

const fs = require('fs');
const jison = require('jison');

const grammar = fs.readFileSync('./dsl.jison', 'utf8');
const parser = new jison.Generator(grammar);

// 解析并生成JavaScript代码
const input = 'add 1 2';
const result = parser.parse(input);
console.log(result); // 输出: add(1, 2);

通过这种方法,你可以使用Jison定义一个DSL的文法,然后将其转换为相应的JavaScript代码。如果你对更复杂的AST处理感兴趣,可以进一步学习如何处理和优化AST树。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!