0

我目前正在开发一个小的 dsl,与 rabl 不同。我正在努力实施我的一项规则。在我们解决问题之前,我将解释一下我的语法/语法。在我的小语言中,您可以定义属性、对象/数组块或自定义块(这些都用于构建 json 对象/数组)。“自定义块”可以是包含我的标准表达式(属性、对象/数组块等)或一些 JavaScript 的块。这些表达式是这样写的——

-- An object block
object @model

    -- A property node
    property some, key(name="value")

    -- A custom node
    object custom_obj as 
        property some(name="key")
    end

    -- A custom script node
    property full_name as (u)
        // This is JavaScript
        return u.first_name + ' ' + u.last_name;
    end
end 

我遇到的问题是我的自定义脚本节点。我有一个真正难以定义的脚本令牌,以便 JISON 可以正确捕获块内的内容。在我的词法分析器中,我目前有...

# script_param is basically a regex to match "(some_ident)"
{script_param}  { this.begin('js'); return 'SCRIPT_PARAM'; }
<js>(.|\n|\r)*?"end" %{ 
    this.popState();
    yytext = yytext.substr(0, yyleng - 3).trim();
    return 'SCRIPT';
%}

该 SCRIPT 令牌基本上将匹配 (u) 之后直到(并包括)结束令牌(通常结束一个块)的任何内容。我真的不喜欢这个,因为我常用的块终止符(结束)实际上是脚本令牌的一部分,这对我来说完全是 hacky。不幸的是,我找不到更好的方法来捕捉 (..) 和结束之间的任何内容。我尝试编写一个正则表达式来捕获以“;”结尾的任何内容,但是当我的 dsl 代码中有多个脚本节点时会出现问题。我只能通过将“end”关键字作为捕获的一部分来完成这项工作。

这是我的语法词法分析器文件的链接。

对于解决我的问题的任何见解,我将不胜感激!如果我没有清楚地解释我的问题,请告诉我,我会尽力澄清!提前谢谢了!!

我也很乐意接受有关如何清理语法的任何建议。我对这些东西还很陌生,感觉我的东西现在一团糟:)

4

1 回答 1

1

匹配一个字符串很容易,但不包括第一个实例end

([^e]|e[^n]|en[^d])*

(而且它甚至不需要非贪婪的重复。)

然而,这不是你想要的。包含的 JavaScript 可能包括:

  • 名称恰好包含字符end( tendency)的变量

  • 评论 ( /* Take the values up to the end of the line */)

  • 字符串 ( if (word == "end"))

  • 而且,确实是这个词end本身,它不是 js 中的保留词。

真的,唯一干净的解决方案是能够使用 lex javascript。幸运的是,您不必精确地执行它,因为您没有解释它,但即便如此,它还是有点工作。与其他类似语言一样,javascript 词法分析最烦人的部分是识别/正则表达式何时开始,何时只是除法;要做到这一点需要大部分 javascript 解析器,特别是因为它还与分号规则交互。

为了处理包含的 javascript 可能实际上使用名为的变量这一事实,end据我所知,您有几个选择:

  1. end记录作为保留字的事实。

  2. 仅识别end它何时出现在括号之外以及语句可能开始的位置(如果您最终构建了足够多的 JS 解析器以正确识别正则表达式,这并不难)

  3. end只有当它单独出现在一条线上时才能识别。

最后一个选择确实会大大简化您的问题,因此您可能需要考虑一下,尽管它并不是很优雅。

于 2014-05-01T03:10:41.347 回答