【背景】
之前用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的异常处理,官网有些帖子:
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的效果的:
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 }
结果也是可以实现对应效果的:
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 }
结果是
即:
无法实现,对于整体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
可以从:
的:
The root of the ANTLR exception hierarchy. |
看出:
RecognitionException,是最顶层的异常。
所以,处理一般的异常,就可以直接去捕获对应的RecognitionException,然后写处理代码即可。
另外,如果不想要处理此最底层的异常,则可以去捕获那些特定的异常,比如:
等等。
8.虽然:
是针对于antlr v2的,但是其异常的设计架构,和之后的antlr,也是一样的,值得参考:
9.有空也可以再参考这个帖子:
【总结】
转载请注明:在路上 » 【记录】尝试折腾antlr v3的异常处理和错误恢复:VARIABLE的CLASS的值INPUT故意写错为INPUT1