2

我想为允许转义标记分隔符的标记语言创建 Jison (Bison) 语法。

这些将是有效的:

I like apples
I like [apples, oranges, pears]
I like [apples, oranges, pears] and [peanut butter, jelly]
I like [apples, oranges, pears] \[when they're in season\]
I like emoticons :-\]

这些示例可能会被解释为以下内容(以 JSON 表示):

["I like apples"]
["I like ", ["apples", "oranges", "pears"]]
["I like ", ["apples", "oranges", "pears"], " and ", ["peanut butter", "jelly"]]
["I like ", ["apples", "oranges", "pears"], " [when they're in season]"]
["I like emoticons :-]"]

转义[]\,是最少的,但允许任何可打印字符转义可能是有意义的,即使转义是不必要的。

如果不支持转义不可打印的字符,那就太好了。也就是说,\一行末尾的 a 是非法的。正则表达式可能会免费提供,.因为它可能不包含换行符,但它也应该发生在其他不可打印的字符上。

很难用谷歌搜索,因为它与 Bison 定义等中转义文字字符的大量结果混在一起。

在 Bison 定义的语言中支持转义字符的最优雅方法是什么?

编辑

这是我到目前为止所拥有的,可以在 Jison 上进行测试,但它不起作用(1如果有的话,只是返回)而且我不希望文本会原封不动地到达 - 这需要第二遍。这是可以避免的吗?

/* description: markup */

/* lexical grammar */
%lex
%%

(\\.|[^\\\[])+            return 'TOPTEXT'
(\\.|[^\\\[\]\,])+        return 'TEXT'
\-?[0-9]+("."[0-9]+)?\b   return 'NUMBER'
".."|"-"                  return '..'
"["                       return '['
"]"                       return ']'
","                       return ','
<<EOF>>                   return 'EOF'

/lex

%start markup

%%

markup
    : template EOF
        { return $template; }
    ;

template
    : template TOPTEXT
        { $$ = $template.push($TOPTEXT); }
    | template dynamic
        { $$ = $template.push($dynamic); }
    | /* empty */
        { $$ = []; }
    ;

dynamic
    : '[' phraselist ']'
        { $$ = $phraselist; }
    ;

phraselist
    : phraselist ',' phrase
        { $$ = $phraselist.push($phrase); }
    | /* empty */
        { $$ = []; }
    ;

phrase
    : TEXT
        { $$ = $phrase.push($TEXT); }
    | phrase dynamic
        { $$ = $phrase.push($dynamic); }
    | /* empty */
        { $$ = []; }
    ;
4

1 回答 1

2

我认为您的代码存在不止一个问题。

第一个(这解释了1输出)是[].push返回列表的新长度,所以你想要的可能是 push,然后定义值:

template
: template TOPTEXT
    { $template.push($TOPTEXT); $$ = $template; }
| template dynamic
    { $template.push($dynamic); $$ = $template; }
| /* empty */
    { $$ = []; }
;

另一件事是,你似乎试图让太多的事情同时工作,而没有真正确定你想要它们,或者它们实际上是以他们应该的方式工作。

也许一个更好的策略是让你从小处着手,让它在当时成为一条规则,从基础开始。

例如,您可以首先确保您的词法分析器适用于每种情况,使用仅打印出标记的简单语法进行测试:

%lex
%%

(\\\\|\\\[|\\\]|\\\,|[^,\\\[\]])+   return 'TEXT'
\-?[0-9]+("."[0-9]+)?\b             return 'NUMBER'
".."|"-"                            return 'RANGE'
"["                                 return '['
"]"                                 return ']'
","                                 return ','

/lex

%start lexertest

%%

lexertest:
token lexertest
| /* empty */
;

token:
TEXT    { console.log("Token TEXT: |" + $TEXT +  "|"); }
|
NUMBER  { console.log("Token NUMBER: |" + $NUMBER +  "|"); }
|
'['     { console.log("Token ["); }
|
']'     { console.log("Token ]"); }
|
','     { console.log("Token ,"); }
|
'RANGE' { console.log("Token RANGE: |" + $1 +  "|"); }
;

注意:在浏览器中运行时,console.log输出只会在开发者工具中。您可能会发现在命令行中使用 Jison 和这样的脚本(对于 Bash)可以更容易地通过多个输入进行测试。

然后你完善它,直到你满意为止。在您对词法分析器感到满意之后,您就开始使语法起作用,同时再次测试一条规则。保留上述规则,以便在您想要调试词法分析器的输出时,只需更改%start规则即可。

最后,您很可能会发现EOF一开始就不需要,而且也许您根本不需要两个不同的规则来匹配自由文本。

希望能帮助到你。

于 2012-09-25T14:05:21.697 回答