语法识别无限制' {' expr'}'彼此相邻

时间:2015-09-25 20:26:27

标签: c# antlr grammar antrl4

我正在使用ANTLR4编写一个C#应用程序来识别以下TeX' ish样式:

  

{A} {X} + {B} {Y} + {C}

我目前的语法总是采用' {' expr'}' 然后忽略字符串的开头。以下是当前语法的一些输出结果(如下所述):

  • 输入: {a} 输出: a [通过]
  • 输入: {a} + {x} 输出: a + x [通过]
  • 输入: {a} {x} 输出: x [失败] 所需: ax
  • 输入: {a} {x} + {b} 输出: x + b [失败] 渴望: ax + b
  • 输入: {a} {x} + {b} {y} 输出: y [失败] 渴望: ax + by
  • 输入: {a} {x} + {b} {y} + {c} 输出: y + c [失败] 期望: ax + by + c
  • 输入: {a} {x} + {b} {y} + {c} {d} 输出: d < strong> [失败] 渴望: ax + by + cd

有关如何解决此问题的任何想法?

语法MyGra.g4文件:

/*
 * Parser Rules
 */
prog: expr+ ;

expr : '{' expr '}'                 # CB_Expr
     | expr op=('+'|'-') expr       # AddSub
     | '{' ID '}'                   # CB_ID
     | ID                           # ID
     ;

/*
 * Lexer Rules
 */
ID: ('a' .. 'z' | 'A' .. 'Z')+;
ADD : '+';
SUB : '-';
WS:   (' ' | '\r' | '\n') -> channel(HIDDEN);

MyGraVisitor.CS文件:

 public override string VisitID(MyGraParser.IDContext context)
 {
      return context.ID().GetText();
 }

 public override string VisitAddSub(MyGraParser.AddSubContext context)
 {
     if (context.op.Type == MyGraParser.ADD)
     {
         return Visit(context.expr(0)) + " + " + Visit(context.expr(1));
     }
     else
     {
         return Visit(context.expr(0)) + " - " + Visit(context.expr(1));
     }
 }

 public override string VisitCB_Expr(MyGraParser.CB_ExprContext context)
 {
     return Visit(context.expr());
 }

 public override string VisitCB_ID(MyGraParser.CB_IDContext context)
 {
     return context.ID().GetText();
 }

更新#1:

建议包含

的语法规则
'{' expr '}{' expr '}'

然而,如果我有 {a} {b} {c} {d} + {e} {f} {g} ,我认为语法应该考虑递归版本&#34;本身&#34;通过解析树...所以,如果我在彼此旁边有1000个{expr},该怎么办?那我需要多少规则?我认为这个建议是有效的,但我不知道如何在彼此旁边占用无限量的{expr}?

我的另一个问题是:如何重新使用规则 CB_Expr

更新#2:

我添加了规则:

| expr CB_Expr                  # CB_Expr2

访客:

public override string VisitCB_Expr2(MyGra.CB_Expr2Context context)
{
    return Visit(context.expr()) + Visit(context.CB_Expr());
}

这没有帮助,我仍然得到所有情况的相同输出(如上所述)。

1 个答案:

答案 0 :(得分:1)

你的语法很暧昧。例如:输入{x}可以有两个不同的解析树(正如Mephy所说):

  

(CB_Expr {(expr(ID x))})

  

(DB_ID {x})

删除CB_ID可以解决这个问题,而不会做任何负面的事情。

对于你的实际问题,这应该是expr的技巧:

expr : left=id_expr op=('+' |'-') right=expr #AddSub
     | id_expr                               #ID_Expr
     ;

id_expr :
     | '{' ID '}' id_expr                    #ID_Ex
     | '{' ID '}'                            #ID
     ;

我没有测试过这个,我没有写过任何访问者,但语法应该有效。

id_expr规则以递归方式工作,因此您应该能够根据需要在彼此之后放置尽可能多的{ID} - 至少有一个,即语法现在的方式。