【发布时间】:2020-05-14 07:27:19
【问题描述】:
我对 Xtext 还很陌生,所以我可能问错了问题,或者使用了不正确的术语。请在您的回复中牢记这一点。
我正在尝试在 Xtext 中从头开始实现 JBehave EBNF Spec 作为学习练习。 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');
我遇到的问题在 cmets 中有概述。
- 当我取消注释终端
NON_KEYWORD时,测试失败并显示预期:“敏捷的棕色狐狸\n跳过懒狗\n” 但是:是“那个”
- 如果我随后替换
Description中注释掉的行,则测试根本无法解析为预期:不为空 但是:为空
我有点模糊地理解这里发生的事情。我在 WORD 之前定义的标记也是有效的单词,因此它会抛出解析器。因此我的问题如下。
我在哪里可以找到 Xtext 文档(或其他来源),这些文档描述了此处受影响的基础原则。到目前为止,我已经多次阅读 Xtext 文档,但我能找到的只是关于终端语句的顺序依赖性的简要说明。
调试解析器如何解释我的语法的好方法是什么?有没有类似于将
IFormattableDocument转储到控制台的东西,但对于词法分析器/解析器/其他什么?最后,从 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 ) ;
我实际上无法独自完成这项工作。但是,当我取消注释原始代码并将它们一起尝试时,它可以工作!
@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 的问题,但意外到达那里有点违背了目的。我现在将接受任何可以指出或向我描述导致我所描述的行为的基本原则的答案。
为什么我不能随机匹配一组单词?在Story 中定义narrative 赋值以及description 赋值如何改变解析器解释语法的方式?
【问题讨论】:
-
我发现了这个问题 blogs.itemis.com/en/… 和 blogs.itemis.com/en/debugging-dsls-in-xtext-and-eclipse 问题 #2。