C++ 如何解决ANTLR CPP14语法中的解析错误

C++ 如何解决ANTLR CPP14语法中的解析错误,c++,antlr,grammar,context-free-grammar,C++,Antlr,Grammar,Context Free Grammar,我正在使用下面的ANTLR语法来解析我的代码 但我在使用以下代码时遇到一个解析错误: TEST_F(TestClass, false_positive__N) { static constexpr char text[] = R"~~~(; ModuleID = 'a.cpp' source_filename = "a.cpp" define private i32 @"__ir_hidden#100007_&

我正在使用下面的ANTLR语法来解析我的代码

但我在使用以下代码时遇到一个解析错误:

TEST_F(TestClass, false_positive__N)
{
  static constexpr char text[] =
    R"~~~(; ModuleID = 'a.cpp'
            source_filename = "a.cpp"

   define private i32 @"__ir_hidden#100007_"(i32 %arg1) {
     ret i32 %arg1
   }

define i32 @main(i32 %arg1) {
   %1 = call i32 @"__ir_hidden#100007_"(i32 %arg1)
   ret i32 %1
}
)~~~";

 NameMock ns(text);
 ASSERT_EQ(std::string(text), ns.getSeed());
}
错误详细信息:

line 12:29 token recognition error at: '#1'
line 12:37 token recognition error at: '"(i32 %arg1)\n'
line 12:31 missing ';' at '00007_'
line 13:2 missing ';' at 'ret'
line 13:10 mismatched input '%' expecting {'alignas', '(', '[', '{', '=', ',', ';'}
line 14:0 missing ';' at '}'
line 15:0 mismatched input ')' expecting {'alignas', '(', '[', '{', '=', ',', ';'}
line 15:4 token recognition error at: '";\n'

解析器/词法分析器中需要进行哪些修改才能正确解析输入?非常感谢您在这方面的任何帮助。提前感谢。

每当某个输入没有被正确解析时,我首先显示输入生成的所有标记。如果你这样做,你可能会明白为什么事情会出错。另一种方法是删除大部分源代码,并逐渐向其中添加更多的代码行:在某一点上,解析器将失败,您就有了解决它的起点

因此,如果您转储输入正在创建的令牌,您将获得以下令牌:

Identifier`TEST\F`
左撇子`(`
标识符`TestClass`
逗号``
标识符“假阳性”`
右翼`)`
左括号`{`
静态`静态`
Constexpr`Constexpr`
Char`Char`
标识符`文本`
左括号`[`
右括号“]`
分配`=`
UserDefinedLiteral`R“~~~”(ModuleID='a.cpp'\n source\u filename=“a.cpp”\n\n定义私有i32@”\uuu-ir\u-hidden(i32%arg1){\n ret i32%arg1\n}\n\ndefine i32@main(i32%arg1){\n%1=call i32@\uu-ir\u-hidden`
指令“100007”(i32%arg1)`
...
您可以看到输入
R“~~(…)~~”
没有标记为
StringLiteral
。请注意,
StringLiteral
将永远不会被创建,因为在lexer语法的顶部有以下规则:

Literal:
整体式
|字符文字
|浮动文字
|StringLiteral
|布尔文字
|指针式
|用户定义文字;
导致没有创建任何
IntegerLiteral
UserDefinedLiteral
:它们都将成为
Literal
标记。最好将此
Literal
规则移到解析器中。我必须承认,在滚动lexer语法时,这有点混乱,并且修复了
R”~~(…)~~“
只会延迟另一个挥之不去的问题出现:)。我敢肯定这个语法从未经过正确测试,而且充满了bug

如果查看
StringLiteral
的lexer定义:

StringLiteral
:Encodingprefix?“'Schar*””
|编码前缀?'R'原始字符串
;
片段原始字符串
: '"' .*? '(' .*? ')' .*? '"'
;
很明显,为什么
'“.*?”(“.*?”)“.*?”
与整个字符串文字不匹配:

您需要的是如下所示的规则:

StringLiteral
:Encodingprefix?“'Schar*””
|编码前缀?'R'~[(]*'('('.*')'~[“]*'”
;
但是这会导致
(.)*
消耗太多:它会抓取每个字符,然后回溯到字符流中的最后一个引号(不是您想要的)

你真正想要的是:

StringLiteral
:Encodingprefix?“'Schar*””
|编码前缀“R”~[(]*'(“(/*当我们看到“)~~~-”`*/.)*'”)“~[”]*'”时中断此循环
;
当我们看到“')~~”部分时,可以使用如下方法来完成此外观的
中断:

lexer语法CPP14Lexer;
@成员{
私有布尔CloseDelimiterHead(字符串匹配){
//获取匹配文本的第一个引号和第一个“('.Prepend a')”之间的所有内容,并附加一个引号
字符串分隔符=“)”+matched.substring(matched.indexOf(“”)+1,matched.indexOf(“(”)+“\”;
StringBuilder ahead=新建StringBuilder();
//尽可能多地收集前面的“分隔符”-字符

对于(int n=1;n每当某个输入没有被正确解析时,我首先会显示该输入生成的所有标记。如果这样做,您可能会看到出现问题的原因。另一种方法是删除大部分源代码,并逐渐向其添加更多的代码行:在某一点上,解析器将失败,并且您有一个错误解决它的起点

因此,如果您转储输入正在创建的令牌,您将获得以下令牌:

Identifier`TEST\F`
左撇子`(`
标识符`TestClass`
逗号``
标识符“假阳性”`
右翼`)`
左括号`{`
静态`静态`
Constexpr`Constexpr`
Char`Char`
标识符`文本`
左括号`[`
右括号“]`
分配`=`
UserDefinedLiteral`R“~~~”(ModuleID='a.cpp'\n source\u filename=“a.cpp”\n\n定义私有i32@”\uuu-ir\u-hidden(i32%arg1){\n ret i32%arg1\n}\n\ndefine i32@main(i32%arg1){\n%1=call i32@\uu-ir\u-hidden`
指令“100007”(i32%arg1)`
...
您可以看到输入
R“~~(…)~~”
没有标记为
StringLiteral
。请注意,
StringLiteral
将永远不会被创建,因为在lexer语法的顶部有以下规则:

Literal:
整体式
|字符文字
|浮动文字
|StringLiteral
|布尔文字
|指针式
|用户定义文字;
导致没有创建任何
IntegerLiteral
UserDefinedLiteral
:它们都将成为
Literal
标记。最好将此
Literal
规则移到解析器中。我必须承认,在滚动lexer语法时,这有点混乱,并且修复了
R”~~(…)~~“
只会延迟另一个延迟的p
 Stringliteral
   : Encodingprefix? '"' Schar* '"'
   | Encodingprefix? '"' Schar* '" GST_TIME_FORMAT'
   | Encodingprefix? 'R' Rawstring
 ;

fragment Rawstring
 : '"'              // Match Opening Double Quote
   ( /* Handle Empty D_CHAR_SEQ without Predicates
        This should also work
        '(' .*? ')'
      */
     '(' ( ~')' | ')'+ ~'"' )* (')'+)

   | D_CHAR_SEQ
         /*  // Limit D_CHAR_SEQ to 16 characters
            { ( ( getText().length() - ( getText().indexOf("\"") + 1 ) ) <= 16 ) }?
         */
     '('
     /* From Spec :
        Any member of the source character set, except
        a right parenthesis ) followed by the initial D_CHAR_SEQUENCE
        ( which may be empty ) followed by a double quote ".

      - The following loop consumes characters until it matches the
        terminating sequence of characters for the RAW STRING
      - The options are mutually exclusive, so Only one will
        ever execute in each loop pass
      - Each Option will execute at least once.  The first option needs to
        match the ')' character even if the D_CHAR_SEQ is empty. The second
        option needs to match the closing \" to fall out of the loop. Each
        option will only consume at most 1 character
      */
     (   //  Consume everthing but the Double Quote
       ~'"'
     |   //  If text Does Not End with closing Delimiter, consume the Double Quote
       '"'
       {
            !getText().endsWith(
                 ")"
               + getText().substring( getText().indexOf( "\"" ) + 1
                                    , getText().indexOf( "(" )
                                    )
               + '\"'
             )
       }?
     )*
   )
   '"'              // Match Closing Double Quote

   /*
   // Strip Away R"D_CHAR_SEQ(...)D_CHAR_SEQ"
   //  Send D_CHAR_SEQ <TAB> ... to Parser
   {
     setText( getText().substring( getText().indexOf("\"") + 1
                                 , getText().indexOf("(")
                                 )
            + "\t"
            + getText().substring( getText().indexOf("(") + 1
                                 , getText().lastIndexOf(")")
                                 )
            );
   }
    */
 ;

 fragment D_CHAR_SEQ     // Should be limited to 16 characters
    : D_CHAR+
 ;
 fragment D_CHAR
      /*  Any member of the basic source character set except
          space, the left parenthesis (, the right parenthesis ),
          the backslash \, and the control characters representing
           horizontal tab, vertical tab, form feed, and newline.
      */
    : '\u0021'..'\u0023'
    | '\u0025'..'\u0027'
    | '\u002a'..'\u003f'
    | '\u0041'..'\u005b'
    | '\u005d'..'\u005f'
    | '\u0061'..'\u007e'
 ;