【发布时间】:2014-04-13 20:40:42
【问题描述】:
我正在构建一种小型规则语言来测试并习惯 ANTLR。我正在使用 ANTLR V4,我的语法拆分如下:
Lexer.g4
lexer grammar Lexer;
/*------------------------------------------------------------------
* LEXER RULES - GENERIC KEYWORDS
*------------------------------------------------------------------*/
NOT
: 'not'
;
NULL
: 'null'
;
AND
: 'and'
| '&'
;
/*------------------------------------------------------------------
* LEXER RULES - PATTERN MATCHING
*------------------------------------------------------------------*/
DELIM
: [\|\\/:,&@+><^]
;
WS
: [ \t\r\n]+ -> skip
;
VALUE
: SQUOTE TEXT SQUOTE
;
fragment SQUOTE
: '\''
;
fragment TEXT
: ( 'a'..'z'
| 'A'..'Z'
| '0'..'9'
| '-'
)+ ;
Attribute.g4
grammar Attribute;
/*------------------------------------------------------------------
* Semantic Predicate
*
* Attributes are capitalised words that may have spaces. They're
* loaded from the database and and set in the glue code so that
* they can be cross checked here. If the grammar passed in sees
* an attribute it will pass so long as the attribute is in the
* database, otherwise the grammar will fail to parse.
*------------------------------------------------------------------*/
attr
: a=ATTR {attributes.contains($a.text)}?
;
ATTR
: ([A-Z][a-zA-Z0-9/]+([ ][A-Z][a-zA-Z0-9/]+)?)
;
ReplaceInWith.g4
grammar ReplaceInWith;
/*------------------------------------------------------------------
* REPLACE IN WITH PARSER RULES
*------------------------------------------------------------------*/
replace_in_with
: rep in with {row.put($in.value , $in.value.replace($rep.value, $with.value));}
| repAtt with {row.put($repAtt.value, $with.value);}
;
rep returns[String value]
: REPLACE v=VALUE {$value = trimQuotes($v.text);}
;
repAtt returns[String value]
: REPLACE a=attr {$value = $a.text;}
;
in returns[String value]
: IN a=attr {$value = $a.text;}
;
with returns[String value]
: WITH v=VALUE {$value = trimQuotes($v.text);}
;
/*------------------------------------------------------------------
* LEXER RULES - KEYWORDS
*------------------------------------------------------------------*/
REPLACE
: 'rep'
| 'replace'
;
IN
: 'in'
;
WITH
: 'with'
;
Parser.g4
grammar Parser;
/*------------------------------------------------------------------
* IMPORTED RULES
*------------------------------------------------------------------*/
import //Essential imports
Attribute,
GlueCode,
Lexer,
//Actual Rules
ReplaceInWith,
/*------------------------------------------------------------------
* PARSER RULES
* MUST ADD EACH TOP LEVEL RULE HERE FOR IT TO BE CALLABLE
*------------------------------------------------------------------*/
eval
: replace_in_with
;
GlueCode.g4
Java to supply static calling functionality to the grammar and to set the attributes up from the database.
ParserErrorListener.java
public class ParserErrorListener extends ParserBaseListener
{
/**
* After every rule check to see if an exception was thrown, if so exit with a runtime exception to indicate a
* parser problem.<p>
*/
@Override
public void exitEveryRule(@NotNull ParserRuleContext ctx)
{
super.exitEveryRule(ctx);
if (ctx.exception != null)
{
throw new ParserRuntimeException(String.format("Error evaluating expression(s) '%s'", ctx.exception));
} //if
} //exitEveryRule
} //class
当我向语法提供以下内容时,它会按预期通过:
"replace 'Acme' in Name with 'acme'",
"rep 'Acme' in Name with 'acme'",
"replace 'Acme' in Name with 'ACME'",
"rep 'Acme' in Name with 'ACME'",
"replace 'e' in Name with 'i'",
"rep 'e' in Name with 'i'",
"replace '-' in Number with ' '",
"rep '-' in Number with ' '",
"replace '555' in Number with '00555'",
"rep '555' in Number with '00555'"
其中 NAME 和 NUMBER 被设置为语义谓词的属性。
但是,当我传入以下语句时,语法仍然通过,但我不确定它为什么匹配:
"replace any 'Acme' in Name with 'acme'",
"replaceany 'Acme' in Name with 'acme'",
再次将 NAME 作为属性传递给语义谓词匹配,这部分语法在我的测试中有效。失败的部分是“任何”部分。语法匹配替换,然后获取它认为是“Acme”的下一个标记,忽略上面两个示例中的“任何”部分。我在这里期望的是语法失败,并且在退出规则的侦听器中添加了一个检查,该检查应该抛出一个运行时异常,该异常被 GlueCode 捕获以指示失败。
有什么想法可以让我的语法在发生这种情况时抛出错误?
【问题讨论】: