我对Xtext相当陌生,所以我可能问错了问题,或者使用了错误的术语。请您在回复中牢记这一点。
我正试图实现 JBehave EBNF规格 在Xtext中从头开始学习。JBehave是一个非常 "啰嗦 "的语法,类似于我需要能够维护的语法,所以我需要了解如何在不同的上下文中处理各种类型的 "单词"。
我以这个测试用例为出发点,得以通过。
@Test
def void loadModel() {
// Multi-line
var story = parseHelper.parse('''
The quick brown fox
Jumps over the lazy dog
''')
assertThat(story, notNullValue())
assertThat(
story.description,
equalTo('''
The quick brown fox
Jumps over the lazy dog
''')
)
// Single-line description
story = parseHelper.parse('''
The quick brown fox
''')
assertThat(
story.description,
equalTo("The quick brown fox\n")
)
}
使用这个语法定义...
grammar org.example.jbehave.JBehave hidden (WS)
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate jbehave "http://www.example.org/jbehave"
// The story describes a feature via description, narrative and a set of scenarios
// Story := Description? Meta? Narrative? GivenStories? Lifecycle? Scenario+ ;
Story:
description=Description?
;
// The Description is expressed by any sequence of words that must not contain any keywords at start of lines.
// Description := (Word Space?)* ;
Description:
((WORD) (WORD)* EOL+)+
// ((NON_KEYWORD) (WORD)* EOL+)+
;
// Key Words
////
// TODO: parser fails when uncommented
//terminal NON_KEYWORD:
// !(IN_ORDER_TO
// | AS_A
// | I_WANT_TO
// | SO_THAT
// | SCENARIO
// | GIVEN_STORIES
// | GIVEN
// | THEN
// | WHEN
// | AND
// )
//;
terminal fragment IN_ORDER_TO: "In order to";
terminal fragment AS_A: "As a";
terminal fragment I_WANT_TO: "I want to";
terminal fragment SO_THAT: "So that";
terminal fragment SCENARIO: "Scenario:";
terminal fragment GIVEN_STORIES: "GivenStories:";
terminal fragment GIVEN: "Given";
terminal fragment WHEN: "When";
terminal fragment THEN: "Then";
terminal fragment AND: "And";
// Common Terminals
////
terminal WORD: ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*;
terminal WS: (' '|'\t')+;
terminal EOL: NL;
terminal fragment NL: ('\r'? '\n');
我遇到的问题在注释中有所概述。
NON_KEYWORD
,测试失败的原因是预期: "快速的棕色狐狸跳过了懒狗",但是...
Description
的情况下,测试根本无法解析。预期:不为空,但:为空
我有点明白这里发生了什么,在模糊的意义上。我在WORD前定义的Token也是有效的词,所以就把解析器扔掉了。因此我的问题如下。
我在Xtext文档(或其他来源)中哪里可以找到描述这里所影响的基本原理。我现在已经读了很多遍Xtext文档,但我能找到的只是关于终端语句的顺序依赖性的简短说明。
有什么好办法可以调试解析器是如何解释我的语法的?有没有类似于转储 IFormattableDocument
到控制台,但对于lexerparserwhatever?
最后,从Xtext的角度来看,解决这个问题的最好方法是什么。我应该研究自定义数据类型,还是用纯Xtext来表达?
我正在寻求了解底层原理。
嗯,这当然很奇怪。我尝试着暂时抛开这个问题,实现规范的下一部分。
; The narrative is identified by keyword "Narrative:" (or equivalent in I18n-ed locale),
; It is followed by the narrative elements
Narrative:= "Narrative:" ( InOrderTo AsA IWantTo | AsA IWantTo SoThat ) ;
实际上,我无法让这个单独工作。然而,当我把原来的代码删掉,然后把它们放在一起尝试时,它就能工作了!这就解决了#3的问题,我想,但到达后,我就会发现,它的工作原理是什么呢?
@Test
def void narrativeOnly() {
var story = _th.parse('''
Narrative:
In order check reports
As a Developer
I want to workin with todos using examples
''')
assertThat(story, notNullValue())
}
@Test
def void descriptionOnly() {
// Multi-line
var story = _th.parse('''
The quick brown fox
Jumps over the lazy dog
''')
assertThat(story, notNullValue())
assertThat(
story.description,
equalTo('''
The quick brown fox
Jumps over the lazy dog
''')
)
// Single-line description
story = _th.parse('''
The quick brown fox
''')
assertThat(
story.description,
equalTo("The quick brown fox\n")
)
}
grammar org.agileware.natural.jbehave.JBehave hidden (WS)
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate jbehave "http://www.agileware.org/natural/jbehave"
// Story
////
// The story describes a feature via description, narrative and a set of scenarios
// Story := Description? Meta? Narrative? GivenStories? Lifecycle? Scenario+ ;
Story:
description=Description?
narrative=Narrative?
;
// Narrative
////
// The narrative is identified by keyword "Narrative:" (or equivalent in I18n-ed locale),
// It is followed by the narrative elements
// Narrative:= "Narrative:" ( InOrderTo AsA IWantTo | AsA IWantTo SoThat ) ;
// The narrative element content is any sequence of characters that do not match a narrative starting word
// NarrativeElementContent := ? Any sequence of NarrativeCharacter that does not match NarrativeStartingWord ? ;
Narrative:
'Narrative:'
inOrderTo=InOrderTo
asA=AsA
wantTo=IWantTo
;
// InOrderTo:= "In order to" NarrativeElementContent ;
InOrderTo:
IN_ORDER_TO (WORD) (WORD)* EOL+;
// AsA:= "As a" NarrativeElementContent ;
AsA:
AS_A (WORD) (WORD)* EOL+;
// IWantTo:= "I want to" NarrativeElementContent ;
IWantTo:
I_WANT_TO (WORD) (WORD)* EOL+;
// SoThat:= "So that" NarrativeElementContent ;
SoThat:
SO_THAT (WORD) (WORD)* EOL+;
// The Description is expressed by any sequence of words that must not contain any keywords at start of lines.
// Description := (Word Space?)* ;
Description:
((WORD) (WORD)* EOL+)+
;
// Key Words
////
//terminal NON_KEYWORD:
// !(IN_ORDER_TO
// | AS_A
// | I_WANT_TO
// | SO_THAT
// | SCENARIO
// | GIVEN_STORIES
// | GIVEN
// | THEN
// | WHEN
// | AND
// )
//;
terminal IN_ORDER_TO: "In order to";
terminal AS_A: "As a";
terminal I_WANT_TO: "I want to";
terminal SO_THAT: "So that";
//terminal SCENARIO: "Scenario:";
//terminal GIVEN_STORIES: "GivenStories:";
//terminal GIVEN: "Given";
//terminal WHEN: "When";
//terminal THEN: "Then";
//terminal AND: "And";
// Common Terminals
////
terminal WORD: (LETTER)(LETTER|DIGIT)*;
terminal fragment LETTER: ('a'..'z'|'A'..'Z');
terminal fragment DIGIT: ('0'..'9');
terminal WS: (' '|'\t')+;
terminal EOL: NL;
terminal fragment NL: ('\r'? '\n');
我想,这就解决了#3的问题,但不小心到了那里,就有点失去目的了。我现在接受任何能给我指出或描述导致我所描述的行为的基本原理的答案。
为什么我不能随便匹配一组词?如何定义 narrative
随同 description
派驻 Story
改变解析器对语法的解释方式?
我已经能够回答我的所有3个问题,使用的是 ANTLRWorks这是一个可执行的jar形式的gui工具,其明确的目的是调试,可视化,并帮助人们理解解析器的行为。
要让这个工具与Xtext一起工作,需要添加以下的mwe2生成器。
language = StandardLanguage {
// ...
parserGenerator = {
debugGrammar = true
}
}
然后在ANTLRWorks工具中打开生成的调试文件 并点击 "Bug"(调试)图标. 这个文件应该位于 src-gen/*/parser/antlr/internal/DebugInternal*.g
资料来源:/blogs.itemis.comendebugging-xtext-grammars-what to do-when-your-language isambiguous: https:/blogs.itemis.comendebugging-xtext-grammars-what-to-do-when-your-language-is-ambiguous。