我需要Java中的游戏描述语言(GDL)解析器
为此,我目前正在尝试使用ANTLR4。
我在下面给出的当前语法似乎不正确,或者至少生成的解析器无法识别我将在下面提供的游戏描述。
ANTLR4-Grammar:
grammar GDL;
description : (gdlRule | sentence)+ ;
gdlRule : '(' SP? '<=' SP? sentence (SP literal)* SP? ')';
sentence : propLit | ( '(' relLit ')' );
literal : ( '(' SP? (orLit | notLit | distinctLit | relLit) SP? ')' )
| ( '(' (orLit | notLit | distinctLit | relLit) ')' )
| propLit;
notLit : 'not' SP literal | '~' literal;
orLit : 'or' SP literal* ;
distinctLit : 'distinct' SP term SP term;
propLit : constant;
relLit : constant (SP term)+;
term : ( '(' funcTerm ')' ) | varTerm | constTerm;
funcTerm : constant (SP term)*;
varTerm : '?' constant;
constTerm : constant;
constant : ident | number;
/* ident is any string of letters, digits, and underscores */
ident: ID;
number: NR;
NR : [0-9]+;
ID : [a-zA-Z] [a-zA-Z0-9]* ;
SP : ' '+;
COMMENT : ';'[A-Za-z0-9; \r\t]*'\n' -> skip;
WS : [ ;\t\r\n]+ -> skip
;
GDL中给出的游戏说明:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Tictictoe
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(role white)
(role black)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(init (cell 1 1 b))
(init (cell 1 2 b))
(init (cell 1 3 b))
(init (cell 2 1 b))
(init (cell 2 2 b))
(init (cell 2 3 b))
(init (cell 3 1 b))
(init (cell 3 2 b))
(init (cell 3 3 b))
(init (step 1))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(<= (next (cell ?j ?k x))
(true (cell ?j ?k b))
(does white (mark ?j ?k))
(does black (mark ?m ?n))
(or (distinct ?j ?m) (distinct ?k ?n)))
(<= (next (cell ?m ?n o))
(true (cell ?m ?n b))
(does white (mark ?j ?k))
(does black (mark ?m ?n))
(or (distinct ?j ?m) (distinct ?k ?n)))
(<= (next (cell ?m ?n b))
(true (cell ?m ?n b))
(does white (mark ?m ?n))
(does black (mark ?m ?n)))
(<= (next (cell ?p ?q b))
(true (cell ?p ?q b))
(does white (mark ?j ?k))
(does black (mark ?m ?n))
(or (distinct ?j ?p) (distinct ?k ?q))
(or (distinct ?m ?p) (distinct ?n ?q)))
(<= (next (cell ?m ?n ?w))
(true (cell ?m ?n ?w))
(distinct ?w b))
(<= (next (step ?y))
(true (step ?x))
(succ ?x ?y))
(succ 1 2)
(succ 2 3)
(succ 3 4)
(succ 4 5)
(succ 5 6)
(succ 6 7)
(<= (row ?m ?x)
(true (cell ?m 1 ?x))
(true (cell ?m 2 ?x))
(true (cell ?m 3 ?x)))
(<= (column ?n ?x)
(true (cell 1 ?n ?x))
(true (cell 2 ?n ?x))
(true (cell 3 ?n ?x)))
(<= (diagonal ?x)
(true (cell 1 1 ?x))
(true (cell 2 2 ?x))
(true (cell 3 3 ?x)))
(<= (diagonal ?x)
(true (cell 1 3 ?x))
(true (cell 2 2 ?x))
(true (cell 3 1 ?x)))
(<= (line ?x) (row ?m ?x))
(<= (line ?x) (column ?m ?x))
(<= (line ?x) (diagonal ?x))
(<= nolinex
(not (line x)))
(<= nolineo
(not (line o)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(<= (legal white (mark ?x ?y))
(true (cell ?x ?y b)))
(<= (legal black (mark ?x ?y))
(true (cell ?x ?y b)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(<= (goal white 50)
(line x)
(line o))
(<= (goal white 100)
(line x)
nolineo)
(<= (goal white 0)
nolinex
(line o))
(<= (goal white 50)
nolinex
nolineo)
(<= (goal black 50)
(line x)
(line o))
(<= (goal black 100)
nolinex
(line o))
(<= (goal black 0)
(line x)
nolineo)
(<= (goal black 50)
nolinex
nolineo)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(<= terminal
(true (step 7)))
(<= terminal
(line x))
(<= terminal
(line o))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
生成的解析器的错误输出:
line 24:6 mismatched input '(' expecting {')', SP}
line 27:7 no viable alternative at input '(or'
我不知道我必须改变什么或如何获得正确的语法
任何帮助将不胜感激
答案 0 :(得分:1)
问题是你对空白的处理。
您有两个规则,其中一个创建令牌:
SP : ' '+;
和另一个忽略空格的那个:
WS : [ ;\t\r\n]+ -> skip
如果空格以空格字符开头,则第一条规则将适用,您将获得SP
标记。如果空格以WS
规则中列出的换行符或其他字符开头,则将忽略整个空白行。
由于您的语法在某些点上坚持使用SP
令牌,因此忽略的空格会导致语法错误。
我没有理由看到用明确的空格复杂你的语法。我会删除SP
,删除语法中对它的所有引用,然后让WS
忽略空格。
我还会从WS
中删除分号,以避免与COMMENT
进行互动。 [注1]我会简化COMMENT
,以便它只是忽略将分号链接到行的末尾,而不是给出有效注释字符列表。 (如果你想在评论中加上逗号或*,该怎么办?)
如果文件开头有换行符,在第2行有分号行,你会看到这个问题。然后COMMENT
在第一个字符处不匹配,但是{{1确实。然后,WS
将匹配(并忽略)换行符,分号行,下一个换行符,下一行开头的分号以及后续空格,将WS
保留为扫描Tictictoe
,这将导致解析错误。
如果任何其他评论不是一行分号,你也会看到它。目前正在将这些内容扫描为ID
,并在评论前使用换行符进行主演。这恰好是好的,因为评论只包括分号。但是任何其他非空格字符都将终止WS
,然后意外地解析为程序文本。
答案 1 :(得分:1)
(至少)3件事不正确:
;
规则中包含WS
及其COMMENT
COMMENT
规则说它需要以换行符结束。但是,换行符已包含在WS
规则中,并且会禁止以EOF
结尾的评论(没有换行符)SP
不需要:需要跳过空格并且不包含在解析器规则中尝试这样的事情:
grammar GDL;
description : (gdlRule | sentence)+ ;
gdlRule : '(' '<=' sentence literal* ')';
sentence : propLit | ( '(' relLit ')' );
literal
: ( '(' (orLit | notLit | distinctLit | relLit) ')' )
| ( '(' (orLit | notLit | distinctLit | relLit) ')' )
| propLit
;
notLit : 'not' literal | '~' literal;
orLit : 'or' literal* ;
distinctLit : 'distinct' term term;
propLit : constant;
relLit : constant (term)+;
term : ( '(' funcTerm ')' ) | varTerm | constTerm;
funcTerm : constant (term)*;
varTerm : '?' constant;
constTerm : constant;
constant : ident | number;
ident: ID;
number: NR;
NR : [0-9]+;
ID : [a-zA-Z] [a-zA-Z0-9]*;
COMMENT : ';'[A-Za-z0-9; \r\t]* -> skip;
WS : [ \t\r\n]+ -> skip;