Bison 转义字符语法

Bison 转义字符语法,bison,flex-lexer,parser-generator,jison,Bison,Flex Lexer,Parser Generator,Jison,我想为允许转义标记分隔符的标记语言创建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 :-\] 这些示例可能被解释为以下内容(在JSO

我想为允许转义标记分隔符的标记语言创建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表示中):

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

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

谷歌很难做到这一点,因为它与许多转义野牛定义中的文字字符的结果混在一起,等等

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

编辑

这是我到目前为止所做的,但它不起作用(如果有任何问题,只返回
1
),我也不希望文本到达时没有经过scaped,这需要第二次通过。这是可以避免的吗

/* 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 */
        { $$ = []; }
    ;
/*说明:标记*/
/*词汇语法*/
%莱克斯
%%
(\\.\.[^\\[])+返回'TOPTEXT'
(\\.\[^\\[\]\,])+返回“TEXT”
\-?[0-9]+(“[0-9]+)?\b返回“编号”
“.”|“-“返回”…”
“[”返回“[”
“]”返回“]”
“,”返回“,”
返回“EOF”
/莱克斯
%开始标记
%%
加成
:模板EOF
{返回$template;}
;
模板
:模板TOPTEXT
{$$=$template.push($TOPTEXT);}
|模板动态
{$$=$template.push($dynamic);}
|/*空*/
{ $$ = []; }
;
动态
:“[”短语列表“]”
{$$=$phraselist;}
;
用语表
:短语列表“,”短语
{$$=$phraselist.push($phrase);}
|/*空*/
{ $$ = []; }
;
短语
:文本
{$$=$phrase.push($TEXT);}
|短语动态
{$$=$phrase.push($dynamic);}
|/*空*/
{ $$ = []; }
;

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

第一个(这解释了
1
输出)是
[]。push
返回列表的新长度,因此您可能需要的是push,然后定义值:

template
: template TOPTEXT
    { $template.push($TOPTEXT); $$ = $template; }
| template dynamic
    { $template.push($dynamic); $$ = $template; }
| /* empty */
    { $$ = []; }
;
另一件事是,你似乎在试图让太多的东西同时工作,而没有真正确定你想要它们,或者它们实际上是按照预期的方式工作的

也许更好的策略是从小事做起,从基础做起,一次只做一条规则

例如,您可以首先确保lexer适用于每种情况,使用一个简单的语法进行测试,该语法只打印出标记:

%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时,使用多个输入更容易测试

然后你对它进行优化,直到你满意为止。 当您对lexer感到满意后,就开始使语法正常工作,同时再次测试一条规则。保留上述规则,以便在您想要调试lexer的输出时,只需更改
%start
规则即可

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


希望能有帮助。

推得很好()!还有很好的建议,谢谢。但是我对逃逸字符的期望是什么呢?这可以由lexer来完成吗?或者我需要一个字符一个字符处理的语法吗?或者什么?@uosɐ是的,我认为逃逸是lexer的工作。如果我理解你所说的逃逸的意思,也就是说,去掉后面的字母根据标记值,您可能会得到类似以下内容的结果:
{yytext=yytext.replace(/\\\()/g,$1');return'TEXT';}
——对标记值应用字符串替换。@uosɐſ是的,这对lexier状态来说是一个很好的用途。:)关于两个规则的事情,问题是lexer可能会变得模棱两可,无法选择它应该使用什么规则来处理输入。我认为您有两个选择:在解析器中执行,为逗号创建正确的含义或者使用你发现的这种lexer状态机制,当它发现一个开括号时,开始一个单独的状态,然后为只接受该状态内部转义逗号的文本制定替代规则。哦,我忘记了你关于EOF的问题!所以,我认为EOF在极少数情况下是有用的,只有当你我真的很希望文件在那里结束。否则,只要让解析工作正常,它就会总是抱怨输入错误。这将使以后更容易更改解析器、扩展它或做其他事情。例如,假设你想在HTML中嵌入你的这门小语言,如果你的语法需要EOF,那么就更难做到。所以,我认为语法中的EOF只是其中之一,“只有在没有它的情况下才能使用”。太棒了!是的,我为两种文本模式做了状态处理。到目前为止效果很好。谢谢你所做的一切。
%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 +  "|"); }
;