【问题标题】:ANTLR "no viable alternative at input" Error for parsing SAS code If Then ElseANTLR“输入时没有可行的替代方案”解析 SAS 代码的错误 If Then Else
【发布时间】:2018-02-01 11:39:33
【问题描述】:

我是 ANTLR 的新手,正在开发一个解析器来解析 SAS 代码,该代码主要由 if then else if 语句组成。我创建了以下语法来解析代码,但是当我尝试使用示例应用程序运行时,Intellij 出现错误。

语法创建:

grammar SASDTModel;

parse
 : if_block+
 | score_block
 ;

//Model
// : If_block+
// | Score_block
// ;

if_block
 : (if_statement|if_in_block)
 | else_if_statement+
 | else_statement
 ;

if_statement
 : IF '(' if_condition ')' THEN Identifier'='Value ';'
 | IF Identifier'='Value THEN Identifier'='Value ';'
 ;
else_if_statement
 : ELSEIF '(' if_condition ')' THEN Identifier'='Value ';'
 | ELSEIF Identifier'='Value THEN Identifier'='Value ';'
 ;

if_condition
 : Value ComparisionOperators Identifier ComparisionOperators Value
 | Value ComparisionOperators Value;


else_statement
 : ELSE Identifier'='Value ';'
 ;

if_in_block
 : IF Identifier IN '(' StringArray ')' THEN Identifier'='Value ';'
 ;

score_block
 : Identifier'='Arithmetic_expression ';'
 ;

Arithmetic_expression:
 | ( ArithmeticOperators '(' Value ')' )+
 | ( ArithmeticOperators '(' Value ArithmeticOperators Identifier ')' )+
 ;
WS : ( ' ' | '\t' | '\r' | '\n' )-> channel(HIDDEN);
//WS : [ \t\n\r]+ -> channel(HIDDEN) ;
//WS : (' ' | '\t')+ -> channel(HIDDEN);
//COMMENT    :   '/*' .*? '*/'    -> skip ;
//LINE_COMMENT    :   '*' ~[\r\n]* -> skip ;

ArithmeticOperators:
 | '+'
 | '-'
 | '*'
 | '/'
 | '**'
 ;

ComparisionOperators
 : '=='
 | '<'
 | '>'
 | '<='
 | '>='
 ;

IF: 'IF' | 'if' ;
ELSE: 'ELSE' | 'else' ;
ELSEIF: 'ELSE IF' | 'else if' ;
THEN: 'THEN' | 'then';
IN: 'IN' | 'in';


Value : INT
 | DOUBLE
 | '-'DOUBLE
 | '-'INT
 | Identifier
 |'null';


INT : [0-9];
DOUBLE : INT+ PT INT+
    | PT INT+
    | INT+
    ;
PT  : '.';

Identifier  : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*  ;

StringArray : (('\'')(Value)('\''))+; 

输入

if  scored = null then  scored = -0.05;
else if ( 0 <  scored <= 300 ) then scored = -0.5;
else if ( 300 < scored <= 500 ) then scored = -0.4;
else if ( 500 < scored <= 800 ) then scored = -0.8;
else if ( 800 < scored <= 1000 ) then  scored =  0.9;
else if ( scored > 1000 ) then  scored =  1.735409628;
else scored = 0;

错误我得到了

line 1:4 no viable alternative at input 'IF  scored'
line 1:61 mismatched input '<=' expecting ')'
line 1:112 mismatched input '<=' expecting ')'
line 1:163 mismatched input '<=' expecting ')'
line 1:214 mismatched input '<=' expecting ')'
line 1:276 mismatched input 'scored' expecting Identifier
line 1:303 mismatched input 'scored' expecting Identifier

所有错误代码都是 1:因为我正在预处理 SAS 代码并删除任何 cmets 并转换为单行。

所以在预处理后输入被转换为以下内容:`

IF 得分 = null THEN 得分 = -0.05;ELSE IF ( 0 1000) THEN 得分 = 1.735409628;否则得分 = 0;

`

【问题讨论】:

  • 可能缺少括号? if (scored = null) ...
  • 我对没有括号的场景有第二条规则,所以我认为它仍然应该能够匹配它。 IF Identifier'='Value THEN Identifier'='Value ';' 如果我的理解有误,请纠正我。
  • 嗯。你是对的。但也许试试看你是否得到不同的行为。
  • 所以在我添加括号后,错误确实更改为 line 1:27 mismatched input 'scored' Expecting Identifier 虽然仍然对新错误感到困惑。
  • 这意味着解析器无法识别您的 if_statement 中的第二种选择。我对 ANTLR 不够熟悉,无法为您提供帮助。但是您现在可能对如何逐步完成一些想法。

标签: java parsing sas antlr4 parser-generator


【解决方案1】:

以下是一些可能导致问题的因素:

  • 通过将StringArray : (('\'')(Value)('\''))+; 设为词法分析器规则,您将只匹配'foo123mu'(没有空格的值)。您应该将StringArray 设为解析器规则(然后Value 也应成为解析器规则)
  • 您的else If 规则:ELSEIF: 'ELSE IF' | 'else if' ; 相当脆弱:只要ELSEIF 之间有2 个或更多空格,您的规则将不匹配。您应该删除此规则,并在解析器规则中使用现有的 ELSEIF 规则
  • 规则ArithmeticOperatorsArithmetic_expression 匹配空字符串。词法分析器规则绝不能匹配空字符串(杠杆可以产生无限数量的空字符串标记)
  • 杠杆规则Arithmetic_expression 应该是解析器规则:每当杠杆规则用于将其他标记“粘合”到彼此时,您应该将它们“提升”到解析器规则
  • 您的词法分析器规则的命名约定不一致:使用PascalCasseUPPER_CASE,不能同时使用
  • 如前所述,INT : [0-9]; 应该是 INT : [0-9]+; 否则 4 将被标记为 INT42 作为 DOUBLE

这些只是我在阅读您的问题时看到的一些内容,因此可能还有更多不正确的地方。我建议您在尝试编写 SAS 语法之前先花时间学习更多 ANTLR。或者,更好的是,尝试找到该语言的现有 (ANTLR) 语法,而不是自己编写。

这是一个你可以看看的现有的:https://github.com/xueqilsj/sas-grammar(不知道它有多准确)

【讨论】:

  • 出于调试目的,我正在使用您的博客“medium.com/@bkiers/debugging-antlr-4-grammars-58df104de5f6”,我从中获取了代码来打印令牌和解析树。我能够打印 Lexer 令牌,但在打印解析树时遇到了一些问题: SASDTModelParser testParser = new SASDTModelParser(tokens); ParserRuleContext 上下文 = testParser。解析器。${4}();字符串树 = context.toStringTree(parser); printPrettyLispTree(树);在上面的代码中,我在“testParser.parser.${4}();”中遇到错误你能帮忙提供相应的Java代码吗?谢谢
  • 我解决了上述问题如下: SASDTModelParser testParser = new SASDTModelParser(tokens); ParserRuleContext 上下文 = testParser.parse();字符串树 = context.toStringTree(testParser); printPrettyLispTree(树);
  • @Ajay 我刚刚测试了我的 bash 脚本,运行和调试测试语法没有问题。我猜你没有使用我在 Medium 上概述的脚本,而是复制粘贴的部分。无论如何,很高兴听到你的工作进展顺利。
【解决方案2】:

您输入的语法不正确:应使用 == 而不是 =。

更新:

另外,虽然 INT 和 DOUBLE 的语法应该可以工作,但最好这样表达:

INT : [0-9]+;
DOUBLE : INT PT INT
    | PT INT
    | INT
    ;

否则,300 将被识别为 DOUBLE,而不是 INT。

更新 2

正如@Raven 评论的那样:

INT : [0-9]+;
DOUBLE : INT PT INT
    | PT INT
    ;

【讨论】:

  • 我已经在输入中用 == 替换了 =,但我仍然遇到同样的错误。 “第 1:3 行在输入‘IF 得分’时没有可行的替代方案”自从我删除了 IF 和得分之间的额外空格后,列号发生了变化。
  • 您可以从DOUBLE 规则中删除最后一个INT 部分,因为它永远不会匹配(此类内容将直接匹配为INT
【解决方案3】:

感谢@Bart、@Seelenvirtuose 和@Maurice,我已经完成了我的语法并解决了所有错误。

以下是用于解析 SAS If Else 和简单 Assignment 语句的 ANTLR 语法。

grammar SASDTModel;

parse : block+ EOF;

block
 : if_block+                # oneOrMoreIfBlock
 | assignment_block+        # assignmentBlocks
 ;

if_block
 : if_statement (else_if_statement)* else_statement?
 ;

/*nested_if_else_statement
 : If if_condition Then Do? ';'? if_statement (else_if_statement)* else_statement? End? ';'?
 ;*/

if_statement
 : If '('? if_condition ')'? Then if_block                                          # nestedIfStatement
 | If '('? if_condition ')'? Then expression Equal expression ';'                   # ifStatement
 | If expression In '(' expression_list+ ')' Then expression Equal expression ';'   # ifInBlock
 ;

else_if_statement
 : Else If '('? if_condition ')'? Then expression Equal expression ';'                  # elseIf
 | Else If expression In '(' expression_list+ ')' Then expression Equal expression ';'  # elseIfInBlock
 ;

if_condition
 : Identifier (Equal|ComparisionOperators) Quote? expression+ Quote?    # equalCondition
 | expression                                                           # expressionCondition
 | expression equals_to_null                                            # checkIfNull
 | expression op=(And|Or) expression                                    # andOrExpression
 ;

/*if_range_condition
 : expression ComparisionOperators expression ComparisionOperators expression
 ;*/

else_statement
 : Else expression Equal expression ';'
 ;

assignment_block
 : Identifier Equal Identifier '(' function_parameter ')' ';'   # functionCall
 | Identifier Equal expression expression* ';'                  # assignValue
 ;


expression
 : Value                                                                                                # value
 | Identifier                                                                                           # identifier
 | SignedFloat                                                                                          # signedFloat
 | '(' expression ')'                                                                                   # expressionBracket
 | expression '(' expression_list? ')'                                                                  # expressionBracketList
 | Not expression                                                                                       # notExpression
 | expression (Min|Max) expression                                                                      # minMaxExpression
 | expression op=('*'|'/') expression                                                                   # mulDivideExpression
 | expression op=('+'|'-') expression                                                                   # addSubtractExpression
 | expression ('||' | '!!' ) expression                                                                 # orOperatorExpression
 | expression ComparisionOperators expression ComparisionOperators expression                           # inRangeExpression
 | expression ComparisionOperators Quote? expression+ Quote?                                            # ifPlainCondition
 | expression (Equal|ComparisionOperators) Quote {_input.get(_input.index() -1).getType() == WS}? Quote # ifSpaceStringCondition
 | expression Equal expression                                                                          # equalExpression
 ;

expression_list
 : Quote? expression+ Quote? Comma?                                                # generalExpressionList
 | Quote ({_input.get(_input.index() -1).getType() == WS}?)? Quote Comma?          # spaceString
 ;

function_parameter
 : expression+
 ;

equals_to_null : Equal Pt ;

/*ArithmeticOperators
 : '+'
 | '-'
 | '*'
 | '/'
 | '**'
 ;*/

Equal : '=' ;

ComparisionOperators
 : '<'
 | '>'
 | '<='
 | '>='
 ;

And : '&' | 'and';

Or
 : '|'
 | '!'
 ;

Not
 : '^'
 | '~'
 ;

Min : '><';
Max : '<>';

If
 : 'IF'
 | 'if'
 | 'If'
 ;

Else
 : 'ELSE'
 | 'else'
 | 'Else';

Then
 : 'THEN'
 | 'then'
 | 'Then'
 ;

In : 'IN' | 'in';

Do : 'do' | 'Do';

End : 'end' | 'END';

Value
    : Int
    | DOUBLE
    | '-'DOUBLE
    | '-'Int
    | SignedFloat
    | 'null';

Int : [0-9]+;

SignedFloat
    : UnaryOperator? UnsignedFloat
    ;

MUL : '*' ; // assigns token name to '*' used above in grammar
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;

DOUBLE
    : Int Pt Int
    | Pt Int
    | Int
    ;

Pt  : '.';

UnaryOperator
 :    '+'
 |    '-'
 ;

UnsignedFloat
 :   ('0'..'9')+ '.' ('0'..'9')* Exponent?
 |   '.' ('0'..'9')+ Exponent?
 |   ('0'..'9')+ Exponent
 ;

Exponent : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

Comma : ',';

Quote
 : '\''
 | '"'
 ;

Identifier  : [a-zA-Z_] [a-zA-Z_0-9]*  ;
WS : ( ' ' | '\t' | '\r' | '\n' )-> channel(HIDDEN);

【讨论】:

    猜你喜欢
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    相关资源
    最近更新 更多