C# Antlr4语法问题(不完全解析)

C# Antlr4语法问题(不完全解析),c#,.net,parsing,antlr4,lexer,C#,.net,Parsing,Antlr4,Lexer,我是ANTLR的新手,我正在努力让这个语法正常工作: grammar TemplateGrammar; //Parser Rules start : block | statement | expression | parExpression | primary ; block : LBRACE statement* RBRACE ; statement : block | IF parExpression

我是ANTLR的新手,我正在努力让这个语法正常工作:

grammar TemplateGrammar;

//Parser Rules 

start
    : block
    | statement
    | expression
    | parExpression
    | primary
    ;

block
    : LBRACE statement* RBRACE
    ;

statement
    : block
    | IF parExpression statement (ELSE statement)?
    | expression
    ;

parExpression
    : LPAREN expression RPAREN
    ;

expression
    : primary #PRIMARY
    | number op=('*'|'/') number            #MULDIV
    | number op=('+'|'-') number            #ADDSUB
    | number op=('>='|'<='|'>'|'<') number  #GRLWOREQUALS
    | expression op=('='|'!=') expression   #EQDIFF
    ;

primary
    :   parExpression
    |   literal
    ;

literal
    :   number  #NumberLiteral
    |   string  #StringLiteral
    |   columnName #ColumnNameLiteral
    ;

number
    :   DecimalIntegerLiteral       #DecimalIntegerLiteral
    |   DecimalFloatingPointLiteral #FloatLiteral
    ;

string
    :   '"' StringChars? '"'
    ;

columnName
    :   '[' StringChars? ']'
    ;

// Lexer Rules

//Integers
 DecimalIntegerLiteral
    :   DecimalNumeral
    ;

 fragment
 DecimalNumeral
    :   '0'
    |   NonZeroDigit (Digits? | Underscores Digits)
    ;

 fragment
 Digits
    :   Digit (DigitOrUnderscore* Digit)?
    ;

 fragment
 Digit
    :   '0'
    |   NonZeroDigit
    ;

 fragment
 NonZeroDigit
    :   [1-9]
    ;

 fragment
 DigitOrUnderscore
    :   Digit
    |   '_'
    ;

 fragment
 Underscores
    :   '_'+
    ;

//Floating point
DecimalFloatingPointLiteral
    :   Digits '.' Digits? ExponentPart?
    |   '.' Digits ExponentPart?
    |   Digits ExponentPart
    |   Digits
    ;

fragment
ExponentPart
    :   ExponentIndicator SignedInteger
    ;

fragment
ExponentIndicator
    :   [eE]
    ;

fragment
SignedInteger
    :   Sign? Digits
    ;

fragment
Sign
    :   [+-]
    ;

//Strings

StringChars
    :   StringChar+
    ;

fragment
StringChar
    :   ~["\\]
    |   EscapeSequence
    ;

fragment
EscapeSequence
    :   '\\' [btnfr"'\\]
    ;

//Separators
LPAREN          : '(';
RPAREN          : ')';
LBRACE          : '{';
RBRACE          : '}';
LBRACK          : '[';
RBRACK          : ']';
COMMA           : ',';
DOT             : '.';

//Keywords
IF              : 'IF';
ELSE            : 'ELSE';
THEN            : 'THEN';

//Operators
PLUS            : '+';
MINUS           : '-';
MULTIPLY        : '*';
DIVIDE          : '/';
EQUALS          : '=';
DIFFERENT       : '!=';
GRTHAN          : '>';
GROREQUALS      : '>=';
LWTHAN          : '<';
LWOREQUALS      : '<=';
AND             : '&';
OR              : '|';

WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ -> skip ;
语法模板语法;
//解析器规则
开始
:块
|声明
|表情
|副表达
|初级的
;
块
:LBRACE语句*RBRACE
;
陈述
:块
|IF parExpression语句(ELSE语句)?
|表情
;
副表达
:LPAREN表达式RPAREN
;
表达
:primary#primary
|数字op=(“*”|“/”)数字#MULDIV
|数字op=(“+”|“-”)数字ADDSUB
|数字op=(“>=”|“|”跳过;

当我将
“Test”
放入输入时,它正在工作并返回字符串
“Test”


以下是我在输入中放入
“Test”
时在
IParseTree
中得到的结果:

“(start(语句(表达式(主(文本(字符串\“Test\”)))))))”


但是当我放置
[Test]
(它几乎与
的“Test”
相同,但使用大括号而不是引号)时,解析器无法识别标记。。。

这是我放置
[Tree]
时得到的
IParseTree

“(开始[测试])


与数字一样,它可以很好地识别诸如
1
123
12.5
等孤独的数字,但不能识别像
1+2
这样的表达式

你知道为什么解析器不能识别
列名
规则,但却能很好地处理
字符串
规则吗?

可能是因为“StringChar”的定义不正确,无法处理“]”

也许您希望将StringChar定义为:

fragment
StringChar
:   ~["\\\]]
|   EscapeSequence
;
如果这是我的语法,我会定义一个QuotedStringChar,就像您为引号字符串定义的那样,并将BracketStringChar定义为~[\]\\]以用于括号列名


欢迎在词汇级别调试语法,并为不同类型的字符串定义不同类型的“引号”。这非常常见。(您应该看到Ruby,可以在其中定义字符串开头的字符串引号,ick。)。

我最终通过以下方式实现了这一功能:

QuotedStringChars
    :   '"' ~[\"]+ '"'
    ;

BracketStringChars
    :   '[' ~[\]]+ ']'
    ;
在引号或括号之间输入任何字符。然后:

primary
    :   literal #PrimLiteral
    |   number  #PrimNumber
    ;

literal
    :   QuotedStringChars   #OneString
    |   BracketStringChars  #ColumnName
    |   number              #NUMBER
    ;

number
    :   DecimalIntegerLiteral       #DecimalIntegerLiteral
    |   DecimalFloatingPointLiteral #FloatLiteral
    ;
literal
规则有助于区分带引号的字符串、括号字符串和数字

primary
literal
规则中有一个重复的
number
,因为我需要在应用程序中为每个规则指定不同的行为

我在Ira Baxter的建议下成功地做到了这一点:)

希望这将帮助其他新手像我一样有一个更好的ANTLR 理解:)


我删除了片段
StringChar
EscapeSequence
,并将
StringChars
替换为:
[A-Za-z0-9]+
。它可以更好地识别列名,但不匹配只包含数字的字符串,如
“123”
。我将尝试您的解决方案:)很抱歉,您的解决方案不适用于字符串,如
“Test”
,也不适用于列名,如
[Test]
。:/因此,您同意我的评估,您需要在非字符串字符集中包含“]”。解释为什么你认为你需要在这个集合中有“[”。另外,解释为什么你必须把数字作为一个特例来输入;当然0-9被字符串接受的方式与a-Z完全相同。没有这些解释,我认为这对其他ANTLR新手没有帮助。好吧,如果输入是
[[Test]
它仍然会返回
Test
,所以这没关系。我真的不明白为什么我必须将数字作为一个特例来处理,但是当我测试
[123]
输入时,解析器无法识别
123
序列。将数字作为一个特例,它就像一个符咒。如果你没有得到“为什么”,你不明白你做了什么,需要花更多的时间在上面。在编程/调试时,如果你不太清楚你的解决方案为什么起作用,那么它可能真的不起作用,或者因为错误的原因起作用。我不打算为你调试语法,但我认为不需要为数字制定单独的规范nse。(这就是为什么我认为这个答案对其他ANTLR新手没有帮助的原因)。我从来没有说过我完全理解语法,只是说它在工作,而且我至少理解了StringChars中的转义部分。当我调试输入解析时,
[123]
它在
start()崩溃
使用
Antlr4.Runtime.NoViableAltException
我不明白为什么…我建议你把语法去掉,只剩下字符串部分,然后用它进行实验,直到找到有趣的地方。