我有了这个解析器语法,我还想使用它与Javascript模板字符串类似的东西。
parser grammar Test;
options {
tokenVocab = TestLexer;
}
definition: sourceElements? EOF ;
sourceElements: sourceElement+ ;
sourceElement: mapping ;
templateString: '`' TemplateStringCharacter* ('${' variable '}' TemplateStringCharacter*)+ '`' ;
fieldName: varname | ('[' value ']') ;
mapping: fieldName ':' ( '{' sourceElements '}'
| variable ( '{' sourceElements '}' )? '?'?
| value
| array )
;
funParameter: '(' value? (',' value)* ')' ;
array: '[' value? (',' value)* ']';
variable: (varname | '{' value '}' | '[' boolEx ']' | templateString) funParameter? ('.' variable)* ;
value: INT | BOOL | FLOAT | STRING | variable ;
varname: VAR ;
还有这个 lexer语法
lexer grammar TestLexer;
WS : [ \t\r\n\u000C]+ -> skip ;
NEWLINE : [\r\n] ;
BOOL : ('true'|'false') ;
TemplateStringLiteral : TemplateStringCharacter*;
VAR : [$]?[a-zA-Z0-9_]+|[@] ;
INT : '-'?[0-9]+ ;
FLOAT : '-'?[0-9]+'.'[0-9]+ ;
STRING : '"' DoubleStringCharacter* '"' | '\'' SingleStringCharacter* '\'' ;
TEMPSTART : '${' ;
TEMPEND : '}' ;
TemplateStart : '`' -> pushMode(template) ;
/// Comments
MultiLineComment : '/*' .*? '*/' -> channel(HIDDEN) ;
SingleLineComment : '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN) ;
mode template;
TemplateVariableStart: TEMPSTART -> pushMode(templateVariable);
TemplateStringLiteral : TemplateStringCharacter* ;
TemplateEnd : '`' -> popMode;
mode templateVariable;
WS : [ \t\r\n\u000C]+ -> skip ;
All : [^}]+ ;
TemplateVariableEnd : TEMPEND -> popMode;
fragment DoubleStringCharacter : ~["\r\n] ;
fragment SingleStringCharacter : ~['\r\n] ;
fragment TemplateStringCharacter : ~[`] ;
fragment DecimalDigit : [0-9] ;
当我输入此内容时:
test: {
abc: `Hello World`
}
解析树如下所示:
(definition
(sourceElements
(sourceElement
(statement
(mapping
(fieldName
(varname test)
) : {
(sourceElements
(sourceElement
(statement mapping)
)
(sourceElement
(statement
(mapping abc : `)
)
)
(sourceElement
(statement mapping)
)
(sourceElement
(statement
(mapping Hello)
)
)
(sourceElement
(statement
(mapping World `)
)
)
)
}
)
)
)
)
<EOF>
)
我得到一个错误:行2:8在输入'abc:`Hello'处没有可行的选择
我不明白,为什么甚至可以匹配空的 mapping 或 mapping 之类的东西,例如“ World`”,因为 mapping < / strong>中间需要有一个“:”。为何规则 templateString 在整个刻度之间都不匹配整个“ Hello World”?
编辑:
当我以为是Lexer时没有注意到,我得到了如下错误:“无法在非组合语法:']'中为字符串文字创建隐式标记”。因此,我不得不将所有隐式声明移至词法分析器语法。所以我将代码更改为此:
parser grammar Test;
options {
tokenVocab = TestLexer;
}
definition: sourceElements? EOF ;
sourceElements: sourceElement+ ;
sourceElement: mapping ;
templateString: OpenBackTick TemplateStringLiteral* (TemplateVariableStart variable CloseBrace TemplateStringLiteral*)+ CloseBackTick ;
fieldName: varname | OpenBracket value CloseBracket ;
mapping: fieldName Colon (
OpenBrace sourceElements CloseBrace
| variable ( OpenBrace sourceElements CloseBrace )? IF?
| value
| array
)
;
funParameter: OpenParen value? (Comma value)* CloseParen ;
array: OpenBracket value? (Comma value)* CloseBracket;
variable: (varname | OpenBrace value CloseBrace | templateString) funParameter? (Dot variable)* ;
value: INT | BOOL | FLOAT | STRING | variable ;
varname: VAR ;
和 lexer语法:
lexer grammar TestLexer;
OpenBracket: '[';
CloseBracket: ']';
OpenParen: '(';
CloseParen: ')';
OpenBrace: '{' ;
CloseBrace: '}' ;
IF: '?' ;
AND: 'AND' ;
OR: 'OR';
LessThan: '<';
MoreThan: '>';
LessThanEquals: '<=';
GreaterThanEquals: '>=';
Equals: '=';
NotEquals: '!=';
IN: 'IN';
NOT: '!';
Colon: ':';
Dot: '.' ;
Comma: ',' ;
OpenBackTick : '`' -> pushMode(template) ;
WS : [ \t\r\n\u000C]+ -> skip ;
NEWLINE : [\r\n] ;
BOOL : ('true'|'false') ;
VAR : [$]?[a-zA-Z0-9_]+|[@] ;
INT : '-'?[0-9]+ ;
FLOAT : '-'?[0-9]+'.'[0-9]+ ;
STRING : '"' DoubleStringCharacter* '"' | '\'' SingleStringCharacter* '\'' ;
/// Comments
MultiLineComment : '/*' .*? '*/' -> channel(HIDDEN) ;
SingleLineComment : '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN) ;
mode template;
TemplateVariableStart: '${' -> pushMode(templateVariable);
CloseBackTick : '`' -> popMode;
TemplateStringLiteral: TemplateStringCharacter ;
mode templateVariable;
WHS : [ \t\r\n\u000C]+ -> skip ;
All : [^}]+ ;
TemplateVariableEnd : CloseBrace -> popMode;
fragment DoubleStringCharacter : ~["\r\n] ;
fragment SingleStringCharacter : ~['\r\n] ;
fragment TemplateStringCharacter : ~[`] ;
fragment DecimalDigit : [0-9] ;
现在我得到了错误: 第1:0行的输入“ test”不匹配,期望{,'?','[',VAR} 这很奇怪,因为“测试”应与 VAR 匹配。任何想法为什么会这样?
答案 0 :(得分:1)
在默认模式下,有两个词法分析器规则可以与反引号匹配:BTICK
和TemplateStart
。 TemplateStart
将切换到template
模式,但BTICK
不会。由于BTICK
在您的语法中排在第一位,因此它具有优先权。这意味着当词法分析器看到反引号时,它将生成一个BTICK
令牌,而不是切换模式。
要解决此问题,每个模式中只有一个与反引号匹配的词法分析器规则,并且该规则应该更改模式。
我不明白,为什么甚至可以匹配空映射或“ World`”之类的映射,因为映射的中间需要有一个“:”。
当您的输入包含语法错误时,生成的解析树可能包含实际上也不有效的构造。当您的输入正确解析时,您会得到一棵有意义的树。