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
问题
您使用了
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; }
;