最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【记录】尝试折腾antlr v3的异常处理和错误恢复:VARIABLE的CLASS的值INPUT故意写错为INPUT1

ANTLR crifan 2204浏览 0评论

【背景】

之前用antlr解析eddl,基本的简单的语法,已经支持。

现在需要做的是,去想办法,支持对应的异常处理,可以捕获异常,然后做一些动作。

比如一直忽略掉当前的整段,或者忽略当前的节点。

继续下一个节点去解析。

自己,先弄个了个示例的eddl的variable作为例子:

VARIABLE    actuator_function_code
{ 
    LABEL   "Actuator function";
    CLASS   INPUT1; 
    HANDLING   READ&WRITE;
    TYPE ENUMERATED
    { 
        {   0, "Double acting"  }, 
        {   1, "Single acting"  } 
    }
}

VARIABLE set_units 
{
    LABEL "Setpoint"; 
    CLASS INPUT;
    HELP [digital_units_help];

    TYPE ENUMERATED 
    {
        { 57,   [Percent],  [percent_help] },
        { 143,  [degrees],  [degrees_help] }, 
        { 39,   [mA],       [milliamperes_help] }, 
        { 49,   [mm],       [millimeters_help] }, 
        { 47,   [in],       [inches_help] }, 
        { 48,   [cm],       [centimeters_help] }
    }
}

VARIABLE set_value
{	        
	CLASS DYNAMIC & INPUT;
	LABEL "Setpoint";
	HELP "Setpoint value for the valve positioner. The dynamic value is generated by a control system or manually from an operator";
	HANDLING   READ&WRITE;
	TYPE  FLOAT 
	{
		DISPLAY_FORMAT ".1f";
	}
}

其中actuator_function_code中的INPUT1,是故意写错的,应该是INPUT。

此处,看看能否捕获此异常,并做后续的动作。

 

【折腾过程】

1.关于antlr的异常处理,官网有些帖子:

Error reporting and recovery

2.后来在:

The Definitive ANTLR Reference.pdf

中看到相关的代码:

stat: expr ';'
{System.out.println("found expr: "+$stat.text);}
| ID '=' expr ';'
{System.out.println("found assign: "+$stat.text);}
;
catch [RecognitionException re] {
reportError(re);
consumeUntil(input, SEMI); // throw away all until ';'
input.consume(); // eat the ';'
}

然后参考去试试。

3.把其中的代码,加到我当前的语法中:

common_class	:	'ALARM'| 'ANALOG_INPUT'| 'ANALOG_OUTPUT'| 'COMPUTATION'| 'CONTAINED'| 'CORRECTION'| 'DEVICE'| 'DIAGNOSTIC'| 'DIGITAL_INPUT'| 'DIGITAL_OUTPUT'| 'DISCRETE_INPUT'| 'DISCRETE_OUTPUT'| 'DYNAMIC'| 'FREQUENCY_INPUT'| 'FREQUENCY_OUTPUT'| 'HART'| 'INPUT'| 'LOCAL'| 'LOCAL_DISPLAY'| 'OPERATE'| 'OUTPUT'| 'SERVICE'| 'TUNE';
catch [RecognitionException re] {
reportError(re);
consumeUntil(input, SEMICOLON); // throw away all until ';'
input.consume(); // eat the ';'
}

是可以实现,consume的效果的:

consume until the semi colon then handling

4.然后,想要实现,当出错时,一直consume,直到下一个别的VARIABLE:

VARIABLE    :    'VARIABLE';

common_class	:	'ALARM'| 'ANALOG_INPUT'| 'ANALOG_OUTPUT'| 'COMPUTATION'| 'CONTAINED'| 'CORRECTION'| 'DEVICE'| 'DIAGNOSTIC'| 'DIGITAL_INPUT'| 'DIGITAL_OUTPUT'| 'DISCRETE_INPUT'| 'DISCRETE_OUTPUT'| 'DYNAMIC'| 'FREQUENCY_INPUT'| 'FREQUENCY_OUTPUT'| 'HART'| 'INPUT'| 'LOCAL'| 'LOCAL_DISPLAY'| 'OPERATE'| 'OUTPUT'| 'SERVICE'| 'TUNE';
catch [RecognitionException re] {
reportError(re);
//consumeUntil(input, SEMICOLON); // throw away all until ';'
//input.consume(); // eat the ';'
consumeUntil(input, VARIABLE); // throw away all until next VARIABLE
}

结果也是可以实现对应效果的:

consume until the next variable key is also ok

5.再去把代码,加到整个的variable的后面试试:

common_class	:	'ALARM'| 'ANALOG_INPUT'| 'ANALOG_OUTPUT'| 'COMPUTATION'| 'CONTAINED'| 'CORRECTION'| 'DEVICE'| 'DIAGNOSTIC'| 'DIGITAL_INPUT'| 'DIGITAL_OUTPUT'| 'DISCRETE_INPUT'| 'DISCRETE_OUTPUT'| 'DYNAMIC'| 'FREQUENCY_INPUT'| 'FREQUENCY_OUTPUT'| 'HART'| 'INPUT'| 'LOCAL'| 'LOCAL_DISPLAY'| 'OPERATE'| 'OUTPUT'| 'SERVICE'| 'TUNE';
/*catch [RecognitionException re] {
reportError(re);
//consumeUntil(input, SEMICOLON); // throw away all until ';'
//input.consume(); // eat the ';'
consumeUntil(input, VARIABLE); // throw away all until next VARIABLE
}*/

common_validity	:	'TRUE' | 'FALSE'; //TODO: add boolean expression

/*******************************************************************************
7.27 VARIABLE
Table 138 – VARIABLE attributes
*******************************************************************************/
variable	:	VARIABLE variable_identifier '{' variable_body '}';
catch [RecognitionException re] {
reportError(re);
//consumeUntil(input, SEMICOLON); // throw away all until ';'
//input.consume(); // eat the ';'

consumeUntil(input, VARIABLE); // throw away all until next VARIABLE
}

结果是

put exception capture after variable then can not consume until

即:

无法实现,对于整体VARIABLE中的CLASS的值INPUT1出错后,无法继续consume到下一个VARIABLE。

具体原因,暂时不太懂。

还是需要抽空把如上代码,整合到后续的解析AST的代码中,到解析代码中去调试,才或许能看懂内部逻辑到底如何。

6.从pdf教程中,可以看出,对应语法是:

r   : ...
    ;
    catch[RecognitionException e] { throw e; }

或:

r   : ...
    ;
    catch[FailedPredicateException fpe] { ... }
    catch[RecognitionException e] { ...; }

或:

r   : ...
    ;
    // catch blocks go first
    finally { System.out.println("exit rule r"); }

7.而关于:RecognitionException

可以从:

Package org.antlr.runtime

的:

RecognitionException

The root of the ANTLR exception hierarchy.

看出:

RecognitionException,是最顶层的异常。

所以,处理一般的异常,就可以直接去捕获对应的RecognitionException,然后写处理代码即可。

另外,如果不想要处理此最底层的异常,则可以去捕获那些特定的异常,比如:

MismatchedTokenException

EarlyExitException

等等。

8.虽然:

Error Handling and Recovery

是针对于antlr v2的,但是其异常的设计架构,和之后的antlr,也是一样的,值得参考:

ANTLRException arch antlr v2

9.有空也可以再参考这个帖子:

ANTLR Tutorial – Hello Word

 

 

【总结】

转载请注明:在路上 » 【记录】尝试折腾antlr v3的异常处理和错误恢复:VARIABLE的CLASS的值INPUT故意写错为INPUT1

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.163 seconds, using 22.14MB memory