我尝试使用Flex&Bison解析一个原始字符串文本。但无法解析。
输入:
R"foo(Hello World)foo"挠曲:
...
raw_string R"([^\(]*)\(([^\)]*)\)\1"
%%
{raw_string} {return raw_string;}
%%野牛:
%{
...
%}
%token raw_string
%start run
%%
run : raw_string;
%%
int main()
{
yyin = stdin;
do
{
yyparse();
} while(!feof(yyin));
return =0;
}错误:
invalid Syntax: at raw_string请帮助我使用Flex和Bison解析原始字符串文本。如果不可能返回引用,那么在flex和bison中解析原始字符串是否有其他的方法。
发布于 2018-02-15 19:24:11
挠曲模式既没有反向引用,也没有非贪婪的匹配,为了正确识别带有“正则”表达式的原始字符串,您需要这两个匹配。注1
然而,flex确实有一个特性-- “启动条件” --这使得实现这些特性变得非常简单,至少在这种情况下,您不需要回溯就可以尝试不同的反引用子模式。
start条件是对给定的词法上下文使用不同规则集的一种方式;在本例中,是原始字符串中的上下文。
注释:原始代码有一个错误,如果原始字符串后面紧跟几个非空格字符和另一个双引号,则会导致它遗漏一个原始字符串的紧凑型序列。这是一个非常不可能的情况,这也许可以解释为什么没有人注意到这个错误。我把所有企图的聪明都移除了。向任何复制buggy代码的人道歉。
因此,(简化的) C++原始字符串的基本解决方案是:
%x C_RAW_STRING
dchar_seq [^()\\[:space:]]{0,16}
%%
size_t delim_len;
R["]{dchar_seq}[(] { delim_len = yyleng - 3;
yymore();
BEGIN(C_RAW_STRING);
}
R["]{dchar_seq} { yyerror("Invalid raw string opener"); }
/* Rules for other tokens omitted */
[[:space:]]+ ; /* Ignore whitespace */
. return *yytext; /* Fallback rule */
<C_RAW_STRING>{
[^"]+ yymore();
["] { if (yytext[yyleng - (delim_len + 2)] == ')' &&
memcmp(yytext + yyleng - (delim_len + 1),
yytext + 2, delim_len) == 0) {
BEGIN(INITIAL);
return STRING_LITERAL;
}
else yymore();
}
<<EOF>> { yyerror("Unterminated raw string");
BEGIN(INITIAL);
return 0;
}
}一些解释
C_RAW_STRING声明为独占条件。(见上面的flex手册,链接)。dchar_seq与C++标准所称的“d-char-序列”(参见lex.string,第5.13.5节)匹配:最多16个字符,除了括号、反斜杠或空格字符之外。(注意,"是一个d-char。)有关正则表达式运算符的详细信息,请参阅关于模式的Flex手册章节。yylext函数的顶部。因此,它们可以用于声明在一次调用yylex期间使用的局部变量。- Remember how long the delimiter string is. (Since we will leave the delimiter string at the beginning of the token, we don't need to copy it anywhere. It's sufficient to know how long it is.)
- Use `yymore()` to tell the lexer to append the next match to the current token, instead of starting a new token.
- Use `BEGIN` to change to the `C_RAW_STRING` start condition.R"和第5行的模式不匹配,那么原始字符串分隔符是不正确的,要么是因为它太长,要么是因为它包含一个无效的字符,或者因为它没有以(结尾。只匹配R"是可以的,但我也选择了匹配最长的d-char序列,以避免对lexer进行回溯,尽管在这种特殊情况下没有太大的区别。因为有了最长匹配规则,这个规则只有在前面的规则没有的情况下才会触发,所以很难从这样的错误中恢复过来,因为没有很好的方法可以知道引用的字符串将在哪里结束。在这里,我没有尝试错误恢复,因为这不是这个答案的重点。C_RAW_STRING启动条件启动一个规则块。这是一个flex扩展,在其他lex实现中是不可用的。为了兼容性,所有模式都必须单独使用<C_RAW_STRING>标记。yymore()表示我们还没有完成令牌。)在我们期望的位置,然后使用memcmp比较这两个分隔符序列。(我们使用memcmp而不是strcmp,因为我们比较的序列不是以NUL结尾的;它们是令牌的子字符串。strncmp可能是另一种可能性。)
如果分隔符字符串匹配,我们已经找到标记的结尾,我们可以返回它。在这种情况下,我们需要将开始条件重置为INITIAL,以便正常扫描下一个令牌。如果字符串不匹配,我们使用yymore()告诉yylex我们还没有完成标记,并继续寻找正确的分隔符。备注
-P选项启用PCRE regex特性),但由于它是一个简单的regex搜索而不是标记,它可能会产生假阳性(例如,注释中的原始字符串):
grep -Po‘“([^()\:space:]*)(.*)\1”https://stackoverflow.com/questions/48801027
复制相似问题