C# Can';t使用ANTLR 3和C解析简单代码#

C# Can';t使用ANTLR 3和C解析简单代码#,c#,antlr,antlr3,C#,Antlr,Antlr3,考虑到格拉玛 grammar T; options { k=4; language=CSharp3; TokenLabelType=CommonToken; output=AST; ASTLabelType=CommonTree; } tokens { LPAREN = '('; RPAREN = ')'; LBRACK = '{'; RBRACK = '}'; } fragment ID : ('a'..'z'|'A'

考虑到格拉玛

grammar T;

options
{
    k=4;
  language=CSharp3;     
  TokenLabelType=CommonToken; 
  output=AST;   
  ASTLabelType=CommonTree;  
}

tokens 
{
  LPAREN = '(';
  RPAREN = ')';
  LBRACK = '{';
  RBRACK = '}';
}

fragment
ID  :   ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
WS : (' ' | '\t' | '\n' |'\r' )+ { $channel = Hidden; } ;

public program: CLASSDEF+ EOF!   ;

CLASSDEF: 'class' ID LBRACK
       RBRACK     ;
这将产生一个lexer和一个解析器,我使用它如下

using System;
using Antlr.Runtime;
using Antlr.Runtime.Tree;

namespace compiler
{
  internal class Program2
  {
    public static void Main(string[]arg)
    {
      ANTLRStringStream Input = new ANTLRStringStream(@"class foo 
{ 
}");
      TLexer lex = new TLexer(Input);
      Console.WriteLine("errors:" + lex.NumberOfSyntaxErrors);
      CommonTokenStream tokens = new CommonTokenStream(lex);
      TParser parser = new TParser(tokens);

      var parsed = parser.program();
      Console.WriteLine("errors: " + parser.NumberOfSyntaxErrors);
      CommonTree tree = parsed.Tree;


      Console.WriteLine("type:" + tree.Type);
      Console.WriteLine("text:" + tree.Text);
      Console.WriteLine("children:" +tree.ChildCount);
      Console.WriteLine(tree.ToString());
      Console.WriteLine(tree.ToStringTree());

      Console.ReadKey();
    }
  }
}
运行此代码时,我得到0个lex错误和1个parse错误

结果

errors:0
errors: 1
type:0
text:{
}
children:0
<error: {
}>
<error: {
}>
错误:0
错误:1
类型:0
正文:{
}
儿童:0
问题

  • 我原以为ANTLR应该给出智能错误信息,但我没能找出哪里出了问题

  • 我是否缺少改进错误消息的代码


  • 您使用了
    CLASSDEF
    一个lexer规则(换句话说:一个令牌),这是不正确的。当lexer遇到类似
    “class X”
    的输入时,它无法创建
    CLASSDEF
    标记,因为
    “class”
    “X”
    之间有一个空格(不,由于
    CLASSDEF
    是lexer规则,
    WS
    标记将无法帮助您)

    换句话说:将
    CLASSDEF
    改为解析器规则(并从
    ID
    中删除
    fragment
    ):

    现在,解析输入,如
    “class foo{}”
    将生成以下解析:


    如果您为关键字
    类定义了一个单独的标记,它会解决问题吗?只是一种预感,但我认为lexer把它和一个标识符混淆了,根据语法,这将是一个语法错误。我有同样的感觉,但看看其他gramars,我发现他们没有这样做。同样,将gramar改为“CLASSDEF:'class'WS-ID WS-LBRACK-RBRACK;”并没有改变任何东西。这非常有效!但是,我仍然需要更好地处理错误情况,例如解析字符串“class foo{”,我只知道如何打印,但这并没有多大帮助。告诉预期的字符如何?我从Console.WriteLine(tree.ToString())中得到了这条消息@CarloV.Dango,生成正确的错误消息本身就是一门艺术。ANTLR不能简单地打印它所期望的字符,因为它不需要是单个字符。但是,Java目标将为无效输入
    “类foo{”
    :“不匹配的输入”期望RBRACK产生一个更有意义的错误。CSharp3生成的错误消息不太具有描述性,这一点我无法帮助您。另请参见以下Wiki条目:
    grammar T;
    
    options
    {
      language=CSharp3;     
      output=AST; 
    }
    
    tokens 
    {
      CLASS  = 'class';
      LPAREN = '(';
      RPAREN = ')';
      LBRACK = '{';
      RBRACK = '}';
    }
    
    public program
     : class_def+ EOF!
     ;
    
    class_def
     : CLASS ID LBRACK RBRACK
     ;
    
    ID
     : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
     ;
    
    WS
     : (' ' | '\t' | '\n' |'\r' )+ { $channel = Hidden; } 
     ;